精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

如何讓 Ansible 和 Docker 愉快地在一起

云計算
Docker 和它的容器工作流可封裝、共享和部署您的應用程序環境。Ansible 是一個與 Docker 高度兼容的自動化工具,它使用一個強大的接口來管理遠程服務器上的容器。在本文中,我將探索為何和如何使用 Ansible 的可擴展設計來將 Docker 和 Ansible 的最佳功能合并在一起。

Docker 之所以如此流行,是因為它創造了一種采用方便的命令行接口 (CLI) 和 HTTP API 工具來封裝、運行和維護容器的獨特方式。這種簡化降低了此技術的入門門檻,使得將應用程序及其運行時環境封裝到一個簡單 Dockerfile 中的獨立鏡像中變得可行。Docker 使您能夠開發更復雜的項目,但您仍需要配置這些容器。在本文中,我將展示 Ansible 如何通過更清晰的語法帶來配置管理器的特性。您將學習如何僅使用已安裝的 Python 和 Docker 構建任何堆棧。

在介紹 Ansible 的細節之前,我首先將介紹 Ansible 的 分析 中提到的一些要點:

  • 盡管容器導致一些新工作流出現,但編排和配置工具仍然非常活躍。
  • Ansible 和 Salt 等新參與者正在挑戰現有的工具,比如 Chef 和 Puppet。
  • 許多與 Docker 有關聯的開發人員也很關心這些工具。

更確切地講,借助 Docker,您可以在幾秒內實現完全隔離的堆棧環境,或者在服務器之間復制準確的設置。但是,Docker 不包含提供端到端體驗的可靠工具,無論是針對開發還是生產。Docker 團隊通過新的集群工具解決了這些不斷演變的挑戰,嘗試將 Docker 轉變為一個大規模運行容器的可靠解決方案。然而,Docker 仍然需要您手動硬編碼任務和重復常見的設置。所以,針對容器的編排和配置管理的關鍵 Docker 流程仍有待解決。在本文中,您將學習如何結合使用 Ansible 和 Docker 來幫助解決這些問題。

DevOps 的興起

在部署到生產中之前,現代應用程序通常涉及到一個復雜的部署管道。最佳實踐建議在每次小型迭代后盡早地、頻繁地發布代碼。任務的手動執行無法擴展,組織已開始完善介于開發人員與系統管理員之間的流程,所以 DevOps 就誕生了。從那時起,敏捷團隊就開始嘗試強化和自動化測試代碼,以及將其交付給用戶的方式。

通過實現最新的技術和方法,公司對其服務器上的代碼建立了信心。然而,隨著應用程序在規模和復雜性上不斷增長,開發人員和系統管理員繼續面臨著無數挑戰。現在比以往更需要為產品提供受支持的社區驅動工具。

Ansible 的可擴展設計

在此環境中,Ansible 提供了一個有趣的框架來管理基礎架構。您可以獲得服務器定義的控制權,比如要安裝的包或要復制的文件,并將該配置擴展到數千個服務器。Ansible playbook 構成了集群的目標狀態的一種安全表示。它的 YAML 語法和龐大的模塊列表生成了任何開發人員都能快速理解的易讀性配置文件。不同于 Chef 或 Puppet,Ansible 是無代理的,這意味著您要在遠程主機上運行命令,只需一個 SSH 連接即可。可以看到,Ansible 可輕松地處理 DevOps 復雜性。

但是,Ansible 是在容器快速興起和它們在云開發環境中帶來革命之前設計的。那么 Ansible 是否仍然有用?微型服務的范式和復雜開發環境引入了新的需求:

  • 輕量型鏡像。為了容易傳輸或節省成本,鏡像被剝離到僅剩下最低限度的依賴項。
  • 單一用,單一流程。如果應用程序不是非常需要 SSH 守護進程,則無需運行它。
  • 短暫性。容器隨時可能死亡、轉移和復活。

在此上下文中,Ansible 的可擴展架構解決了這些問題。一個 Docker 模塊在較高層面上管理主機和容器。盡管您可能會爭論哪個編排工具(來自 Google 的 Kubernetes,還是來自 New Relic 的 Centurion)最適合此環境,但 Docker 模塊執行效率很高,這正是我在本文中使用它的原因。但是,您還可以構建從其官方 Ansible 鏡像啟動的容器,然后在本地模式下從內部運行 playbook。盡管此方法非常適合 Packer,而且肯定也適合許多使用情況,但它的缺點通常極為關鍵。

您被鎖定在一個基礎鏡像中,無法再利用特殊的秘訣或其他堆棧。

最終的工件已安裝 Ansible 和它的依賴項,它們與實際應用程序毫無關系,這讓工件變得更笨重。

盡管 Ansible 可管理數千個服務器,但它只配備(Provision)了一個容器。

此方法將容器視為小型 VM,您可以在其中使用一個特定的解決方案。幸運的是,Ansible 擁有模塊化設計。模塊分散在不同的存儲庫中,而且 Ansible 的大部分功能都可以通過插件進行擴展。

在下一節中,您將設置一個有效的環境,針對您的需求來調整 Ansible。

設置一個 Ansible 環境

假設您想要一個很容易部署的工具,它在輕量型容器中配置應用程序環境。由于與這些容器分離,您需要一個安裝了 Ansible 的客戶端,您將使用它來向 Docker 守護進程發送命令。此設置如 圖 1 中所示。

使用 Ansible 高效交付 Docker 容器

圖 1. 使用 Ansible 配備容器所需的組件

您在此配置中必須管理的依賴項,已通過從容器中運行 Ansible 來最小化。此架構將主機限制為容器與命令之間的一個通信橋梁。

可通過許多選項在您服務器上安裝 Docker:

使用 docker-machine 將它安裝在遠程主機上。

安裝在本地。順便說一下,您可能不想親自管理一個嚴格基于容器的基礎架構;在這種情況下,可以考慮采用外部提供程序。

依賴于外部提供程序。

使用 boot2docker,這是一個在 Windows 和 Mac 上運行 Docker 容器的輕量型 Linux 發行版。

無論選擇何種解決方案,請確保部署了 Docker 1.3 版或更高版本(1.3 版引入了進程注入)。您還需要運行一個 SSH 服務器來安全地處理 Ansible 命令。

清單 1 中的命令使用公鑰設置了一種方便可靠的身份驗證方法。

清單 1. 使用公鑰設置身份驗證的命令

  1. # install dependencies 
  2. sudo apt-get install -y openssh-server libssl-dev 
  3. # generate private and public keys 
  4. ssh-keygen -t rsa -f ansible_id_rsa 
  5. # allow future client with this public key to connect to this server 
  6. cat ansible_id_rsa.pub >> ~/.ssh/authorized_keys 
  7. # setup proper permissions 
  8. chmod 0700  ~/.ssh/ 
  9. chmod 0600  ~/.ssh/authorized_keys 
  10. # make sure the daemon is running 
  11. sudo service ssh restart 

配置 SSH 和安全性問題不屬于本文的討論范圍。細心的讀者可查閱 /etc/ssh/sshd_config 文件,進一步了解配置 SSH 的可用選項。

下一步是將公鑰加載到運行 Ansible 的客戶端容器上并配備構建器容器。使用一個 Dockerfile 來配備構建器。參見 清單 2。

清單 2. 配備構建器的 Dockerfile

  1. FROM python:2.7 
  2.  
  3. # Install Ansible from source (master) 
  4. RUN apt-get -y update && \ 
  5.     apt-get install -y python-httplib2 python-keyczar python-setuptools python-pkg-resources 
  6. git python-pip && \ 
  7.     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 
  8. RUN pip install paramiko jinja2 PyYAML setuptools pycrypto>=2.6 six \ 
  9.     requests docker-py  # docker inventory plugin 
  10. RUN git clone http://github.com/ansible/ansible.git /opt/ansible && \ 
  11.     cd /opt/ansible && \ 
  12.     git reset --hard fbec8bfb90df1d2e8a0a4df7ac1d9879ca8f4dde && \ 
  13.     git submodule update --init 
  14.  
  15. ENV PATH /opt/ansible/bin:$PATH 
  16. ENV PYTHONPATH $PYTHONPATH:/opt/ansible/lib 
  17. ENV ANSIBLE_LIBRARY /opt/ansible/library 
  18.  
  19. # setup ssh 
  20. RUN mkdir /root/.ssh 
  21. ADD ansible_id_rsa /root/.ssh/id_rsa 
  22. ADD ansible_id_rsa.pub /root/.ssh/id_rsa.pub 
  23.  
  24. # extend Ansible 
  25. # use an inventory directory for multiple inventories support 
  26. RUN mkdir -p /etc/ansible/inventory && \ 
  27.     cp /opt/ansible/plugins/inventory/docker.py /etc/ansible/inventory/ 
  28. ADD ansible.cfg  /etc/ansible/ansible.cfg 
  29. ADD hosts  /etc/ansible/inventory/hosts 

這些指令改編自官方構建版本,自動化了一次來自 Ansible 主分支上的提交 fbec8bfb90df1d2e8a0a4df7ac1d9879ca8f4dde 有效安裝。

主機和 ansible.cfg 配置文件(參見 清單 3 和 清單 4)已封裝。通過使用容器,可以確保您將共享同一個環境。在本示例中,Dockerfile 安裝了 Python 2.7.10 版和 Ansible 2.0.0。

清單 3. 主機配置文件

  1. # hosts 
  2. # this file is an inventory that Ansible is using to address remote servers.  
  3. Make sure to replace the information with your specific setup and variables  
  4. that you don't want to provide for every command. 
  5.  
  6. [docker] 
  7. # host properties where docker daemon is running 
  8. 192.168.0.12 ansible_ssh_user=xavier 

清單 4. Ansible 配置文件

  1. # ansible.cfg 
  2.  
  3. [defaults] 
  4.  
  5. # use the path created from the Dockerfile 
  6. inventory = /etc/ansible/inventory 
  7.  
  8. # not really secure but convenient in non-interactive environment 
  9. host_key_checking = False 
  10. # free you from typing `--private-key` parameter 
  11. priva_key_file = ~/.sh/id_rsa 
  12.  
  13. # tell Ansible where are the plugins to load 
  14. callback_plugins   = /opt/ansible-plugins/callbacks 
  15. connection_plugins = /opt/ansible-plugins/connections 

#p#

在構建 Ansible 容器之前,您必須導出 DOCKER_HOST 環境變量,因為 Ansible 將使用它連接到遠程 Docker 守護進程。在使用 HTTP 端點時,需要修改 /etc/default/docker(參見 清單 5)。

清單 5. 修改 /etc/default/docker

  1. # make docker to listen on HTTP and default socket 
  2. DOCKER_OPTS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock" 

輸入命令 sudo service docker restart 來重新啟動 Docker 守護進程,以便讓對它的配置文件的更改生效。

以下命令將會構建并驗證您用來輸入命令的 Ansible 容器(參見 清單 6)。

清單 6. 構建和驗證 Ansible 容器的命令

  1. # you need DOCKER_HOST variable to point to a reachable docker daemon 
  2. # pick the method that suits your installation 
  3.  
  4. # for boot2docker users 
  5. eval "$(boot2docker shellinit)" 
  6. # for docker-machine users, provisioning the running VM was named "dev" 
  7. eval "$(docker-machine env dev)" 
  8. # for users running daemon locally 
  9. export DOCKER_HOST=tcp://$(hostname -I | cut -d" " -f1):2375 
  10. # finally users relying on a remote daemon should provide the server's public ip 
  11. export DOCKER_HOST=tcp://1.2.3.4:2375 
  12.  
  13. # build the container from Dockerfile 
  14. docker build -t article/ansible . 
  15.  
  16. # provide server API version, as returned by `docker version | grep -i "server api"` 
  17. # it should be at least greater or equal than 1.8 
  18. export DOCKER_API_VERSION=1.19 
  19.  
  20. # create and enter the workspace 
  21. docker run -it --name builder \ 
  22.     # make docker client available inside 
  23.     -v /usr/bin/docker:/usr/bin/docker \ 
  24.     -v /var/run/docker.sock:/var/run/docker.sock \ 
  25.     # detect local ip 
  26.     -e DOCKER_HOST=$DOCKER_HOST \ 
  27.     -e DEFAULT_DOCKER_API_VERSION=DOCKER_API_VERSION \ 
  28.     -v $PWD:/app -w /app \  # mount the working space 
  29.     article/ansible bash 
  30.  
  31. # challenge the setup 
  32. $ container > ansible docker -m ping 
  33. 192.168.0.12 | SUCCESS => { 
  34.     "invocation": { 
  35.         "module_name""ping"
  36.         "module_args": {} 
  37.     }, 
  38.     "changed"false
  39.     "ping""pong" 

目前為止,一切順利。您能夠從容器輸入命令。在下一節中,將對 Ansible 使用特定于 Docker 的擴展。

使用 playbook 和插件擴展 Ansible 環境

實質上,Ansible 通過 playbook 自動化了它的執行,這些 playbook 是指定要執行的每個任務和它們的屬性的 YAML 文件(參見清單 7)。

Ansible 還使用了清單 (inventory) 來將用戶提供的主機映射到基礎架構中的具體端點。不同于上一節中使用的靜態 hosts 文件,Ansible 也支持動態內容。內置的列表包含一個 Docker 插件,該插件可查詢 Docker 守護進程并向 Ansible playbook 共享大量信息。

清單 7. 一個 Ansible playbook

  1. # provision.yml 
  2.  
  3. - name: debug docker host 
  4.   hosts: docker 
  5.   tasks: 
  6.   - name: debug infrastructure 
  7.     # access container data : print the state 
  8.     debug: var=hostvars["builder"]["docker_state"
  9.  
  10. # you can target individual containers by name 
  11. - name: configure the container 
  12.   hosts: builder 
  13.   tasks: 
  14.    - name: run dummy command 
  15.      command: /bin/echo hello world 

清單 8 中的命令查詢 Docker 主機,導入事實,打印一些事實,并使用它們對構建器容器執行第二個任務(如 清單 7 中所示)。

清單 8. 查詢 Docker 主機的命令

  1. ansible-playbook provision.yml -i /etc/ansible/inventory 
  2. # ... 
  3. TASK [setup] ******************************************************************** 
  4. fatal: [builder]: FAILED! => {"msg": "ERROR! SSH encountered an unknown error during the 
  5. connection. Re-run the command using -vvvv, which enables SSH debugging 
  6. output to help diagnose the issue", "failed": true
  7. # ... 

Ansible 不能連接容器,因為它沒有運行 SSH 服務器。SSH 服務器是一個要管理的額外進程,它與實際應用程序完全無關。在下一節中,我們將使用一個連接插件來排除此困難。

連接插件是實現傳輸命令(比如 SSH 或本地執行)的類。Docker 1.3 隨帶了 docker exec,并能夠在容器命名空間內運行任務。此外,因為您之前已學習如何連接特定的目標容器,所以您可以使用此功能來處理 playbook。

像其他插件類型一樣,連接掛鉤(參見 清單 9)繼承一個抽象類,會在您將其放到預期的目錄(您在配置文件 ansible.cfg 中定義的是 /opt/ansible-plugins/connections)時自動可用。

清單 9. 連接插件

  1. # saved as ./connection_plugins/docker.py 
  2.  
  3. import subprocess 
  4. from ansible.plugins.connections import ConnectionBase 
  5.  
  6. class Connection(ConnectionBase): 
  7.  
  8.    @property 
  9.     def transport(self): 
  10.         """ Distinguish connection plugin. """ 
  11.         return 'docker' 
  12.  
  13.    def _connect(self): 
  14.         """ Connect to the container. Nothing to do """ 
  15.         return self 
  16.  
  17.    def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, 
  18.                      executable='/bin/sh', in_data=None, su=None, 
  19.                      su_user=None): 
  20.         """ Run a command within container namespace. """ 
  21.  
  22.     if executable: 
  23.         local_cmd = ["docker""exec", self._connection_info.remote_addr, executable, '-c', cmd] 
  24.     else
  25.         local_cmd = '%s exec "%s" %s' % ("docker", self._connection_info.remote_addr, cmd) 
  26.  
  27.     self._display.vvv("EXEC %s" % (local_cmd), host=self._connection_info.remote_addr) 
  28.     p = subprocess.Popen(local_cmd, 
  29.         shell=isinstance(local_cmd, basestring), 
  30.         stdin=subprocess.PIPE, stdout=subprocess.PIPE, 
  31.         stderr=subprocess.PIPE) 
  32.  
  33.     stdout, stderr = p.communicate() 
  34.     return (p.returncode, '', stdout, stderr) 
  35.  
  36.     def put_file(self, in_path, out_path): 
  37.         """ Transfer a file from local to container """ 
  38.         pass 
  39.  
  40.     def fetch_file(self, in_path, out_path): 
  41.         """ Fetch a file from container to local. """ 
  42.         pass 
  43.  
  44.     def close(self): 
  45.         """ Terminate the connection. Nothing to do for Docker""" 
  46.         pass 

#p#

此代碼掛鉤到 Ansible 模塊中,以便通過一個本地 docker exec 而不是默認的 ssh 來運行命令。您需要重新排列一些設置步驟來告訴 Ansible 使用此插件(參見 清單 10)。

清單 10. docker exec 的連接插件

  1. # modify the builder Dockerfile to upload the plugin code  
  2. where Ansible is expecting connection plugins 
  3. echo "ADD connection_plugins/docker.py /opt/ansible-plugins/connections/docker.py" >> Dockerfile 
  4.  
  5. # then, you need to explicitly tell which connection hook to use  
  6. when executing playbooks. 
  7. # you can achieve this by inserting the 'connection' property at the top  
  8. of provision tasks in provision.yml 
  9.  
  10. - name: configure the container 
  11.   connection: docker 
  12.   hosts: builder 
  13.  
  14. # you are ready to redeploy the builder container  
  15. # (providing DOCKER_HOST and DOCKER_API_VERSION are still set like before) 
  16.  
  17. # rebuild the image 
  18. docker build -t article/ansible . 
  19.  
  20. # restart the builder environment 
  21. docker run -it --name builder \ 
  22.     # make docker client available inside 
  23.     -v /usr/bin/docker:/usr/bin/docker \ 
  24.     -v /var/run/docker.sock:/var/run/docker.sock \ 
  25.     # detect local ip 
  26.     -e DOCKER_HOST=$DOCKER_HOST \ 
  27.     -e DEFAULT_DOCKER_API_VERSION=DOCKER_API_VERSION \ 
  28.     -v $PWD:/app -w /app \  # mount the working space 
  29.     article/ansible bash 
  30.  
  31. # rerun provisioning from inside 
  32. ansible-playbook -i /etc/ansible/inventory provision.yml 
  33. # ... Hurrah, full green output ... 

目前為止,您在容器中運行 Ansible 任務,對容器或主機沒有太多需求。盡管此實現滿足了初始需求,但仍有一些不嚴密的地方需要解決。

前面的代碼在同一個節點上運行任務。一種更逼真的工作流會啟動一個新基礎鏡像,配置它,最終提交、推送和關閉得到的工件。得益于 Ansible 中內置的 Docker 模塊,這些步驟無需額外的代碼即可實現(參見 清單 11)。

清單 11. Ansible 中啟動一個新基礎鏡像的 Docker 模塊

  1. --- 
  2. - name: initialize provisioning 
  3.   hosts: docker 
  4.  
  5.   - name: start up target container 
  6.     docker: 
  7.       image: python:2.7 
  8.       name: lab 
  9.       pull: missing 
  10.       detach: yes 
  11.       tty: yes 
  12.       command: sleep infinity 
  13.       state: started 
  14.   # dynamically update inventory to make it available down the playbook 
  15.   - name: register new container hostname 
  16.     add_host: name=lab 
  17.  
  18. - name: provision container 
  19.   connection: docker 
  20.   hosts: lab 
  21.   tasks: 
  22.       # ... 
  23.  
  24. - name: finalize build 
  25.   hosts: docker 
  26.   tasks: 
  27.     - name: stop container 
  28.       docker: 
  29.         name: lab 
  30.         image: python:2.7 
  31.         state: stopped 

前面已經提到過,自動命名和存儲在成功配備后構建的鏡像會很方便。不幸的是,Ansible 中的 Docker 模塊沒有實現方法來標記和推送鏡像。您可以使用簡單的 shell 命令來克服此限制(參見 清單 12)。

清單 12. 命名和存儲鏡像的 shell 命令

  1. # name the resulting artifact under a human readable image tag 
  2. docker tag lab article/lab:experimental 
  3.  
  4. # push this image to the official docker hub 
  5. # make sure to replace 'article' by your own Docker Hub login (https://hub.docker.com) 
  6. # (this step is optional and will only make the image available from any docker host.  
  7. You can skip it or even use your own registry) 
  8. docker push article/lab:experimental 

我們的工具正在成形,但它仍缺少一個必要特性:層緩存。

在使用 Dockerfile 構建容器時,通常需要迭代許多次才能完成。為了顯著加快該過程,成功的步驟會被緩存并在后續運行中重用。

要復制此行為,我們的工具在每次成功完成任務后提交了容器狀態。如果發生構建錯誤,該工具會從上次的快照位置重新啟動配備過程。Ansible 承諾實現冪等的任務,所以以前成功的任務不會處理兩次。

借助 Ansible,您可以使用回調插件來掛住任務事件(參見 清單 13)。這些類應實現了特定的回調,這些回調在 playbook 生命周期的各個步驟上觸發。

清單 13. 掛住任務事件的回調插件

  1. # save as callback_plugins/docker-cache.py 
  2. import hashlib 
  3. import os 
  4. import socket 
  5.  
  6. # Hacky Fix `ImportError: cannot import name display` 
  7. # pylint: disable=unused-import 
  8. import ansible.utils 
  9. import requests 
  10. import docker 
  11.  
  12.  
  13. class DockerDriver(object): 
  14.     """ Provide snapshot feature through 'docker commit'. """ 
  15.  
  16.     def __init__(self, author='ansible'): 
  17.         self._author = author 
  18.         self._hostname = socket.gethostname() 
  19.         try
  20.             err = self._connect() 
  21.         except (requests.exceptions.ConnectionError, docker.errors.APIError), error: 
  22.             ansible.utils.warning('Failed to contact docker daemon: {}'.format(error)) 
  23.             # deactivate the plugin on error 
  24.             self.disabled = True 
  25.             return 
  26.  
  27.         self._container = self.target_container() 
  28.         self.disabled = True if self._container is None else False 
  29.  
  30.     def _connect(self): 
  31.         # use the same environment variable as other docker plugins 
  32.         docker_host = os.getenv('DOCKER_HOST''unix:///var/run/docker.sock'
  33.         # default version is current stable docker release (10/07/2015) 
  34.         # if provided, DOCKER_VERSION should match docker server api version 
  35.         docker_server_version = os.getenv('DOCKER_VERSION''1.19'
  36.         self._client = docker.Client(base_url=docker_host, 
  37.                                      version=docker_server_version) 
  38.         return self._client.ping() 
  39.  
  40.     def target_container(self): 
  41.         """ Retrieve data on the container you want to provision. """ 
  42.         def _match_container(metadatas): 
  43.             return metadatas['Id'][:len(self._hostname)] == self._hostname 
  44.  
  45.         matchs = filter(_match_container, self._client.containers()) 
  46.         return matchs[0] if len(matchs) == 1 else None 
  47.  
  48.     def snapshot(self, host, task): 
  49.         tag = hashlib.md5(repr(task)).hexdigest() 
  50.         try
  51.             feedback = self._client.commit(container=self._container['Id'], 
  52.                                            repository='factory'
  53.                                            tag=tag, 
  54.                                            author=self._author) 
  55.         except docker.errors.APIError, error: 
  56.             ansible.utils.warning('Failed to commit container: {}'.format(error)) 
  57.             self.disabled = True 
  58.  
  59.  
  60. # pylint: disable=E1101 
  61. class CallbackModule(object): 
  62.     """Emulate docker cache. 
  63.     Commit the current container for each task. 
  64.  
  65.     This plugin makes use of the following environment variables: 
  66.         - DOCKER_HOST (optional): How to reach docker daemon. 
  67.           Default: unix://var/run/docker.sock 
  68.         - DOCKER_VERSION (optional): Docker daemon version. 
  69.           Default: 1.19 
  70.         - DOCKER_AUTHOR (optional): Used when committing image. Default: Ansible 
  71.  
  72.     Requires: 
  73.         - docker-py >= v0.5.3 
  74.  
  75.     Resources: 
  76.         - http://docker-py.readthedocs.org/en/latest/api/ 
  77.     ""
  78.  
  79.     _current_task = None 
  80.  
  81.     def playbook_on_setup(self): 
  82.         """ initialize client. """ 
  83.         self.controller = DockerDriver(self.conf.get('author''ansible')) 
  84.  
  85.     def playbook_on_task_start(self, name, is_conditional): 
  86.         self._current_task = name 
  87.  
  88.     def runner_on_ok(self, host, res): 
  89.         if self._current_task is None: 
  90.             # No task performed yet, don't commit 
  91.             return 
  92.         self.controller.snapshot(host, self._current_task) 

因為您已將代碼上傳到期望的位置,并重新構建了構建器容器,所以您可以像 docker exec 連接插件一樣注冊此插件。

清單 14. 注冊回調插件的命令

  1. # modify the builder Dockerfile to upload the code where Ansible is expecting callback plugins 
  2. echo "ADD callback_plugins/docker-cache.py /opt/ansible-plugins/callbacks/docker-cache.py" >> Dockerfile 

重新構建構建器容器并重新運行 Ansible playbook 后,該模塊會自動加載,您可以查看中間容器是如何創建的(參見 清單 15)。

清單 15. Docker 鏡像

  1. REPOSITORY          TAG                     IMAGE ID            CREATED             VIRTUAL SIZE 
  2. factory             bc0fb8843e88566c    bbdfab2bd904        32 seconds ago      829.8 MB 
  3. factory             d19d39e0f0e5c133    e82743310d8c        55 seconds ago      785.2 MB 

結束語

配備是一個復雜流程,您在本教程中執行的實現為未來的開發奠定了基礎。代碼本身已經過簡化,而且一些步驟仍需人類干預。緩存實現肯定值得更多關注,例如更具體的提交命名或清理技能。

盡管如此,您創建了一個可運行 Ansible playbook 來管理容器配置的工具。借助此實現,您可以通過為基礎架構的微型服務來組合、重用和設置陳述性的構建文件,充分利用 Ansible 的全部威力。此解決方案可幫助避免鎖定問題。您開發的插件包裝了 playbook,您可對不同的目標重用這些 playbook,而且極低的需求使得該項目能兼容大部分提供程序。

原文鏈接:http://www.ibm.com/developerworks/cn/cloud/library/cl-provision-docker-containers-ansible/index.html

責任編輯:Ophira 來源: ibm developerWorks 中國
相關推薦

2022-06-10 10:01:17

MacDockerLinux

2013-08-06 09:49:01

2009-11-06 08:57:31

WCF開發

2009-11-20 12:09:40

ExchangeVPNWindowsServ

2021-03-15 10:26:29

邊緣計算云計算混合云

2018-02-01 21:18:40

戴爾

2011-01-20 11:42:49

同事

2016-09-02 16:49:54

APPVR

2020-09-16 11:20:40

PythonBashLinux

2019-01-03 13:58:53

人工智能大數據數據分析

2016-08-12 09:49:06

Intel

2018-07-30 16:04:09

ReactJS代碼HTML

2023-03-30 16:23:09

人工智能AI

2013-05-31 09:03:47

SkypeLync集成

2009-06-19 15:11:34

DWR和Spring

2015-03-05 10:27:56

蘋果IBM

2022-05-06 14:19:02

邊緣計算物聯網5G

2017-11-15 08:26:52

IntelAMD技術

2015-02-09 19:49:19

暢捷通

2015-04-22 17:22:05

eBay京東
點贊
收藏

51CTO技術棧公眾號

久久久久久国产精品久久| 日韩精品在线看片z| 日韩尤物视频| 国产麻豆免费视频| 国产精品日韩精品欧美精品| 国产亚洲欧美日韩精品| 伊人五月天婷婷| 亚洲黄色免费av| 亚洲蜜臀av乱码久久精品蜜桃| 精品国产一区二区三区四区vr| 国产精品国产精品国产| 亚洲精品1区2区| www.xxxx欧美| b站大片免费直播| 香蕉免费一区二区三区在线观看 | 欧美黄色免费在线观看| 久久av免费| 精品国产成人在线影院| 国产精品区在线| 永久免费毛片在线播放| 一级日本不卡的影视| 亚洲高清在线观看一区| 三级在线电影| 成人激情视频网站| 亚洲自拍小视频| 中文字幕永久在线视频| 久久久www| 国模极品一区二区三区| 东方av正在进入| 91综合久久| 国产一区二区精品丝袜| 国产偷人妻精品一区| 99re8这里有精品热视频8在线| 在线视频亚洲一区| 欧美色图另类小说| 2001个疯子在线观看| 亚洲伦理在线精品| 午夜啪啪免费视频| 日本在线视频站| 中文字幕av一区二区三区| 欧美精品尤物在线| 人妻少妇一区二区三区| 丁香亚洲综合激情啪啪综合| 999国产视频| jlzzjlzz亚洲女人18| 蓝色福利精品导航| 国产美女精品免费电影| 中文字幕有码视频| 久久99精品久久久| 91久久久久久久久久| 97人妻精品一区二区三区| 精品夜夜嗨av一区二区三区| 国产在线不卡精品| 国产精品久久久久久久久毛片| 精品无人码麻豆乱码1区2区| 国产日韩av在线播放| 国产一区二区三区视频免费观看| 久久最新视频| 国产精品第1页| 在线免费一级片| 激情综合网激情| 亚洲一区中文字幕| 黄色av免费观看| 97精品久久久久中文字幕| 欧美13一14另类| 国产一级免费在线观看| 日本一区二区三区久久久久久久久不| 亚洲v国产v在线观看| 免费人成在线观看播放视频| 亚洲欧美日韩综合aⅴ视频| 日本香蕉视频在线观看| 蜜桃av在线| 欧美伊人久久久久久久久影院| wwwwwxxxx日本| 欧美高清hd| 精品视频久久久久久| x88av在线| 欧美在线观看天堂一区二区三区| 欧美高清在线观看| 欧美激情黑白配| 久久99热国产| 黄色99视频| chinese偷拍一区二区三区| 亚洲视频精选在线| 免费看国产曰批40分钟| 69堂精品视频在线播放| 日韩三级高清在线| 大又大又粗又硬又爽少妇毛片| 欧美日韩黑人| 欧美激情一区二区三区成人| 午夜婷婷在线观看| 国产一区美女在线| 精品欧美一区二区久久久伦| 天堂中文8资源在线8| 亚洲电影中文字幕在线观看| 妺妺窝人体色www在线观看| 国产乱码精品一区二区三区亚洲人 | 免费视频一区三区| 久久久91精品国产| 日韩视频在线观看一区| 国产精品中文字幕一区二区三区| 精品国产综合区久久久久久| 精品黄色免费中文电影在线播放| 图片区小说区国产精品视频| 在线能看的av网站| 最新亚洲精品| 欧美激情性做爰免费视频| 最近中文字幕在线视频| 99r精品视频| 2021国产视频| 国内精品伊人| 亚洲欧美综合精品久久成人| 免费视频一二三区| 久久av老司机精品网站导航| 欧美一区二区三区成人久久片| 欧美性猛片xxxxx免费中国| 欧美影院午夜播放| 国产又爽又黄无码无遮挡在线观看| 我不卡影院28| 国产精品白嫩初高中害羞小美女| 日本激情一区二区三区| 中文字幕一区二区三区蜜月| 日本成人中文字幕在线| 群体交乱之放荡娇妻一区二区 | 日韩精品一区二区三区丰满 | 综合天堂av久久久久久久| 国产精品成人在线| 狠狠v欧美ⅴ日韩v亚洲v大胸| 亚洲五月六月丁香激情| 五月天婷婷在线观看视频| 日韩理论在线| 国产精品综合久久久| 成人影视在线播放| 色久综合一二码| 亚洲成人网在线播放| 一区二区三区国产盗摄| 国产在线资源一区| 爱草tv视频在线观看992| 欧美xxxx老人做受| 妺妺窝人体色www聚色窝仙踪| 国产一区亚洲一区| 妞干网这里只有精品| 高清不卡一区| 久久夜精品香蕉| va婷婷在线免费观看| 有码一区二区三区| 美国黄色一级视频| 在线日韩中文| 久久av一区二区三区漫画| 中文字幕在线免费观看视频| 亚洲精品永久免费精品| 国产91精品看黄网站在线观看| 国产亚洲精品免费| 校园春色 亚洲色图| 99久久.com| 99re热精品| av电影院在线看| 日韩av一区二区在线观看| 亚洲精品国产精品乱码| 久久久精品中文字幕麻豆发布| 欧美日韩在线免费播放| 日韩免费久久| 91免费在线观看网站| 久操av在线| 亚洲免费av片| 中文字幕一区二区三区免费看| 国产精品三级视频| 免费人成视频在线播放| 亚洲东热激情| 日韩高清dvd| avtt久久| 97精品久久久| 国产黄在线观看| 91精品欧美一区二区三区综合在| 久久免费黄色网址| 久久久久久97三级| 九九九九九九九九| 91久久夜色精品国产九色| 久久综合久久综合这里只有精品| 日本欧美韩国| 欧美寡妇偷汉性猛交| 欧美视频免费一区二区三区| 欧美色综合久久| 久久久久成人精品无码| 久久久精品免费观看| 在线观看网站黄| 久久国产主播| 丰满人妻一区二区三区53号| 亚洲第一论坛sis| 91精品中文在线| 在线观看网站免费入口在线观看国内| 中文国产成人精品| 免费av一级片| 欧美久久久久久蜜桃| 好吊操这里只有精品| 欧美国产日韩在线观看| 日批免费观看视频| 久久99精品网久久| 国产精品丝袜久久久久久消防器材| 婷婷激情综合| 青青草原成人| 大奶在线精品| 国产在线视频2019最新视频| h片在线观看视频免费免费| 日韩亚洲欧美成人| 欧美高清电影在线| 欧美精品一区二| 国产又粗又猛又爽又黄的| 91国偷自产一区二区三区成为亚洲经典 | 小嫩嫩12欧美| 成人欧美视频在线| 日韩成人一区| 国产不卡av在线| 黄色aa久久| 欧美劲爆第一页| 国产剧情在线| 色小说视频一区| 免费一级毛片在线观看| 亚洲国产私拍精品国模在线观看| 国产女人18毛片水18精| 欧美色窝79yyyycom| 午夜精品免费观看| 欧美视频一二三| 国产精品免费av一区二区| 一区二区三区免费看视频| 多男操一女视频| 国产精品网站在线观看| 国产一区二区三区四区五区六区| 成人av在线播放网址| av电影中文字幕| 国产自产v一区二区三区c| 免费一区二区三区在线观看| 日韩不卡一二三区| 欧美日韩在线中文| 国产精品日本| 少妇高清精品毛片在线视频| 久久精品人人做人人爽电影蜜月| 丁香花在线影院观看在线播放| 国产精品a级| bt天堂新版中文在线地址| 国语自产精品视频在线看8查询8| 中文字幕乱码免费| 欧美一区影院| 成人一级生活片| 亚洲毛片网站| 北条麻妃69av| 美女日韩在线中文字幕| 国产无套粉嫩白浆内谢的出处| 日韩国产精品久久久| 日本成人中文字幕在线| 久久精品久久综合| 中文字幕第22页| 国产成人av电影在线观看| 国产情侣久久久久aⅴ免费| 不卡的看片网站| 国产美女喷水视频| 日本一区二区三区国色天香| 日韩在线一卡二卡| 夜夜精品视频一区二区| 日本天堂网在线观看| 色综合天天综合网国产成人综合天| 欧美日韩一级黄色片| 欧美日本国产一区| 国产成人精品毛片| 亚洲激情视频网站| 毛片在线免费| 精品国产欧美一区二区五十路| 国产美女av在线| 性色av香蕉一区二区| 天堂久久午夜av| 亚洲最大福利视频网| 日韩伦理一区二区三区| 日本亚洲欧洲精品| 一区二区三区中文| 青青草视频在线免费播放| 日韩黄色免费电影| 特黄特黄一级片| 久久天天做天天爱综合色| 国产成人精品视频免费| 一区二区三区在线观看国产| 日韩精品在线观看免费| 精品视频一区二区不卡| 午夜久久久久久噜噜噜噜| 亚洲免费电影一区| 超碰公开在线| 2020欧美日韩在线视频| 欧美黄色成人| 精品乱色一区二区中文字幕| 三级电影一区| 僵尸世界大战2 在线播放| 久久精品国产亚洲高清剧情介绍 | 国产一区二区三区四区五区| 亚洲免费av网| 免费亚洲一区| 四川一级毛毛片| 国产亚洲综合性久久久影院| 青娱乐国产在线| 欧美影片第一页| 天堂国产一区二区三区| 爱福利视频一区| 高清av不卡| 成人一区二区三区四区| 第一sis亚洲原创| www国产精品内射老熟女| 国产又粗又猛又爽又黄91精品| 女~淫辱の触手3d动漫| 亚洲综合色丁香婷婷六月图片| 中文字幕日本视频| 日韩电影在线观看永久视频免费网站| 婷婷激情在线| 日本久久亚洲电影| 国产日韩三级| 久久久天堂国产精品| 美女看a上一区| 少妇真人直播免费视频| 亚洲一区二区三区在线播放| 888奇米影视| 一区二区三区四区精品| 天堂av在线网| 国产伦精品一区二区三区在线 | 九九热爱视频精品视频| 人妻少妇精品久久| 国产精品系列在线播放| 99精品中文字幕| 欧美主播一区二区三区| 欧洲一级在线观看| 69视频在线免费观看| 大桥未久女教师av一区二区| 亚洲小说欧美另类激情| 久久99久久久欧美国产| 免费观看特级毛片| 欧美日韩二区三区| 视频免费一区| 国产精品亚洲视频在线观看| 精品国产精品| av视屏在线播放| 中文字幕电影一区| 中文字幕av网站| 色伦专区97中文字幕| 久久婷婷五月综合色丁香| 亚洲视频sss| 久久国产夜色精品鲁鲁99| 色撸撸在线视频| 欧美日韩夫妻久久| caoporn免费在线视频| 亚洲a∨日韩av高清在线观看| 91九色精品| 在线观看一区二区三区视频| 亚洲综合色噜噜狠狠| 日韩有码第一页| 欧美性受xxx| 免费精品国产| 九九热精品在线播放| 中文字幕人成不卡一区| av男人天堂网| 午夜精品在线视频| 亚洲宅男网av| 杨幂毛片午夜性生毛片| ●精品国产综合乱码久久久久| 国产女人18毛片水真多| 欧美激情一级欧美精品| 老牛国内精品亚洲成av人片| 97xxxxx| 国产精品国产三级国产aⅴ原创| 一区二区三区播放| 欧美高清在线视频观看不卡| 日韩极品在线| www.se五月| 亚洲亚洲精品在线观看| 亚洲色图狠狠干| 国产精品永久免费| 欧美日韩国产探花| 丝袜美腿中文字幕| 欧美日韩aaaaaa| 波多野结衣中文字幕久久| 欧美日韩一区二区视频在线 | 亚洲深夜福利| 少妇人妻好深好紧精品无码| 欧美一卡二卡在线| 在线天堂新版最新版在线8| 亚洲色图自拍| 99免费精品视频| 亚洲天堂网在线视频| 国模私拍一区二区三区| 成人羞羞网站入口免费| 亚洲成人激情小说| 色综合久久中文字幕综合网| 九色porny在线| 欧美连裤袜在线视频| 国产精品99久久久| 亚洲天堂五月天| 欧美精品久久久久久久| 色呦哟—国产精品| 黄色性生活一级片| 日韩一区二区免费电影| 日韩a**中文字幕| 国产综合av在线| 亚洲美女免费视频| 日韩伦理在线观看| 免费av在线一区二区|