CI/CDや、Ansibleのインストールが難しいオフライン環境とかで使えるかな、と思って、試しに作ってみた。
Ansibleバージョン
各メジャーバージョン毎の、最新マイナーバージョンは、各バージョン毎のリリースノートで確認できる。
2.8であればここから。
(なぜ2.8なのかは、deprecatedとなって2.9で消えたモジュールとかあるので、とりあえず2.8にした感じ)
(ちなみに試した結果、Python3だとpysphereは動作しない)
※ 2020.08.10時点で2.8.13だったが、2020.08.11時点で2.8.14にアップデートしてる。記事内では2.8.13で進めてる。
ベースイメージ
pip
でインストールするので、Pythonイメージをベースとした。
2020.08.10時点でpython:3.8.5-slim-buster
あたりかな。
とりあえずpull
する。
[zaki@cloud-dev ~]$ docker pull python:3.8.5-slim-buster 3.8.5-slim-buster: Pulling from library/python bf5952930446: Pull complete 385bb58d08e6: Pull complete ab14b629693d: Pull complete 7a5d07f2fd13: Pull complete 56745e40505a: Pull complete Digest: sha256:f7edd1bb431a224e7f4f3e23cbb22738e82f4895a6d28f86294ce006177360c3 Status: Downloaded newer image for python:3.8.5-slim-buster docker.io/library/python:3.8.5-slim-buster
Dockerfile作成のためのネタ作り用にbash
起動。
[zaki@cloud-dev ~]$ docker run -it python:3.8.5-slim-buster bash root@6b6492e770bb:/# root@6b6492e770bb:/# python --version Python 3.8.5 root@6b6492e770bb:/# pip pip pip3 pip3.8 root@6b6492e770bb:/# pip --version pip 20.2.1 from /usr/local/lib/python3.8/site-packages/pip (python 3.8) root@6b6492e770bb:/#
Ansible 2.8インストール
root@6b6492e770bb:/# pip install ansible==2.8.13 Collecting ansible==2.8.13 Downloading ansible-2.8.13.tar.gz (12.7 MB) |████████████████████████████████| 12.7 MB 3.2 MB/s Collecting jinja2 Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) |████████████████████████████████| 125 kB 6.5 MB/s Collecting PyYAML Downloading PyYAML-5.3.1.tar.gz (269 kB) |████████████████████████████████| 269 kB 3.2 MB/s Collecting cryptography Downloading cryptography-3.0-cp35-abi3-manylinux2010_x86_64.whl (2.7 MB) |████████████████████████████████| 2.7 MB 11.3 MB/s Collecting MarkupSafe>=0.23 Downloading MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl (32 kB) Collecting cffi!=1.11.3,>=1.8 Downloading cffi-1.14.1-cp38-cp38-manylinux1_x86_64.whl (409 kB) |████████████████████████████████| 409 kB 18.9 MB/s Collecting six>=1.4.1 Downloading six-1.15.0-py2.py3-none-any.whl (10 kB) Collecting pycparser Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB) |████████████████████████████████| 112 kB 18.5 MB/s Building wheels for collected packages: ansible, PyYAML Building wheel for ansible (setup.py) ... done Created wheel for ansible: filename=ansible-2.8.13-py3-none-any.whl size=12654620 sha256=f768271c4c958b04f4dfddde1e73dd6fcce16ae61b59e53b0812838b8c823884 Stored in directory: /root/.cache/pip/wheels/c2/75/3a/4707639b7733d0689b966c190b6828ddc98c8f8c9a90dcef07 Building wheel for PyYAML (setup.py) ... done Created wheel for PyYAML: filename=PyYAML-5.3.1-cp38-cp38-linux_x86_64.whl size=44617 sha256=1e4c20c21b93f8b820447ffdcf4c60f331feb3c808cedf3286461e48daa4e334 Stored in directory: /root/.cache/pip/wheels/13/90/db/290ab3a34f2ef0b5a0f89235dc2d40fea83e77de84ed2dc05c Successfully built ansible PyYAML Installing collected packages: MarkupSafe, jinja2, PyYAML, pycparser, cffi, six, cryptography, ansible Successfully installed MarkupSafe-1.1.1 PyYAML-5.3.1 ansible-2.8.13 cffi-1.14.1 cryptography-3.0 jinja2-2.11.2 pycparser-2.20 six-1.15.0
これだけか?
(だめ。sshがない。後述)
root@6b6492e770bb:/# which ansible /usr/local/bin/ansible root@6b6492e770bb:/# ansible --version ansible 2.8.13 config file = None configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/local/lib/python3.8/site-packages/ansible executable location = /usr/local/bin/ansible python version = 3.8.5 (default, Aug 4 2020, 16:24:08) [GCC 8.3.0]
失敗作
Dockerfile
FROM python:3.8.5-slim-buster RUN pip install ansible==2.8.13 CMD ["/usr/local/bin/ansible", "--version"]
これだけでいいかな。
(だめ。sshがない。後述)
build
[zaki@cloud-dev ansible]$ ls -F 2.8.13/ [zaki@cloud-dev ansible]$ ls -l 2.8.13/ 合計 4 -rw-rw-r--. 1 zaki zaki 107 8月 10 17:45 Dockerfile [zaki@cloud-dev ansible]$ cat 2.8.13/Dockerfile FROM python:3.8.5-slim-buster RUN pip install ansible==2.8.13 CMD ["/usr/local/bin/ansible", "--version"] [zaki@cloud-dev ansible]$ docker build -t ansible:2.8.13 . unable to prepare context: unable to evaluate symlinks in Dockerfile path: lstat /home/zaki/src/docker-images/ansible/Dockerfile: no such file or directory [zaki@cloud-dev ansible]$ docker build -t ansible:2.8.13 2.8.13/ Sending build context to Docker daemon 2.048kB Step 1/3 : FROM python:3.8.5-slim-buster ---> 07ea617545cd Step 2/3 : RUN pip install ansible==2.8.13 ---> Running in 32b8a3c22ee2 Collecting ansible==2.8.13 Downloading ansible-2.8.13.tar.gz (12.7 MB) Collecting jinja2 Downloading Jinja2-2.11.2-py2.py3-none-any.whl (125 kB) Collecting PyYAML Downloading PyYAML-5.3.1.tar.gz (269 kB) Collecting cryptography Downloading cryptography-3.0-cp35-abi3-manylinux2010_x86_64.whl (2.7 MB) Collecting MarkupSafe>=0.23 Downloading MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl (32 kB) Collecting six>=1.4.1 Downloading six-1.15.0-py2.py3-none-any.whl (10 kB) Collecting cffi!=1.11.3,>=1.8 Downloading cffi-1.14.1-cp38-cp38-manylinux1_x86_64.whl (409 kB) Collecting pycparser Downloading pycparser-2.20-py2.py3-none-any.whl (112 kB) Building wheels for collected packages: ansible, PyYAML Building wheel for ansible (setup.py): started Building wheel for ansible (setup.py): finished with status 'done' Created wheel for ansible: filename=ansible-2.8.13-py3-none-any.whl size=12654620 sha256=d6580d8b3a5eb988efd8fbf52f5012c47d8eea979356146134e4ac40ec6b3e82 Stored in directory: /root/.cache/pip/wheels/c2/75/3a/4707639b7733d0689b966c190b6828ddc98c8f8c9a90dcef07 Building wheel for PyYAML (setup.py): started Building wheel for PyYAML (setup.py): finished with status 'done' Created wheel for PyYAML: filename=PyYAML-5.3.1-cp38-cp38-linux_x86_64.whl size=44617 sha256=38be490d110d8b5f68c43993b572f7d7d4a89bd33fc4dfa302a1e55ecf253c1a Stored in directory: /root/.cache/pip/wheels/13/90/db/290ab3a34f2ef0b5a0f89235dc2d40fea83e77de84ed2dc05c Successfully built ansible PyYAML Installing collected packages: MarkupSafe, jinja2, PyYAML, six, pycparser, cffi, cryptography, ansible Successfully installed MarkupSafe-1.1.1 PyYAML-5.3.1 ansible-2.8.13 cffi-1.14.1 cryptography-3.0 jinja2-2.11.2 pycparser-2.20 six-1.15.0 Removing intermediate container 32b8a3c22ee2 ---> c723d156486c Step 3/3 : CMD ["/usr/local/bin/ansible", "--version"] ---> Running in 902e6e0c9f94 Removing intermediate container 902e6e0c9f94 ---> 39a7fa69321b Successfully built 39a7fa69321b Successfully tagged ansible:2.8.13 [zaki@cloud-dev ansible]$
[zaki@cloud-dev ansible]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE ansible 2.8.13 39a7fa69321b 22 seconds ago 243MB python 3.8.5-slim-buster 07ea617545cd 5 days ago 113MB : :
できました。
[zaki@cloud-dev ~]$ docker run --rm ansible:2.8.13 ansible 2.8.13 config file = None configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/local/lib/python3.8/site-packages/ansible executable location = /usr/local/bin/ansible python version = 3.8.5 (default, Aug 4 2020, 16:24:08) [GCC 8.3.0] [zaki@cloud-dev ~]$
push
Docker Hubに置いておく。
Docker Hub
Docker Hubにログインし、「Create Repository」押下。
リポジトリ名やDescriptionを適度に入力して、ページ下部の「Create」押下する。
Build Settingsのオプションはひとまず設定なし。
(今表示を見て気付いたんだけど、Docker Hubのプライベートのリポジトリって1個しか作れなかったのね…)
Docker Hubにリポジトリができました。
イメージのpush
ビルド済みイメージはこの通り。
[zaki@cloud-dev ~]$ docker images ansible REPOSITORY TAG IMAGE ID CREATED SIZE ansible 2.8.13 39a7fa69321b 30 minutes ago 243MB
これを、作成したzakihmkc/ansible
にpush
するために、docker tag
を使って別名を作成する。
[zaki@cloud-dev ~]$ docker images | grep ansible ansible 2.8.13 39a7fa69321b 30 minutes ago 243MB zakihmkc/ansible 2.8.13 39a7fa69321b 30 minutes ago 243MB
[zaki@cloud-dev ~]$ docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: zakihmkc Password: WARNING! Your password will be stored unencrypted in /home/zaki/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded [zaki@cloud-dev ~]$ [zaki@cloud-dev ~]$ docker push zakihmkc/ansible:2.8.13 The push refers to repository [docker.io/zakihmkc/ansible] 0cdb117a6909: Pushed 71c24c079ec4: Mounted from library/python 1e441fe06d90: Mounted from library/python 98ff2784e9f5: Mounted from library/python 2b99e2403063: Mounted from library/python d0f104dc0a1f: Mounted from library/python 2.8.13: digest: sha256:f6388d0d606eeee5c2d06ded24cf683b814b6f6b48d5d01d6d4999a03580068d size: 1582 [zaki@cloud-dev ~]$
Docker Hubだとこうなる。
一般ユーザーから見るとこんな感じ
※ ちなみにこれ、push直後でpull 4になってるので、くれぐれも機密情報込みのイメージをうっかりpushしないように。。
お試し実行
Dockerは動いているが、Ansibleは未インストールのホストでお試し。
[zaki@example ~]$ which ansible /usr/bin/which: no ansible in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/zaki/.local/bin:/home/zaki/bin) [zaki@example ~]$ which docker /usr/bin/docker [zaki@example ~]$ sudo docker version Client: Docker Engine - Community Version: 19.03.12 API version: 1.40 Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:46:54 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.12 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:45:28 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
[zaki@example ~]$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE
実行 (初回はpull
分の時間がかかる)
[zaki@example ~]$ sudo docker run --rm zakihmkc/ansible:2.8.13 Unable to find image 'zakihmkc/ansible:2.8.13' locally 2.8.13: Pulling from zakihmkc/ansible bf5952930446: Pull complete 385bb58d08e6: Pull complete ab14b629693d: Pull complete 7a5d07f2fd13: Pull complete 56745e40505a: Pull complete a651563c3173: Pull complete Digest: sha256:f6388d0d606eeee5c2d06ded24cf683b814b6f6b48d5d01d6d4999a03580068d Status: Downloaded newer image for zakihmkc/ansible:2.8.13 ansible 2.8.13 config file = None configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/local/lib/python3.8/site-packages/ansible executable location = /usr/local/bin/ansible python version = 3.8.5 (default, Aug 4 2020, 16:24:08) [GCC 8.3.0] [zaki@example ~]$
うむ。
ansible pingモジュール実行
Dockerコンテナ実行時に、用意したインベントリとプレイブックを参照できるようにvolume設定すればOK
[zaki@example ansible-work]$ ls inventory.ini playbook.yml [zaki@example ansible-work]$ cat inventory.ini [hosts] client1 ansible_host=192.168.0.18 client2 ansible_host=192.168.0.19 client3 ansible_host=192.168.0.21
[zaki@example ansible-work]$ sudo docker run -v "$PWD":/tmp -it --rm zakihmkc/ansible:2.8.13 ansible all -i /tmp/inventory.ini -m ping -k SSH password: client1 | FAILED! => { "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program" } client3 | FAILED! => { "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program" } client2 | FAILED! => { "msg": "to use the 'ssh' connection type with passwords, you must install the sshpass program" }
sshが無い。なるほど。。
修正版
Dockerfile
FROM python:3.8.5-slim-buster RUN pip install ansible==2.8.13 \ && apt update \ && apt install -y sshpass \ && apt clean \ && rm -rf /var/lib/apt/lists/* CMD ["/usr/local/bin/ansible", "--version"]
build
push
用のtagつけてビルド。(上書き)
[zaki@cloud-dev ansible]$ ls 2.8.13/ Dockerfile [zaki@cloud-dev ansible]$ docker build -t zakihmkc/ansible:2.8.13 2.8.13/
[zaki@cloud-dev ansible]$ docker images zakihmkc/ansible REPOSITORY TAG IMAGE ID CREATED SIZE zakihmkc/ansible 2.8.13 1a6ff41f0e9b 44 minutes ago 253MB zakihmkc/ansible <none> 39a7fa69321b 28 hours ago 243MB
前日(28時間前)の残骸が見える
push
[zaki@cloud-dev ansible]$ docker push zakihmkc/ansible:2.8.13
お試し実行
[zaki@example ansible-work]$ ls ansible.cfg inventory.ini playbook.yml
ファイル説明:
~/.ssh/known_hosts
などは無いし書き込んでも無意味なので、ansible.cfg
に無視する設定を記述。
[ssh_connection] ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
Ansible実行時にコンテナ内のユーザーIDは(デフォルトではrootだが)基本的に固定されてない前提で、inventory.iniにansible_user
で設定。
[hosts] client1 ansible_host=192.168.0.18 client2 ansible_host=192.168.0.19 client3 ansible_host=192.168.0.21 [all:vars] ansible_user=zaki
パスワード認証
-k
付与して実行。
前述のansible.cfg/inventoryをコンテナ内で使用するため、-v $PWD:/mnt
でコンテナ内/mnt
に送り込み、-w /mnt
で実行時のワーキングディレクトリを/mnt
に設定(ansible
実行時のカレントディレクトリを/mnt
にすることで、-v
で設定したansible.cfg
をカレントディレクトリで参照させる)
-it
でttyとstdinを実行時シェルと繋げて-k
によるパスワード認証などコンソールが使えるようにする。
この辺りもどうぞ。
あと、コンテナイメージ名指定の後のansible all -i /mnt/inventory.ini -m ping -k
は通常利用の通り。
[zaki@example ansible-work]$ sudo docker run -v "$PWD":/mnt -w /mnt -it --rm zakihmkc/ansible:2.8.13 ansible all -i /mnt/inventory.ini -m ping -k SSH password: client2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } client3 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } client1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" }
公開鍵認証
公開鍵設定は↑を組み合わせるなどして手動で一度仕込んでおこう。
[zaki@example ansible-work]$ sudo docker run -v "$PWD":/mnt -w /mnt -v ~/.ssh:/.ssh -it --rm zakihmkc/ansible:2.8.13 ansible all -i inventory.ini --private-key /.ssh/id_rsa_nopass -m ping client3 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } client2 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } client1 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" }
無事に公開鍵認証で(対話的にパスワード入力無しに)Ansible実行できました。
(root
で実行してるのでコンテナ実行中は鍵の参照権限的に危ないんだけど。。)
ansible-playbook
同じディレクトリにPlaybookファイルも置いてコンテナから参照できるようにすればこの通り。
[zaki@example ansible-work]$ sudo docker run -v "$PWD":/mnt -w /mnt -v ~/.ssh:/.ssh -it --rm zakihmkc/ansible:2.8.13 ansible-playbook -i inventory.ini --private-key /.ssh/id_rsa_nopass playbook.yml PLAY [all] ********************************************************************* TASK [Gathering Facts] ********************************************************* ok: [client2] ok: [client3] ok: [client1] TASK [run container] *********************************************************** ok: [client1] => { "msg": "cloud-dev" } ok: [client2] => { "msg": "manager" } ok: [client3] => { "msg": "registry" } PLAY RECAP ********************************************************************* client1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 client2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 client3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 [zaki@example ansible-work]$
動いてる。
イメージとソース(Dockerfile)はこちら。
Docker HubにdescribeとかDockerfileソースへのリンクとか設定しないとなぁ。。
Docker Hub、describeにusageとかちょっと書いてみた。Markdownで書けたのね。
Ansible Runner
公式でAnsibleのイメージあったらしい!
なんかこないだ自前でイメージ作ってたけど、実はansibleが公式にansible-runnerってイメージをdockerhubで公開してんだよね(前はタグがlatestしかなくて困ったけど最近はちゃんとバージョニングしてるので安心
— (っ’ヮ’c) < ★しっぽ (@ryosms) 2020年9月11日