新しい Ansible Builder 3 で Execution Environment を作る

はじめに

先日、Ansible Builder がメジャバージョンアップし、3.0.0 がリリースされました。

Ansible Builder は 本ブログでも過去に取り上げています が、設定ファイルで記述する内容に大きめの変更が入っているため、本エントリで改めて簡単に紹介します。

基本的な考え方

Ansible Builder のコンセプト自体は従来と変わっていないため、設定ファイルを用意してビルド用のコマンドを実行する流れはそのままです(過去のエントリ でも紹介しています)。

一方で、設定ファイルのスキーマのバージョンに新しく 3 が定義され、大きく以下の点が変更されています。

  • 専用のベースイメージが撤廃され、ベースイメージは OS のプレーンなイメージに
  • Python と Ansible のバージョンが指定可能に
  • ビルドのステップの細かなカスタマイズが可能に

今回は、新しいスキーマの実際の設定ファイルを用いて、上記の点を含めた Ansible Builder 3 での設定ファイルの記述内容とビルドの方法を簡単に紹介します。

設定ファイルの準備

実際のファイルは GitHub のリポジトリ にも配置しています。また、指定できる項目の完全な一覧と詳細は、公式のドキュメント で確認できます。

設定ファイル例

Ansible Builder 3 で利用できる、新しいスキーマ(バージョン 3)の設定ファイルの例です。

---
version: 3

images:
  base_image:
    name: quay.io/centos/centos:stream9-minimal

options:
  package_manager_path: /usr/bin/microdnf

dependencies:
  python_interpreter:
    package_system: python3.11
    python_path: /usr/bin/python3.11
  ansible_core:
    package_pip: ansible-core~=2.15
  ansible_runner:
    package_pip: ansible-runner~=2.3
  system: dependencies/bindep.txt
  python: dependencies/requirements.txt
  galaxy: dependencies/requirements.yml

additional_build_files:
  - src: files/ansible.cfg
    dest: configs

additional_build_steps:
  append_base:
    - RUN alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 0
  prepend_galaxy:
    - ADD _build/configs/ansible.cfg ~/.ansible.cfg

以下、上から順に紹介します。

ベースイメージの指定

images で、EE のベースになるイメージを指定します。

images:
  base_image:
    name: quay.io/centos/centos:stream9-minimal

従来の Ansible Builder では専用のベースイメージ(quay.io/ansible/ansible-runner)を使ってビルドする形でしたが、これは撤廃 され、バージョン 3 では RHEL ファミリの OS のプレーンなイメージをそのまま使える ようになっています。

今回の例では、CentOS Stream 9 の Minimal イメージを指定しています。ドキュメント でも一部例示されていますが、他の選択肢として、例えば認証が不要なものでは次のイメージが挙げられます。

  • quay.io/centos/centos:stream9
  • registry.fedoraproject.org/fedora:38
  • registry.access.redhat.com/ubi9/ubi-minimal:9.2docker.io/redhat/ubi9-minimal:9.2

また、ビルドに Podman を利用する場合は、ドキュメント の通り、イメージの署名の検証に関する設定もできます(今回は Docker を使うため設定していません)。

補足: 利用できるベースイメージは現時点では RHEL ファミリのみ

ベースイメージに OS のプレーンなイメージをそのまま使えるようになったとはいえ、現時点では前述の通り あくまで RHEL ファミリの OS に限定 される点は注意が必要です。

技術的には、OS にパッケージを追加するために内部で利用されている bindep は幅広いディストリビューションに対応していますし、後述のようにビルド中に利用するパッケージマネージャのパスもオプションで指定できます。であれば、一見すると RHEL ファミリでない EE(たとえば Ubuntu ベースの EE)も作れそうに思えてしまいますが、現在の実装では、パッケージマネージャに渡す引数がハードコードされていたり、中で ensurepip が使われていたりするため、ビルドは失敗します。

RHEL ファミリ以外のディストリビューションのサポートに対しては メンバの方から慎重な姿勢が提示されており、まずは方針や設計の原則を固めるべきとされています。少なくとも特定のディストリビューションに特化した PR がサクサクとマージされていくようなことはなさそうです。

オプションの指定

options では細かいオプションを指定できます(詳細は ドキュメント で確認できます)。

options:
  package_manager_path: /usr/bin/microdnf

今回は、前述した通りベースイメージに CentOS Stream 9 の Minimal イメージを使うため、ビルドのステップ中で利用されるパッケージマネージャに(デフォルトの dnf ではなく)microdnf を使うよう指定しています。

依存関係の指定

dependencies で、EE に導入するパッケージ群を細かく指定できます。

dependencies:
  python_interpreter:
    package_system: python3.11
    python_path: /usr/bin/python3.11
  ansible_core:
    package_pip: ansible-core~=2.15
  ansible_runner:
    package_pip: ansible-runner~=2.3
  system: dependencies/bindep.txt
  python: dependencies/requirements.txt
  galaxy: dependencies/requirements.yml

従来の Ansible Builder のアーキテクチャでは、Python と Ansible、Ansible Runner のバージョンは、基本的には利用するベースイメージに依存してしまい、カスタマイズの余地が大きくはありませんでした。

バージョン 3 では、python_interpreteransible_coreansible_runner を使ってこれらが指定できるようになっています。今回の例では、Python 3.11、Ansible 2.15、Ansible Runner 2.3 をそれぞれ指定しています。

systempythongalaxy では、従来と同様、導入したい OS パッケージや Python モジュール、Ansible の Collection や Role を指定できます。今回の例では(従来と同様に)別に用意したテキストファイルと YAML ファイルを指定しています(実物は リポジトリ に置いています)が、YAML の Multiline Strings やリストを使ったベタ書きもできるようになっています(ドキュメント に例があります)。

補足: 依存関係は隅々まで明示が必要

従来の Ansible Builder で利用されていた専用のベースイメージは、専用なだけあって、Ansible で必要になりがちな OS パッケージや Python モジュール(sshpasskrb5-develpywinrmparamiko など)はあらかじめバンドルされていました。このため、ユーザは細かな依存関係をあまり気にしなくてもどうにかなる場合が多かった印象があります。

一方でバージョン 3 では、OS のプレーンなイメージをベースに組み立てるようになったことで、逆に言えば 自分のプレイブックの動作に必要なモノは隅から隅まで全部明示しないとダメ になってしまったということでもあります。例えば、今回のように Minimal イメージをベースにした場合、そもそも openssh-clients すら自分で system 下で明示しないと、ターゲットノードへの SSH 接続もできません。

バージョン 3 で EE をビルドする場合、ビルドした EE でいざプレイブックを動かそうとしたときにパッケージやモジュールが足りなくて怒られてしまう可能性は、専用のベースイメージを使った場合よりは高くなりそうです。

なお、従来の専用のベースイメージに導入されていたパッケージ群は、Ansible Runner のリポジトリの過去の断面から確認できる ため、困ったときの足がかりにはできそうです。

追加のファイルの指定

additional_build_files で、ビルドに利用する追加のファイルを指定できます。

additional_build_files:
  - src: files/ansible.cfg
    dest: configs

ここで指定したファイルは、後述の追加のビルドのステップ(additional_build_steps)で参照できるようになります。今回は、ビルドのステップ中で実行される ansible-galaxy コマンドのための ansible.cfg をカスタマイズする想定で記載しています。

少しわかりにくいですが、ここで指定する dest は EE 内のパスではなく、ビルド時にローカルに作成される context/_build ディレクトリ内のパスです。ビルドの過程で必要なファイルをいちど context/_build 下に集約し、集約されたファイルを additional_build_steps 中で利用する考え方です。

追加のビルドのステップの指定

additional_build_steps で、生成される Dockerfile(Containerfile)中のビルドの各フェイズの前後に任意のコマンドを追加できます。

additional_build_steps:
  append_base:
    - RUN alternatives --install /usr/bin/python3 python3 /usr/bin/python3.11 0
  prepend_galaxy:
    - ADD _build/configs/ansible.cfg ~/.ansible.cfg

今回は、python3.11python3 として実行できるようにするための RUN alternatives ... をベースイメージに追加しています(AWX から渡されるインベントリスクリプトにハードコードされている Shebang の関係で、AWX で利用する EE では python3 が必須です)。

また、先述の additional_build_files で指定した ansible.cfg ファイルを、ビルド中の ansible-galaxy による Collection のインストール時に使えるよう、ADD ... を追加しています。パスがややこしいですが、additional_build_filesdestconfigs にしていたため、当該ファイルはビルド時にローカルの context/_build/configs 下にコピーされ、これが additional_build_steps ではビルドのコンテキスト(context)からの相対パス(_build/configs 下)で参照できるようになっています。

補足: ビルドのステップいろいろ

ビルドは、全部で BaseGalaxyBuilderFinal の 4 つのステージで行われます。概略はドキュメント でも触れられていますが、それぞれ以下の処理です。

  • Base
    • 指定された OS イメージに Python と Ansible と Ansible Runner を導入する
    • このステージでできたイメージが、以降の全てのステージのベースイメージとして利用される
  • Galaxy
    • 指定された依存関係に基づいて、Ansible の Collection や Role を所定のパスにインストールする
  • Builder
    • 指定された依存関係に基づいて、必要な OS のパッケージや Python のモジュールを(Collection や Role の依存関係を含め解決し)整理してインストールする
  • Final
    • Galazy ステージと Builder ステージのイメージから必要なファイル群を抽出してインストールし、EE イメージとして仕上げる

additional_build_steps では、これらそれぞれのステージの前(prepend_*)と後(append_*)に任意の処理を追加できます(ドキュメント で一覧されています)。今回は append_baseprepend_galaxy を使っています。

その他の記述内容

version は設定ファイル自体のスキーマのバージョンの指定です。今回指定している 3 が、Ansible Builder 3 で追加された新しいバージョンです。記述がない場合は従来の 1 として扱われます(つまり、従来の設定ファイルも引き続き利用できます)。

version: 3

このほか、紹介したサンプルでは使っていませんが、ビルド時の引数を指定できる build_arg_defaults も用意されています。

ビルド

設定ファイルが用意できたら、付与したいタグとともに build コマンドを実行すると、EE のイメージができあがります。細かい進捗を見るには --verbosity 3 が便利です。

$ ansible-builder build --tag registry.example.com/ansible/ee:2.15-custom --container-runtime docker --verbosity 3
Ansible Builder is generating your execution environment build context.
File context/_build/requirements.yml will be created.
File context/_build/requirements.txt will be created.
File context/_build/bindep.txt will be created.
Creating context/_build/configs
File context/_build/configs/ansible.cfg will be created.
File context/_build/scripts/assemble will be created.
File context/_build/scripts/install-from-bindep will be created.
File context/_build/scripts/introspect.py will be created.
File context/_build/scripts/check_galaxy will be created.
File context/_build/scripts/check_ansible will be created.
File context/_build/scripts/entrypoint will be created.
Ansible Builder is building your execution environment image. Tags: registry.example.com/ansible/ee:2.15-custom
Running command:
  docker build -f context/Dockerfile -t registry.example.com/ansible/ee:2.15-custom context
Sending build context to Docker daemon  50.18kB
Step 1/77 : ARG EE_BASE_IMAGE="quay.io/centos/centos:stream9-minimal"
...
Step 77/77 : CMD ["bash"]
 ---> Running in 2eff2dca84d2
Removing intermediate container 2eff2dca84d2
 ---> d804667597e9
Successfully built d804667597e9
Successfully tagged registry.example.com/ansible/ee:2.15-custom

Complete! The build context can be found at: /home/********/awx-on-k3s/builder/context

ビルドのコンテキストは、./context に生成されています。dependenciesadditional_build_files で指定したファイル群もすべてこの中に保持されます。このディレクトリの中身さえあれば Ansible Builder が無くてもビルドできるため、EE イメージの構成だけを管理したい場合や、CI のパイプラインにビルドを組み込みたい場合にも活用できます。

$ tree context
context
|-- Dockerfile
`-- _build
    |-- bindep.txt
    |-- configs
    |   `-- ansible.cfg
    |-- requirements.txt
    |-- requirements.yml
    `-- scripts
        |-- assemble
        |-- check_ansible
        |-- check_galaxy
        |-- entrypoint
        |-- install-from-bindep
        `-- introspect.py

3 directories, 11 files

Dockerfile からは、各ステージの内容が確認できます。

$ cat context/Dockerfile
ARG EE_BASE_IMAGE="quay.io/centos/centos:stream9-minimal"
...

# Base build stage
FROM $EE_BASE_IMAGE as base
...

# Galaxy build stage
FROM base as galaxy
...

# Builder build stage
FROM base as builder
...

# Final build stage
FROM base as final
...

補足: コンテキストの生成だけを行いたい場合

イメージのビルドは行わずにコンテキストの生成だけを行いたい場合は、create コマンドを利用できます。

$ ansible-builder create --verbosity 3
Ansible Builder is generating your execution environment build context.
File context/_build/requirements.yml will be created.
File context/_build/requirements.txt will be created.
File context/_build/bindep.txt will be created.
Creating context/_build/configs
File context/_build/configs/ansible.cfg will be created.
File context/_build/scripts/assemble will be created.
File context/_build/scripts/install-from-bindep will be created.
File context/_build/scripts/introspect.py will be created.
File context/_build/scripts/check_galaxy will be created.
File context/_build/scripts/check_ansible will be created.
File context/_build/scripts/entrypoint will be created.
Complete! The build context can be found at: /home/********/awx-on-k3s/builder/context

まとめ

Ansible Builder 3 の設定ファイルの内容と使い方を簡単に紹介しました。

専用のベースイメージが不要になってカスタマイズ範囲が広がったことはメリットですが、悪く言えば、特に依存関係まわりなどユーザが明示的に指定しなければならない範囲も同様に広がっているため、苦労が増えてしまう面もありそうです。

@kurokobo

くろいです。ギターアンサンブルやら音響やらがフィールドの IT やさんなアルトギター弾き。たまこう 48 期ぎたさん、SFC '07 おんぞう、新日本ギターアンサンブル、Rubinetto。今は野良気味。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です