背景
以前AnsibleのDockerモジュールを活用してDockerコンテナのイメージビルドからコンテナ作成までをAnsible上で行いました。Ansibleを使ってNuxt.jsのDockerコンテナを構築してみた
その時はAnsible-Containerというコンテナ管理に便利なツールがあることを紹介しましたが、2020年現在は開発終了されています。ただし、その後ansible-benderというAnsible Containerの機能を一部引き継いだツールが新しく登場しました。
今回はansible-benderを使ってコンテナイメージをビルドしていきたいと思います。
ansible-benderについて
ansible-benderはAnsible Playbookを使ってコンテナイメージをビルドすることができるツールです。(https://github.com/ansible-community/ansible-bender)
Dockerモジュールでは、Dockerfileの宛先パスをPlaybookで指定してコンテナイメージのビルドを行いましたが、ansible-benderでは直接Playbook内にコンテナイメージを記述することでコンテナイメージのビルドが可能となります。pipパッケージからインストールすることが可能です。
pip install ansible-bender
必須要件
ansible-benderを動かすには予めPodmanとBuildahをインストールする必要があります。
こちらのツールは前回の記事で紹介していますので、初めてツールの存在を知った方はそちらの記事もご参照ください。
またコンテナイメージをビルドする際、Pythonのインストールされたコンテナベースイメージが必要です。(Python2系3系問わない)
事前にPythonを含む最小コンテナイメージを用意しておくと後々便利です。参考記事ansible-bender でコンテナイメージを作成する
FROM debian:buster
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3 && apt-get clean
コンテナイメージのビルド
ansible-benderの準備ができましたら、コンテナイメージのビルドを行っていきます。
ここでは、前回の記事で構築したNuxt.jsのコンテナイメージをansible-benderでビルドできるか検証していきます。
ベースコンテナイメージの取得
FROM node:latest
WORKDIR /app
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y python3 && apt-get clean
Debianコンテナをベースイメージにするよりもnodeイメージをベースにした方が後々のコンテナイメージビルドが楽になりますので、nodeイメージにPythonをインストールしてベースイメージを取得しました。続いてディレクトリ構成について紹介します。
├── Prototype
│ └── app/(Nuxt.jsのひな型)
└── build_nuxtimage.yml
前回記事を踏襲していますが、変更点としてはDockerfileがなくなっております。コンテナイメージの作成をbuild_nuxtimage.yml
で作成するので、不要となります。
比較用に前回のDockerfileの中身も載せて置きます。
FROM node:latest
ENV NUXT_HOST=0.0.0.0
ENV NUXT_TELEMETRY_DISABLED=1
WORKDIR /app
COPY ./app/package.json ./app/yarn.lock ./
RUN yarn install
COPY ./app .
CMD ["yarn", "run", "dev"]
これをansible-benderのPlaybookに直しますと次のようになります。
---
- name: Build Nuxt.js image
hosts: all
gather_facts: false
vars:
ansible_python_interpreter: /usr/bin/python3
ansible_bender:
base_image: "localhost/node-python3"
ansible_extra_args: "-vvv"
target_image:
name: yuta28/bender-test
working_dir: /app
environment:
NUXT_HOST: 0.0.0.0
labels:
built-by: '{{ ansible_user }}'
cmd: "yarn run dev"
tasks:
- name: Copy Prototype parts
copy:
src: "{{ item }}"
dest: /app/
with_items:
- "{{ playbook_dir }}/Prototype/app/package.json"
- "{{ playbook_dir }}/Prototype/app/yarn.lock"
- name: Yarn install
command: "yarn install"
- name: Archive app directory
delegate_to: localhost
archive:
path: "{{ playbook_dir }}/Prototype/app"
dest: "{{ playbook_dir }}/Prototype/app.tar.gz"
format: gz
- name: Unpacks app.tar.gz
unarchive:
src: "{{ playbook_dir }}/Prototype/app.tar.gz"
dest: /
Dockerfile内のRUN命令箇所は、commandモジュール、CMD命令はtarget_image内のcmd変数に変換してPlaybookでコンテナのイメージビルドのPlaybookを作成しました。
基本的にはTaskにDockerfileの命令文を記載しておりますが、Nuxt.jsのひな型プロジェクトのコピーはansilbeのcopy/synchronizeで実行しますと、ファイルの量が多すぎるため処理が完了できませんでした。
代替案としてひな型プロジェクトのファイル群をarchiveモジュールで圧縮して、コンテナ内で展開するように変更しております。このPlaybookをansible-benderコマンドで実行します。
ansible-bender build build_nuxtimage.yml
$ ansible-bender build build_nuxtimage.yml
ansible-playbook 2.9.13
config file = /tmp/ab_x4m8plk/ansible.cfg
configured module search path = ['/home/ec2-user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 3.6.8 (default, Dec 5 2019, 15:45:45) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
Using /tmp/ab_x4m8plk/ansible.cfg as config file
host_list declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
script declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
auto declined parsing /tmp/ab_x4m8plk/inventory as it did not pass its verify_file() method
Parsed /tmp/ab_x4m8plk/inventory inventory source with ini plugin
PLAYBOOK: .build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml *********************************************************************************************
1 plays in .build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml
PLAY [Build Nuxt.js image] ***********************************************************************************************************************************
META: ran handlers
TASK [Copy Prototype parts] **********************************************************************************************************************************
task path: /home/ec2-user/ansible-bender/simple-test/.build_nuxtimage-20200913-071938404664-rjqqvxkjpc.yaml:5
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'mount', b'--', b'yuta28-bender-test-20200913-071934769597-cont']
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'( umask 77 && mkdir -p "` echo /tmp `"&& mkdir "` echo /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493 `" && echo ansible-tmp-1599981579.9843893-85539-240769061862493="` echo /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493 `" ) && sleep 0']
Using module file /usr/lib/python3.6/site-packages/ansible/modules/files/stat.py
<yuta28-bender-test-20200913-071934769597-cont> PUT /home/ec2-user/.ansible/tmp/ansible-local-85531c92iy6sw/tmptlan88hf TO /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'chmod u+x /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/ /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py && sleep 0']
<yuta28-bender-test-20200913-071934769597-cont> RUN [b'buildah', b'run', b'--', b'yuta28-bender-test-20200913-071934769597-cont', b'/bin/sh', b'-c', b'/usr/bin/python3 /tmp/ansible-tmp-1599981579.9843893-85539-240769061862493/AnsiballZ_stat.py && sleep 0']
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~省略~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
META: ran handlers
META: ran handlers
PLAY RECAP ***************************************************************************************************************************************************
yuta28-bender-test-20200913-071934769597-cont : ok=4 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Getting image source signatures
Copying blob sha256:b323b70996e4f6d603c331669ac44cf6234a2e22002d3686e9c88398c6911c25
Copying blob sha256:e8847c2734e1bec913fbb00dbd638e9bff6c42f699bbeb897728e234cf1a6e72
Copying blob sha256:a4c504f73441d711e6e71e5c177a772efe4d500c2d97b2a1358ea65edc98e8d5
Copying blob sha256:ef5de533cb53783465669a60fc9b0b1c782d319c5c8991fe9868f3be8be8e58b
Copying blob sha256:cbe6bbd0c86ff46f87950e109e891445a085c9bbf5af737b0ae3871d782e5335
Copying blob sha256:174e334f3f463272eeba0021b8b2c54a8891abc0c74201bbd98e87e8c00524e2
Copying blob sha256:e404bec46f40991019fbf239256326c48afb7672768755740a6ba862d431e5c6
Copying blob sha256:58b4b808347b3cdc40003e905f03059f37ae8cf169e91ecf25250e475e27728f
Copying blob sha256:24a8e30559a7f9f31238761563cc4ab907863039cbc3778449ca8c55f50ecc4a
Copying blob sha256:9b6e6b48454d80e68f9709e8b82abfe7bd0d059464b9c1796d462601ea59182f
Copying blob sha256:9f9869f02922117d69ea1b18239a9d55ac8e6d4ca578fc7ef226d20c3e7424f2
Copying config sha256:ddcc7b1e45f6483f9df7f0d19a17969aa27f92f2e6f77962d3c87c29f32c8186
Writing manifest to image destination
Storing signatures
ddcc7b1e45f6483f9df7f0d19a17969aa27f92f2e6f77962d3c87c29f32c8186
Image 'yuta28/bender-test' was built successfully \o/
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/yuta28/bender-test latest ddcc7b1e45f6 32 minutes ago 1.41 GB
localhost/node-python3 latest 79003b61771b 3 hours ago 990 MB
コンテナイメージlocalhost/yuta28/bender-test
が作成されましたので、コンテナを起動します。
$ podman run --rm -it -p 8080:3000 localhost/yuta28/bender-test:latest
yarn run v1.22.5
$ nuxt
WARN mode option is deprecated. You can safely remove it from nuxt.config 07:59:19
╭────────────────────────────────────────╮
│ │
│ Nuxt.js @ v2.14.5 │
│ │
│ ▸ Environment: development │
│ ▸ Rendering: server-side │
│ ▸ Target: server │
│ │
│ Listening: http://10.0.2.100:3000/ │
│ │
╰────────────────────────────────────────╯
ℹ Preparing project for development 07:59:21
ℹ Initial build may take a while 07:59:21
✔ Builder initialized 07:59:21
✔ Nuxt files generated 07:59:21
✔ Client
Compiled successfully in 8.21s
✔ Server
Compiled successfully in 6.60s
ℹ Waiting for file changes 07:59:30
ℹ Memory usage: 212 MB (RSS: 320 MB) 07:59:30
ℹ Listening on: http://10.0.2.100:3000/
別ターミナル画面からpodman ps
コマンドでコンテナ起動を確認します。
$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fe83f066139c localhost/yuta28/bender-test:latest yarn run dev 12 minutes ago Up 12 minutes ago 0.0.0.0:8080->3000/tcp strange_moore
コンテナが起動でき、ブラウザからもNuxt.jsのサンプルページにアクセスすることが確認できました。
課題
DockerfileからPlaybookへ変更してコンテナイメージビルドを行いましたが、Dockerfileでは出来たのにPlaybookではできなかったことがいくつかありました。
①telemetryによるデータ収集問い合わせの無効化設定を埋め込めない
Dockerfileでは環境変数としてこのような設定を行っていました。
NUXT_TELEMETRY_DISABLED=1
こちらですが、Nuxtの統計情報の収集問い合わせを無視する設定です。デフォルトでは有効化されており、最初にコンテナを起動すると以下のメッセージが出てきます。
yarn run v1.22.5
$ nuxt
ℹ NuxtJS collects completely anonymous data about usage. 11:21:11
This will help us improving Nuxt developer experience over the time.
Read more on https://git.io/nuxt-telemetry
? Are you interested in participation? Yes ← Yes/Noで選択
起動のたびに聞かれるのが煩わしいので設定で無効化しようと、変数をPlaybookに組み込みましたが、以下のエラーが出て失敗しました。
$ ansible-bender build simple-test/build_nuxtimage.yml
There was an error during execution: variable /target_image/environment/NUXT_TELEMETRY_DISABLED is set to 1, which is not of type string
詳細な原因が分からないですが、環境変数がString型でないからエラーになっているかと思われます。NUXT_TELEMETRY_DISABLED
はBoolean型ですが、Boolean型の環境変数をPlaybookに加える方法がわかりませんでした。
こちらの対処法ですが、Nuxt.jsの公式リファレンスで紹介されていた方法でapp/nuxt.config.js
に設定を追記しました。
export default {
~~~~~末尾追加~~~~~
telemetry: false
}
②noneイメージが溜まり続ける
Playbook実行直後にイメージリストを調べると以下のように中間層であるnoneイメージがたくさん溜まってきます。
$ podman images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/yuta28/bender-test latest 3b568629853d 2 hours ago 1.41 GB
<none> <none> 30f38e724bd8 2 hours ago 1.41 GB
<none> <none> 2c3401135802 2 hours ago 1.41 GB
<none> <none> ab36ebfbcb82 2 hours ago 1.41 GB
<none> <none> 0c15be92f176 2 hours ago 992 MB
<none> <none> 0f4f0464e1e9 2 hours ago 992 MB
<none> <none> f19ac9e8da69 2 hours ago 991 MB
localhost/node-python3 latest 73bb42b858aa 5 days ago 991 MB
localhost/debian-python3 buster af956b4f0450 8 days ago 177 MB
サイズも1GBと大きく溜まり続けるとローカルマシンに負担がかかるので作成後に手動でpodman image prune
で削除していますが、Dockerfileのビルド時には出てこなかった事象でPlaybook内でどのような設定を加えたらいいのかわかりませんでした。
所感
上の課題にも挙げられているようにDockerfileからビルドする時と比較しますといくつか問題点が生じ、コンテナイメージのビルドもAnsibleのDockerモジュールから実行した方が体感的には早く感じました。Dockerfileを書く必要がなく、Playbook内だけでコンテナイメージビルドを完結すことができるのはメリットだと思いましたが、やっぱりDockerfileを書いてそこからビルド指定したほうが良い気がしてきました。
そもそもAnsibleでコンテナ管理を行うメリットがあまり思い浮かばず、docker-composeやKubernetesでコンテナ管理を行った方がトレンドにも乗っており、実務で使うには少し心もとない感じがしました。
ansible-benderでコンテナ管理を行うメリットについてわかる方がいましたらコメント欄にてご指摘お願いいたします。