zaki work log

作業ログやら生活ログやらなんやら

[Ansible / AAP / AWX] EEのコンテナイメージ作成にAnsible Builderは必ずしも必要ないかを確認してみた (小ネタ)

AAPやAWXでジョブ実行に必要なExecution Environments(EE)を作るために通常はAnsible Builderを使ってコンテナイメージをビルドするが、要件を満たせばDockerfileを直接書いて自前でビルドしても動くのでは…と思ったので確認してみた。

結論としては、以下が入っていれば最低限動作した。

  • Ansible Core
    • プラス必要なAnsible Collection
  • Ansible Runner
  • SSHクライアント
    • sshpass (パスワード認証の場合)

Ansible BuilderではRHEL系コンテナしか使えない(夏にv3対応したときにいろいろ試したがRHEL系以外はダメだった)が、お試しでDebian系…もいいかと思ったけど、せっかくなのでAnsible利用時にあまり使われず(個人の感想)、イメージサイズがより小さいAlpine Linuxでビルドして確認。

Dockerfile

2024.01.08時点で公開されてるAlpine 3.19.0のイメージをベースにするなら以下の内容でビルドすればOK
(実行確認用の追加パッケージ有)

FROM alpine:3.19.0

RUN apk add ansible-core py3-jmespath py3-pip openssh-client sshpass && \
    ansible-galaxy collection install community.general && \
    pip install ansible-runner --break-system-packages

Alpineのパッケージでansible-coreをインストールすると、Alpine 3.19の場合はcore 2.16.1がインストールされるのでこれを利用。
(ansibleパッケージもあり、こちらを使えばオフィシャルのコレクションは多分すべて入る。pip install ansibleと同等と思われる)

Ansbile Runnerは必須だがAlpineのパッケージでは提供されないため、pipを使用する。その際、venvを使わずシステムに直接インストールしようとするとパッケージ管理の競合対策のためエラーになるが、コンテナを使った限定された環境なので--break-system-packagesオプションを付加する。

SSHクライアントも(自動化で標準的に使用するSSHコネクションプラグインを使用するのであれば)必要。Alpineのコンテナにはデフォルトではsshが無いため、追加インストールしないと下記エラーが発生する。

The command was not found or was not executable: ssh-agent.

また、SSH鍵認証でなく、パスワード認証を使用する場合はsshpassも必要。無いと下記エラーになる。

"to use the 'ssh' connection type with passwords or pkcs11_provider, you must install the sshpass program"

あとは実行例としてjson_queryを試すために、APKパッケージ版jmespathcommunity.generalコレクションを追加している。
使ったplaybookは基本的にこんな感じ
localhost実行のため、これとあとリモートに接続に行く適当なジョブを実行

これでビルドしたイメージをAAP/AWXでそれぞれ実行環境として試したが、ジョブの実行は問題なかった。

イメージサイズ比較

※ これはビルドしただけで動作は未確認

Ansible Builderを使ってrockylinux:9.3-minimalベースに前述Dockerfile同様jmespathとcommunity.generalを入れたイメージサイズと比較。
また、Ansible Coreもpipで入れた場合とも比較。これも若干増えた。

  • apk add版: 127MB
  • pip版: 148MB
  • Ansible Builder版(rockylinux:9.3-minimalベース): 280MB

前述のパッケージ版をpip版に置き換えたこの場合のDockerfileは以下の通り。

FROM alpine:3.19.0

RUN apk add py3-pip openssh-client sshpass && \
    pip install ansible-runner ansible-core==2.16.1 jmespath --break-system-packages && \
    ansible-galaxy collection install community.general

Ansible Builder用execution-environment.ymlファイルは以下の通り。

---
version: 3

dependencies:
  ansible_core:
    package_pip: ansible-core==2.16.1
  ansible_runner:
    package_pip: ansible-runner
  galaxy:
    collections:
      - community.general
  python:
    - jmespath
  system:
    - sshpass
  python_interpreter:
    python_path: /usr/bin/python3.11

images:
  base_image:
    name: docker.io/library/rockylinux:9.3-minimal

options:
  package_manager_path: /usr/bin/microdnf  # required (when use rocky/alma)

additional_build_steps:
  prepend_base:
    - RUN microdnf install python3.11 -y   # for alma/rocky minimal

詳しくは下記参照

zaki-hmkc.hatenablog.com

--break-system-packagesオプション

何をOSのパッケージ管理(apk)で入れて何をPythonのパッケージ管理(pip)で入れるかは、あまりごちゃごちゃさせると文字通り競合するかもしれないので、どちらかに寄せるのが良いと思う。
この辺りは深く検証してないので都度対応かな。

で、運用とかで使える?

自己責任で(ry

公式ドキュメントで「Ansible Builderを使わない場合はこんな感じで~」的な記載を見つけられず表技か裏技かは微妙なことをしてるため、あくまで「動かしたいplaybookがあってそれが動く専用のEEのイメージを用意する」のであれば手段の一つとしてありかもしれない。特に「求めているコンテナイメージの完成形はわかっているのに、Ansible Builder(というかexecution-environment.yml)でどう実装すればわからない場合とか。
あとはAnsible Builderを使うとイメージサイズが大きすぎて困る…みたいなときは良いかもね。

今回はsshとjmespathを追加インストールしてるけど、EEに必要なパッケージ類は実行するplaybookで使用しているモジュール・プラグイン次第なので、必要に応じて追加する。(不足していれば実行時にエラーになるので、メッセージを頼りに不足分を補う地道な作業になるはず。ってこれはAnsible Builderを使っていても変わらないと思う)

あと一つ発見だったのは、Alpineのパッケージ管理はAnsibleインストールできるしバージョンも最新にかなり近いものを追従してるという点。


根本的におかしいとか、こうすればもっといいとか、ここに公式情報あるとかあれば、ぜひ教えてください。