はじめに
Ansible の Execution Environment(EE、Playbookを実行するコンテナイメージ)をビルドするツールとして、ansible-builder
があります。
正直、私はこれまで「Dockerfile / Containerfile を yaml で記述できるちょっとしたラッパーツール」くらいにしか思っていなかったのですが、最近 Ansible 関連のツールならではの機能があることを知りました。
それは、ビルドする定義ファイル execution-environment.yml
には、インストールしたいコレクションも指定できるのですが、ansible-builder は、そのコレクションが依存している Python パッケージや、システムパッケージもセットでインストールしてくれる点です(除外あり)。
既知の方も多いと思いますが、私は最近気が付きました・・。
Ansible Builder combines all the Python requirements files from all collections into a single file
https://ansible.readthedocs.io/projects/builder/en/latest/collection_metadata/#python-dependencies から
Ansible Builder combines system package entries from multiple collections into a single file.
it will install the collection inside the image, read requirements.txt inside of the collection
https://ansible.readthedocs.io/projects/builder/en/stable/usage/#examples から
この記事では、挙動を確認したときのことをまとめます。確認は、ビルドしてできたイメージ内のパッケージのインストール状態を確認するまでとします。
- 検証環境
- ansible-builder: 3.0.0
- Docker: 20.10.25
[2023/12/10 追記] これに関するドキュメントの追記の PR がでていました。
試す定義ファイル
今回試す定義ファイル execution-environment.yml
は以下のとおりです。
--- version: 3 images: base_image: name: registry.redhat.io/ansible-automation-platform-24/ee-minimal-rhel8:latest dependencies: galaxy: collections: - ansible.posix - ansible.utils options: package_manager_path: /usr/bin/microdnf
galaxy
では、ansible.posix
と ansible.utils
コレクションを指定しています。
ansible.posix
コレクションは、依存するシステムパッケージとして bindep.txt
に rsync
が指定されています。ansible.posix.synchronize
が依存していためでしょう。なお、requirements.txt
は空です。
もう一つの ansible.utils
コレクションは、requirements.txt
では、以下の Python パッケージが指定されていました。
- jsonschema
- textfsm
- ttp
- xmltodict
- netaddr
ビルド
今回はベースイメージに registry.redhat.io/ansible-automation-platform-24/ee-minimal-rhel8:latest
を指定しているため、あらかじめログインが必要です。
docker registry.redhat.io
続いて ansible-builder
でビルドします。ビルドの状態が分かるように -v 3
も付けます(以降、タグは仮です)。
ansible-builder build -t ghcr.io/akira6592/ee-dep -v 3
途中以下のようなログが表示されます。
Creating parent directory for /tmp/src/requirements.txt --- python: - 'jsonschema # from collection ansible.utils' - 'textfsm # from collection ansible.utils' - 'ttp # from collection ansible.utils' - 'xmltodict # from collection ansible.utils' - 'netaddr # from collection ansible.utils' system: - 'rsync [platform:redhat] # from collection ansible.posix' - 'gcc-c++ [doc test platform:rpm] # from collection ansible.utils' - 'python3-devel [test platform:rpm] # from collection ansible.utils' - 'python3 [test platform:rpm] # from collection ansible.utils'
定義ファイル内で指定したコレクションが依存している Python パッケージやシステムパッケージが表示されます。# from collection ansible.utils
のように、どのコレクションが依存しているのかがコメントで併記されるのがわかりやすいです。
後述もしますが、システムパッケージのほうは doc
や test
のように何かしらのプロファイルが指定されているパッケージは実際にはインストールされません。
今回は指定していませんが、定義ファイル内の python
や system
で明示的にパッケージを指定した場合は、組み合わせたものが表示されます。明示的に指定した場合は、先コメントの部分は # from collection user
と表示されます。
なお、ビルドすると(正確には ansible-builder create
でも)context/_build/
ディレクトリ配下に requirements.txt
や bindep.txt
が生成されることがありますが、これらは定義ファイル内で明示的に指定したものです。
以下のように、インストールしている様子も見れました。
Installing: rsync-3.1.3-19.el8_7.1.x86_64 ubi-8-baseos-rpms 420.2 kB Transaction Summary: Installing: 1 packages Reinstalling: 0 packages Upgrading: 0 packages Obsoleting: 0 packages Removing: 0 packages Downgrading: 0 packages Downloading packages... Running transaction test... Installing: rsync;3.1.3-19.el8_7.1;x86_64;ubi-8-baseos-rpms Complete. ...(略)... Requirement already satisfied: jsonschema in /usr/lib/python3.9/site-packages (from -r /output/requirements.txt (line 1)) (4.16.0) Collecting textfsm Using cached textfsm-1.1.3-py2.py3-none-any.whl (44 kB) Collecting ttp Using cached ttp-0.9.5-py2.py3-none-any.whl (85 kB) Requirement already satisfied: xmltodict in /usr/local/lib/python3.9/site-packages (from -r /output/requirements.txt (line 4)) (0.12.0) Collecting netaddr Using cached netaddr-0.8.0-py2.py3-none-any.whl (1.9 MB) Requirement already satisfied: attrs>=17.4.0 in /usr/lib/python3.9/site-packages (from jsonschema->-r /output/requirements.txt (line 1)) (21.4.0) Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/lib64/python3.9/site-packages (from jsonschema->-r /output/requirements.txt (line 1)) (0.18.1) Requirement already satisfied: six in /usr/lib/python3.9/site-packages (from textfsm->-r /output/requirements.txt (line 2)) (1.16.0) Requirement already satisfied: future in /usr/lib/python3.9/site-packages (from textfsm->-r /output/requirements.txt (line 2)) (0.18.3) Installing collected packages: textfsm, ttp, netaddr Successfully installed netaddr-0.8.0 textfsm-1.1.3 ttp-0.9.5 ...(略)...
確認
ビルドしたイメージの中を確認します。
システムパッケージの確認
まず、念のためコレクションのインストール状況を確認します。
$ docker run -it ghcr.io/akira6592/ee-dep ansible-galaxy collection list # /usr/share/ansible/collections/ansible_collections Collection Version ------------- ------- ansible.posix 1.5.4 ansible.utils 2.10.3
想定どおりです。今回指定したベースイメージには ansible.builtin
以外にはなかった状態なので、純粋にこの2つが追加された状態です。
Python パッケージの確認
次に Python のパッケージの確認です。
$ docker run -it ghcr.io/akira6592/ee-dep pip3 list Package Version ------------------- -------- ansible-compat 3.0.2 ansible-core 2.15.0 ansible-lint 6.14.3 ansible-runner 2.3.2 ...(略)... jsonschema 4.16.0 # ansible.utils 依存 lockfile 0.12.2 lxml 4.6.5 MarkupSafe 2.1.0 mypy-extensions 0.4.3 ncclient 0.6.10 netaddr 0.8.0 # ansible.utils 依存 ...(略)... textfsm 1.1.3 # ansible.utils 依存 toml 0.10.2 tomli 2.0.1 ttp 0.9.5 # ansible.utils 依存 typing-extensions 3.10.0.2 urllib3 1.25.10 wcmatch 8.3 xmltodict 0.12.0 # ansible.utils 依存 yamllint 1.30.0
ansible.utils
コレクションの requirements.txt
で指定されていたパケージがあることが分かります。
ベースイメージとの比較はこちら(*.before
がベース、*.after
が今回のビルド分)。
$ diff pip.before pip.after 29a30 > netaddr 0.8.0 61a63 > textfsm 1.1.3 63a66 > ttp 0.9.5
diff に表示されない jsonschema
、xmltodict
はベースイメージにもともと入っていたということも分かります。
システムパッケージの確認
続いて、システムパッケージを確認します。
$ docker run -it ghcr.io/akira6592/ee-dep rpm -qa | sort ...(略)... rpm-4.14.3-26.el8.x86_64 rpm-libs-4.14.3-26.el8.x86_64 rsync-3.1.3-19.el8_7.1.x86_64 # ansible.posix 依存 sed-4.5-5.el8.x86_64 setup-2.12.2-9.el8.noarch ...(略)...
ansible.posix
コレクションの bindep.txt
で指定されていた rsync
がることことがわかります。
ベースイメージとの比較はこちら(*.before
がベース、*.after
が今回のビルド分)。
$ diff rpm.before rpm.after 175a176 > rsync-3.1.3-19.el8_7.1.x86_64
なお、ansible.utils
コレクションには bindep.txt
の定義もありますが、test
や doc
プロファイルが指定されます。ansible-builder の仕様としてはプロファイルが指定されていないパッケージがインストール対象)なので、特にインストールされません。
Only requirements with no profiles (runtime requirements) are installed to the image.
ちなみに、ここまでログの貼りやすさから docker run
コマンドを利用していますが、ansible-navigator images
コマンド経由でもインストールされたパッケージは確認できます。
補足
試したり調べたりしたときわかったことを、3点補足します。
注意点: 依存パッケージを読み込んでくれないケース
paloaltonetworks.panos
コレクションをインストールしたときに気が付いたのですが、requiremsnts.txt
が \
で折り返されていると、ansible-builder 側で正しく読み込んでくれないようです。
例: https://github.com/PaloAltoNetworks/pan-os-ansible/blob/v2.17.3/requirements.txt
本事象含めたパース失敗の事象は、ansible-builder 3.0.0 時点では Warning
レベルのですが、Error
レベルに修正する PR も出ています。
また、そもそも、ドキュメントには依存パッケージが明記されているが、requiremsnts.txt
や bindep.txt
がないケースももちろん自動では読み込んでくれません。
requirements.txt
というファイル名について
ここまで、便宜上、 requirements.txt
というファイル名を利用してきましたが、コレクションの meta/execution-environment.yml
の dependencies.python
にファイル名が指定されていてファイルが存在する場合は、そのファイルを読み込む仕様になっています。
たとえば、azure.azcollection
コレクション 1.16.0 には、requirements.txt
というファイル名のファイルがありません。あるのは requirements-azure.txt
です。meta/execution-environment.yml
の dependencies.python
に requirements-azure.txt
と指定されているため、 ansible-builder は requirements-azure.txt
を読んでくれます。
依存パッケージの一覧確認
コレクションが依存している各パッケージは ansible-builder introspect コレクションを束ねるディレクトリ
コマンドで確認できます。すでにコレクションがインストールされている状態が前提です。
たとえば、
~/.ansible/collections └── ansible_collections ├── ansible │ └── utils # ansible.utils コレクションのディレクトリ
上記のようなディレクトリ構成の場合は、以下のように実行します。
実行例:
$ ansible-builder introspect ~/.ansible/collections/ # Dependency data for /Users/sakana/.ansible/collections/ --- python: ansible.eda: - azure-servicebus - aiobotocore - aiohttp - aiokafka - watchdog - systemd-python - dpath ...(略)... system: ansible.netcommon: - gcc-c++ [doc test platform:rpm] - libyaml-devel [test platform:rpm] - libyaml-dev [test platform:dpkg] - python3-devel [test platform:rpm] - python3 [test platform:rpm] - gcc [compile platform:rpm] - libssh-dev [compile platform:dpkg] ...(略)...
簡単なジョブテンプレートの実行
ansible.builtin.debug
モジュールしか使ってないのであまり意味はないですが、今回ビルドして EE で、Automation Controller 4.4 にデフォルトで入っている Demo Job Template
を実行できるところまでは確認しました。
おわりに
ansible-builder で、コレクションが依存しているパッケージをセットでインストールしてくれることを試しました。
当たり前かもしれませんが、ある程度使ったり調べたりしないと、便利さに気づけないものだなと思いました。
あと、公式ドキュメントちゃんと読んでおけば分かっていた話でしたね。