Chengwei Chen
Mar 6, 2018 · 13 min read

自從上次(2016年)試用 ansible-container 遭遇慘痛的踩雷經驗之後,如今 ansible-container 的版本號已進入 0.9.2,據說文件及穩定度皆已有所改善,因此決定趁著放假撥一點空檔再次試用它,希望這次的試用過程不會像上次一樣地慘痛。


以乾淨的 Ubuntu 16.04 環境試用

根據官方文件ansible-container 的 Prerequisites 為

  • Python 2.7 or Python 3.5
  • pip
  • setuptools 20.0.0+

因此決定直接以乾淨的 ubuntu 16.04 環境挑戰,避免遇到 python 版本或相依套件的問題。首先透過 Vagrant 建立乾淨的 ubuntu 16.04,並在 VM 內安裝 Docker。接著以下面指令安裝 pip

apt-get update
apt-get install python-pip
pip install --upgrade pip

接著按官方文件安裝 ansible-container

pip install ansible-container[docker]

[] 內除了可以填 docker 之外,也可填寫另外兩種 engines,分別是 k8s 及 openshift。)

順利安裝後即可執行 ansible-container -h,查看 help。

試用 ansible-container

開始簡易地試用 ansible-container

首先建立乾淨的資料夾並產生相關檔案。

mkdir demo
cd demo
ansible-container init

執行指令之後,即可產生 ansible-container 所需之結構,,如下圖可以看見一共自動產生了五個檔案,每個檔案分別有其用途。

  • ansible.cfg - 應該無須解釋,即是 ansible 的 Configuration file。在執行 ansible 指令時,會優先參照當前路徑之下有沒有 ansible.cfg,因此若是需要特別的組態設定時,即可隨著專案各別搭配一個 ansible.cfg
  • ansible-requirements.txt - 用來紀錄所需之 Python dependencies。
  • container.yml - 類似 docker-compose.yml,用來描述你所需之 container 架構與環境,這正是 ansible-container 指令的關鍵檔案。
  • meta.yml - 如同 Ansible Roles 的 meta,官方似乎有意要讓 Ansible Galaxy 也能夠存放 ansible-container 的 templates。(不過目前在 Ansible Galaxy 上,似乎尚無法針對此種 templates 進行搜尋)
  • requirements.yml - 同 Roles,用來紀錄所需之相依 Roles。

接著修改 container.yml,將 services: 這一段修改成如下。

services:
web:
from: "centos:7"
ports:
- "80:80"
command: ["/bin/bash"]

接下來就試著執行 ansible-container build,送出指令之後需要一段不短的等待時間,你會發現如下圖,畫面上也會秀出訊息要你 be patient。

等待許久之後,接著就⋯⋯就爆掉了。

ERROR   Unknown exception
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/container/cli.py", line 299, in __call__
getattr(core, u'hostcmd_{}'.format(args.subcommand))(**vars(args))
File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
return fn(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/container/core.py", line 181, in hostcmd_build
environment=env_vars
File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 105, in __wrapped__
return fn(self, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/container/__init__.py", line 28, in __wrapped__
return fn(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/container/docker/engine.py", line 1070, in build_conductor_image
return image.id
AttributeError: 'tuple' object has no attribute 'id'

根據 issue,有其他使用者表示可以用下列指令修復。

pip install docker==2.7.0

修復並再次執行 ansible-container build,即可獲得正常的結果。

那麼到底 ansible-container 在背後偷偷做了哪些事情了?大致包含了以下幾項:(如果你有興趣一探究竟,可以改用指令 ansible-container --debug build,即可一窺其中的奧妙。)

  • 下載 ansible-container 所需之 docker images。
  • 下載 container.yml 中載明各 Service 所需之 base image。
  • 接著會 build 類似 ansible/container-conductor-centos-7:0.9.2 此種名稱的 docker images。
  • 最後運行一些名稱帶有 conductor 的 container,根據 container.yml 的設定,進行環境設置(包含你想要執行的 roles),將 base image 建置成各 services 最終的 docker images。

試著以 ansible-container 建立 nginx + php 的環境

上面我們測試 ansible-container build 時,使用的是一個沒特別意義的 container.yml,接著我們就嘗試用 ansible-container 建立並運行 nginx + php 的環境。

第一步修改 container.yml

version: "2"
settings:

conductor:
base: ubuntu:16.04

project_name: demo

services:
php:
from: "ubuntu:16.04"
roles:
- { role: geerlingguy.php, php_enable_webserver: false, php_enable_php_fpm: true }
- create_run_php
ports:
- "9000:9000"
command: ["/usr/sbin/php-fpm7.0", "-F"]

nginx:
from: "ubuntu:16.04"
roles:
- geerlingguy.nginx
ports:
- "80:80"
links:
- php
command: ["/usr/sbin/nginx", "-g", "daemon off;"]

registries: {}

按上述的 yml,如果是熟悉 docker、docker-compose 的工程師應該多半能推敲出會產生什麼樣的結果:

  • 會 build 兩個 docker image
  • 皆是以 ubuntu:16.04 為 base image
  • 分別提供 php 及 nginx 這兩種 service
  • 屆時運行 php 的 container 時會開通 port 9000
  • 同理運行 nginx 的 container 則開通 port 80
  • 同時運行 nginx 的 container 時要相依於 php 的 container
  • 另外就是為了 build 出這兩個 image,會以 base image 為基礎,透過 geerlingguy.php 及 geerlingguy.nginx 這兩個 Ansible role 來安裝所需之 php 及 nginx

眼尖的人應該有注意到在 php 那一段有還有多一個 role 名為 create_run_php,特別針對這點說明。狀況是這樣的,如果你採用 ubuntu:16.04 的 base image 並於其上透過 role geerlingguy.php 來安裝 php 環境。在安裝完 php,想要啟動 php-fpm 時,將會遇見因為找不到 /run/php/php7.0-fpm.pid 而無法啟動的錯誤。

為了修正這個錯誤,最簡單的方法是手動補建 /run/php 這個資料夾。因此這個 create_run_php 即是用來幫我修復這個錯誤的客制 role。(或者你也可以考慮以修改 php-fpm.confpid = /run/php/php7.0-fpm.pid 的設定來解決。)

搞定 container.yml 可別急著執行 ansible-container build,在那之前你還得先將會使用到的 roles 都先下載完畢才行,這部分只要按 ansible-playbook 的使用慣例,在 container.yml 同一個資料夾內建立 roles 資料夾,並將各個 roles 分別丟進以自己名稱為名的資料夾即可。

接著就執行 ansible-container build,如一切順利,應該會看見類似下述的過程。

首先會看見 ansible-container 真的會在 container 上跑 role。

當 role 都執行完畢,就會 build 成 image,並且繼續 build 下一個 image。

所有的 image 都建置完畢之後,就會如下圖一樣,告知你 All images successfully built

接著就用 docker images 查看成果。

透過以上的案例,我們驗證了確實可以透過 ansible-container 運用既有 roles 來建置 docker images,但實際上 roles 不一定能 100% 直接套用,例如前述在 php 的 container 內缺少 /run/php 該路徑的問題就是一個例子,將原本針對 VM、Server 而撰寫的 roles 轉而使用在 container 時可能會出現部分需要微調之處。

ansible-container run

除了 ansible-container build 之外,還有另一個厲害的指令是 ansible-container run,前面在介紹 container.yml 時有提過,它的結構非常類似 docker-compose.yml,這並非錯覺,因為 ansible-container 不僅可以用來建置 images,它也能如 docker-compose up 一樣,幫你運行多個 container 並建立彼此的相依與關聯。

續上案例,直接來執行 ansible-container run,即可看見如下圖的結果:

這次用 docker ps 來檢查,得到下圖的結果。

就如 container.yml 所紀錄的一樣,順利運行 php 及 nginx 兩個 container,並且其中的 service 皆有在提供服務。

如果用 docker inspect 檢查 demo_nginx_1,也確實會發現它和 demo_php_1 確實有連接在一起。

前面在安裝 ansible-container 時有稍微提到,除了 pip install ansible-container[docker] 之外,還可以 pip install ansible-container[docker,k8s,openshift],我想看到這應該就不用再多做解釋,很容易能夠推想到 Ansible 官方有計畫要讓 ansible-container 不只能單純 build、run containers,甚至能幫助你將 containers 運行於 k8s 及 openshift,不過本文就先略過這些內容,未來有機會再繼續試用這一塊。

最後如同 docker-compose stop 一樣,想要停止 container 可以執行 ansible-container stop,如果要刪除 containers 及 images 則可以透過 ansible-container destroy,如此方才建立的 container 及 images 皆會被一併刪除。

小結

從目前釋出的功能觀察,Ansible 官方對於 ansible-container 似乎有一些野心與期待,不過目前版本號依然尚未進入 1.0.0,因此仍有許多地方需要使用者們給予回饋與回報 bug,如果各位也有心試用,不妨也將發現的問題回報給官方,幫忙貢獻自己的心力。

回到 Ansible 這項工具本身,不乏有時會遇到人們詢問:「在 docker container 普遍的時代,ansible 還能用來做什麼?該何去何從?」,而或許 ansible-container 即是官方對此問題的其中一項回答,對此不知您是否也有什麼想法呢?


Laravel 道場

Laravel 道場致力於提供最好的 PHP/Laravel 教育訓練及顧問服務。從 2013…

Chengwei Chen

Written by

表面上是只會釋放閃光文的愛妻家,私底下其實是默默關注新知的技術愛好者。平時熱衷研究維運及自動化相關技術,目標是未來可以像畢凱艦長一樣用嘴巴叫所有主機做事! 目前為 DevOps Taiwan 社群志工以及 DevOpsDays Taipei 其中一位 Organizer。https://chengweichen.com

Laravel 道場

Laravel 道場致力於提供最好的 PHP/Laravel 教育訓練及顧問服務。從 2013 年起就經營開發社群、舉辦讀書會、教學工作坊,希望透過活動交流與互動,能增加開發者的本職學能及產能。聯絡信箱:hi@laravel-dojo.com

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade