てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible/AAP] コンテナでデプロイする AAP「Containerized AAP」を試して仕組みを少し調べた(AAP 2.4 時点の Technical Preview)

はじめに

Automation Automates 2023 Japan での AAP のロードマップの話の中で、「Containerized AAP」という言葉がありました。その後、AAP 2.4 内で「Technical Preview」という扱いで提供が始まりました。

どんな感じか気になりつつ、試せていなかったので試してみました。

デプロイそのもののほか、postinstall 処理(ライセンス自動適用、プロジェクトの設定投入)も試ました。インストール処理の中身や、自動起動、ポート開放などの仕組みにいて気になったこともあったため、ついでに調査しました。

手順については、公式ドキュメントや、先人のブログを参考にさせていただきました。ありがとうございます!

なお、将来的に Containerized AAP が GA になった場合、現在から大小さまざまな変更が入ると思います。本記事はあくまでも AAP 2.4 時点で Technical Preview のものを Technical Preview として扱い、一時的な環境で試してみるだけです。なので、GA になったらあまり意味がない内容になります。

まとめ

長いので先にポイントをまとておきます。

  • podman でデプロイする方式、ルートレス
  • デプロイ後にライセンスの適用や設定投入もできる
  • 各コンテナはユーザーレベルの systemd 経由で起動

■ 環境・要件

今回は以下の環境、要件です。

  • 環境
    • RHEL 9.4 (minimal)
    • サブスクリプション適用済み
    • ホスト名設定済み
    • パスワード入力で sudo できる非 root ユーザーを利用(今回は admin
    • podman 4.9.4-rhel (インストール Playbook 実行中にインストールされる)
    • オンライン版インストーラー(バンドル版ではないほう)
      • ansible-automation-platform-containerized-setup-bundle-2.4-2-x86_64.tar.gz
      • 最終更新日は 2024-01-16
    • 主なコレクション(インストーラーに同梱)
      • ansible.containerized_installer 1.3.3
      • ansible.controller 4.5.0
      • infra.controller_configuration 2.6.0
  • 要件
    • Autmation Controller のみデプロイ(実際は Automation Hub や EDA Controller もデプロイ可能)
      • 作業マシン自身にデプロイ
    • ライセンス適用も自動化
    • Automation Controller の事後設定も自動化(postinstall)

■ インストール手順

私の環境、要件でインストールした手順です。

準備

パッケージを一通りアップデートします。

$ sudo dnf update '*' -y
...(略)...
$ cat /etc/redhat-release 
Red Hat Enterprise Linux release 9.4 (Plow)

リポジトリのリストを表示し、ドキュメントに記載の appstreambaseos があることを確認します。

$ dnf repolist
Not root, Subscription Management repositories not updated
repo id                                                     repo name
rhel-9-for-x86_64-appstream-rpms                            Red Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)
rhel-9-for-x86_64-baseos-rpms                               Red Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)

デプロイ対象マシンのホスト名を名前解決可能な状態にしておきます。

今回は今作業している(インストーラーを実行する)マシン自身をデプロイ対象としますので、作業マシンのホスト名 rhel9-aap24c192.168.1.139 で名前解決できるようにしました。

何が起こるか見たかったこともあり、ドキュメントとは異なり /etc/hosts で設定しました。あくまで検証目的であり、公式ドキュメントに載っている方法ではありません。

ansible-core のインストール

イントールに必要な ansible-core などをインストールします。

$ sudo dnf install -y ansible-core wget git rsync
...()...
Complete!

これまであった、VMRPM でインストールする方式では、インストールスクリプトinsstall.sh の処理の中で、(なければ)ansible がインストールされ、具体的な処理が書かれた Playbook を実行するという流れでした。

一方で、Containerized AAP の場合は、Playbook を直接実行するかたちなので予め ansible-core のインストールが必要です。

他に指定されている wgetgit などは、Playbook が依存しているからなのだと思います。git でいうと、postinstall のための定義ファイルを git clone する時に使うようです。

なお、ここまで作業しても podman はインストールされていません。

$ podman
bash: podman: command not found
$ rpm -qa | grep podman
$ 

インストーラーのダウンロード

ダウンロードページ(要ログイン)にブラウザでアクセスして、Tech Preview: Ansible Automation Platform 2.4 Containerized Setup をダウンロードします。

今回はバンドル版を利用しないので、末尾に Bundle が付かないほうです。最終更新日は 2024-01-16 となっていました。

ダウンロードした ansible-automation-platform-containerized-setup-2.4-2.tar.gz を作業マシンにコピーしておきます。

作業マシンで解凍して、作成されたディレクトリに移動します。

$ tar xzf ansible-automation-platform-containerized-setup-2.4-2.tar.gz 
$ cd ansible-automation-platform-containerized-setup-2.4-2

解凍した直下のファイル、ディレクトリは以下のとおりです。

ファイル・ディレクトリ名 説明
collections ディレクト インストーラーに同梱しているコレクションの親ディレクトリ。イントール用の Playbook がこの配下の ansible.containerized_installer コレクション内にある。後述の ansible.cfgcollections_path がこのディレクトリを指している。
ansible.cfg collections_path 等の設定
inventory インストール上のホスト、設定の定義
README.md インストール上の設定の変数の説明

inventory (インストール設定ファイル)の編集

これまでと同様、インストール上のさまざまな設定を inventory ファイルに指定します。普段と同じように、パスワード類は暗号化するなどしてセキュリティを高めることもできます。

rhel9-aap24c は作業マシン兼インストール先マシンです。

[automationcontroller]
# Aumation Controller のデプロイ先を指定
# 実際は作業マシン自身
# https の待ち受けポートを 443 に指定(デフォルト8443)
rhel9-aap24c ansible_connection=local nginx_https_port=443

[database]
# DB も同じホストのコンテナとしてデプロイする
rhel9-aap24c ansible_connection=local

[all:vars]
# DB の認証情報
postgresql_admin_username=postgres
postgresql_admin_password=<DBパスワード>

# オンライン版インストーラーの場合 registry.redhat.io からイメージを pull するので必要な認証情報を指定
registry_username=<Red Hat アカウントのユーザー名>
registry_password=<Red Hat アカウントのパスワード>

# Automation Controller の Web UI admin パスワード
controller_admin_password=<Automation Controller adminパスワード>

# Automation Controller から DB への接続情報
controller_pg_host=rhel9-aap24c
controller_pg_password=<DBパスワード>

# デプロイ後に設定流し込み処理(postinstall)をする
# postinstall の有効化(デフォルトは無効)
controller_postinstall=true
# マニフェストファイルのパス
controller_license_file=/home/admin/cac/manifest_sakana-trial-5nodes_20240913T050813Z.zip
# 設定流し込みに利用する定義ファイルを格納したディレクトリ
controller_postinstall_dir=/home/admin/cac

# 状況確認感覚のチューニング(トラブルシューティングで後述)
controller_postinstall_async_delay=2

automationedaautomationhub グループはグループ定義自体をしない形にしてみました。この影響で、後述の Playbook 実行時に警告が表示されます。気になる場合は、グループに定義は残しつつ所属ホストなしにするとよいと思います。

README.md にさまざまな変数の説明があります。上記の inventory で利用している変数のうち、いくつか以下で説明します。

デプロイ処理関連

Automation Controller の https の待ち受けポートとして nginx_https_port 変数で 443 を指定しています。これは、妥当性はさておき、一般ユーザーでデプロイしたらどうなるんだろうという好奇心で試したものです。実際はこれでいけました。インストール処理の中でカーネルパラメーター net.ipv4.ip_unprivileged_port_start が調整されるためです。

postintall 関連の設定

controller_postinstalltrue に指定して、postinstall(デプロイ後の設定流し込み)機能を有効化していました。

controller_license_file は適用したいマニフェストファイルのパスです。今回はトライアルライセンスから作成しました。試した限りマニフェストファイルの適用だけであれば controller_postinstall はデフォルトの false のままでも大丈夫でした。一方、controller_postinstalltrue とした場合は、controller_license_file の指定がセットで必要になります。

設定に利用する変数ファイル群が git 上にある場合は、hub_postinstall_repo_url で指定します。

今回は、変数ファイルを作業マシンに直接配置したので、controller_postinstall_dir のみの指定です。ここで指定したディレクトリ配下にある *.yml*.yaml ファイルを一式読み込みます。拡張子以外のファイル名は何でもよいです。今回は、controller.yml というファイル名で以下の内容のモノを作成して、controller_postinstall_dir で指定したディレクトリ配下に置きました。

---
controller_projects:
 - name: My Project
   organization: Default
   scm_type: git
   scm_url: https://github.com/akira6592/tower-sample-nw
   scm_branch: main
   scm_delete_on_update: false
   scm_update_on_launch: true
   scm_clean: true

今回はとにかく動くことを確認したかったので、プロジェクトを1つ作成するのみとしました。postinstall の機能自体は非常に興味深いので別途深掘りしたいと思います。

なお、この設定流し込みには infra.controller_configuration.dipatch ロールが利用されます。変数ファイルの書きっぷりは以下のページが参考になります。

インストール Playbook の実行

$ ansible-playbook -i inventory ansible.containerized_installer.install -K
BECOME password: (作業ユーザーのパスワードを入力)

(オプション -K でbecomeパスワードを対話的に入力するの手間な時は ansible_become_password を指定するなど)

8分位で終わりました。aap_install.log にログが記録さます。

なお、Playbook の指定はカレントディレクトリから見たファイル名ではなく、ansible.containerized_installer コレクション内の Playbook install を指しています。ansible.containerized_installer コレクションはインストーラーに同梱されていいて、Playbook の実体は <解凍ディレクトリ>/collections/ansible_collections/ansible/containerized_installer/playbooks/install.yml です。

ansible.cfg で以下のように collections_path が指定されているため、 ansible.containerized_installer コレクションを認識できるようになっています。

[defaults]
collections_path = ./collections
inventory = ./inventory
log_path = ./aap_install.log

Playbook のファイル名の補完ができなくて少し不便ですが、ansible-core 2.11 からこのようにコレクション内の Playbook を呼べるようになっています。

なお、2023年月時点の公式ブログでは、export ANSIBLE_COLLECTIONS_PATH=/full-path-to-installer/collections でコレクションがあるパスを指定していますが、上記の ansible.cfgansible-playbook コマンドを実行する分には export 不要です。

動作確認

無事にジョブテンプレートが実行できました。

ジョブの実行

Automation Controller のバージョンは、4.5.11 でした。ここは変動するかもしれません。

Automation Controller 4.5.11

postinstall の処理で指定したプロジェクト「My Project」も追加されて、同期も成功していました。

プロジェクトが追加された

■ インストール時のトラブルシューティング

本記事の手順はあたかも最初からうまくいったように書きましたが、実際は試行錯誤がありました。その中で出会った事象や対処などをまとめます。

あくまで今回利用したバージョンですので、今後のバージョンでは再現性がないかもしれません。

トラシュー1: ジョブテンプレートを実行しても「保留中」のままになる

インストールの Playbook が正常に終了した後、試しに Dome Job Template を実行すると「保留中」のまま先に進まないことがありました。

他にも、インストール Playbook を実行中、postinstall の処理にジョブが起動する処理(プロジェクトの設定など)があると、そのジョブが保留中のままタイムアウトとなり、タスク infra.controller_configuration.projects : Managing Projects | Wait for finish the projects management でエラーになることがありました。

原因: インベントリで localhost を指定していたため

複数のケースが考えられますが、今回の場合は、EE を実行するための receptor コンテナが起動していなかったためでした。

インストール Playbook 実行後の podman ps の結果は以下のとおり receptorautomation-controller-task がありませんでした。

$ podman ps
CONTAINER ID  IMAGE                                                                      COMMAND               CREATED        STATUS             PORTS       NAMES
f728f9c17261  registry.redhat.io/rhel8/postgresql-13:latest                              run-postgresql        6 minutes ago  Up 5 minutes                   postgresql
54a15d3dfdd7  registry.redhat.io/rhel8/redis-6:latest                                    run-redis             5 minutes ago  Up 5 minutes                   redis
f7e9f4709730  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest  /usr/bin/launch_a...  4 minutes ago  Up About a minute              automation-controller-rsyslog
f0b5d5f93ae5  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest  /usr/bin/launch_a...  4 minutes ago  Up About a minute              automation-controller-web

podman ps -a で調べてみると receptorautomation-controller-task はそれぞれ終了していました。

$ podman ps -a
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED        STATUS                    PORTS       NAMES
f728f9c17261  registry.redhat.io/rhel8/postgresql-13:latest                                run-postgresql        8 minutes ago  Up 8 minutes                          postgresql
54a15d3dfdd7  registry.redhat.io/rhel8/redis-6:latest                                      run-redis             8 minutes ago  Up 8 minutes                          redis
12b94e181d9b  registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel8:latest  /usr/bin/receptor...  7 minutes ago  Exited (1) 7 minutes ago              receptor
f7e9f4709730  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  7 minutes ago  Up 4 minutes                          automation-controller-rsyslog
12dbc9d8db3f  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  7 minutes ago  Exited (0) 3 minutes ago              automation-controller-task
f0b5d5f93ae5  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  7 minutes ago  Up 3 minutes                          automation-controller-web

で、まず receptor がなんで異常終了したんだろうと、podman logs receptor でログを確認したら Error: node ID "localhost" is reserved とありました。

$ podman logs receptor
Error: node ID "localhost" is reserved

どうやら、プログラムとしての receptor の処理として「localhost は予約されているため、node の id に指定できない」ということのようでした。

遡ってみると、試しに inventoryautomationcontroller グループのホストに localhost を指定したときがありました。この localhost という値が巡り巡って ansible.containerized_installer.receptor ロール内のテンプレート receptor.conf.j2 で、nodeid として利用され、先述のエラーとなっていたようです。

# roles/receptor/templates/receptor.conf.j2
---
- node:
    id: {{ _receptor_hostname }}
# ...(略)...

もう一つのコンテナ、podman logs automation-controller-task のほうは、詳細を追えませんでしたが、おそらく receptor のエラーとも関係があるのだと思います。

エラー抜粋

$ podman logs automation-controller-task
...(略)...
Traceback (most recent call last):
  File "/usr/bin/awx-manage", line 8, in <module>
    sys.exit(manage())
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/__init__.py", line 175, in manage
    execute_from_command_line(sys.argv)
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/django/core/management/__init__.py", line 442, in execute_from_command_line
    utility.execute()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/django/core/management/__init__.py", line 436, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/django/core/management/base.py", line 412, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/django/core/management/base.py", line 458, in execute
    output = self.handle(*args, **options)
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/management/commands/run_dispatcher.py", line 68, in handle
    consumer.run()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/dispatch/worker/base.py", line 236, in run
    self.worker.on_start()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/dispatch/worker/task.py", line 141, in on_start
    dispatch_startup()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/system.py", line 120, in dispatch_startup
    cluster_node_heartbeat()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/system.py", line 578, in cluster_node_heartbeat
    inspect_execution_and_hop_nodes(instance_list)
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/system.py", line 517, in inspect_execution_and_hop_nodes
    mesh_status = ctl.simple_command('status')
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/receptorctl/socket_interface.py", line 81, in simple_command
    self.connect()
  File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/receptorctl/socket_interface.py", line 99, in connect
    raise ValueError(f"Socket path does not exist: {path}")
ValueError: Socket path does not exist: /run/receptor/receptor.sock
...(略)...

対処: localhost 以外を指定

もともとちょっと意地悪感覚で指定した inventoryautomationcontroller グループのホストに localhost を、実際のホスト名(名前解決可)に変更して再度インストール Playbook を実行しました。

・・一筋縄ではいかず以下のエラーになりました。変なタイミングでホスト名を変更したため、整合性が取れなくなったのだと思います。

TASK [ansible.containerized_installer.automationcontroller : Wait for the Controller API to te ready] ***
fatal: [rhel9-aap24c]: FAILED! => {"changed": false, "elapsed": 0, "msg": "Status code was -1 and not [200]: Request failed: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'rhel9-aap24c'. (_ssl.c:1129)>", "redirected": false, "status": -1, "url": "https://rhel9-aap24c:443/api/v2/ping/"}

詳細を調べる気力がなかったので、一度アンインストール Playbook を実行してから、インストール Playbook を実行しました。

完了の podman ps は以下のとおりです。

$ podman ps 
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED        STATUS         PORTS       NAMES
1bdb7ba2d638  registry.redhat.io/rhel8/postgresql-13:latest                                run-postgresql        4 minutes ago  Up 4 minutes               postgresql
5db357812714  registry.redhat.io/rhel8/redis-6:latest                                      run-redis             4 minutes ago  Up 4 minutes               redis
2c9dfbbeb62b  registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel8:latest  /usr/bin/receptor...  4 minutes ago  Up 4 minutes               receptor
3beee138c0e6  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  3 minutes ago  Up 34 seconds              automation-controller-rsyslog
fe2516aff573  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  3 minutes ago  Up 31 seconds              automation-controller-task
15133bf168e8  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  3 minutes ago  Up 20 seconds              automation-controller-web

receptorautomation-controller-task も起動しました。

これでジョブが正常に実行できるようになりました。postinstall でプロジェクトの設定をするようにしている場合も、無事に終了するようになりました。

トラシュー2: プロジェクトの設定がタイムアウトエラー

今回は postinstall の処理で、プロジェクト設定の流し込みを含めていますが、以下のエラーになることがありました。

TASK [infra.controller_configuration.projects : Managing Projects | Wait for finish the projects management] ************************************
FAILED - RETRYING: [rhel9-aap24c]: Managing Projects | Wait for finish the projects management (30 retries left).
FAILED - RETRYING: [rhel9-aap24c]: Managing Projects | Wait for finish the projects management (29 retries left).
FAILED - RETRYING: [rhel9-aap24c]: Managing Projects | Wait for finish the projects management (28 retries left).
...(略)...
FAILED - RETRYING: [rhel9-aap24c]: Managing Projects | Wait for finish the projects management (2 retries left).
FAILED - RETRYING: [rhel9-aap24c]: Managing Projects | Wait for finish the projects management (1 retries left).
failed: [rhel9-aap24c] (item=Create/Update Project My Project | Wait for finish the project creation) => {"__projects_job_async_results_item": {"__controller_project_item": {"name": "My Project", "organization": "Default", "scm_branch": "main", "scm_clean": true, "scm_delete_on_update": false, "scm_type": "git", "scm_update_on_launch": true, "scm_url": "https://github.com/akira6592/tower-sample-nw"}, "ansible_job_id": "j210680799387.309524", "ansible_loop_var": "__controller_project_item", "changed": false, "failed": 0, "finished": 0, "results_file": "/home/admin/.ansible_async/j210680799387.309524", "started": 1}, "ansible_job_id": "j210680799387.309524", "ansible_loop_var": "__projects_job_async_results_item", "attempts": 30, "changed": false, "finished": 0, "results_file": "/home/admin/.ansible_async/j210680799387.309524", "started": 1, "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}

あれれと思って、Automation Controller の GUI にログインして確認すると、プロジェクトは正常に設定されていた、という状況でした。

原因: プロジェクト同期処理が間に合わなかった

設定の流し込みには、infra.controller_configuration.dipatch ロールが利用されます。この際、非同期で処理します。デフォルトでは 1秒間隔で状況確認して、30回リトライして処理が完了しなければエラーになります。

何度かインストールを試していると、デフォルトではうまくいったりいかなかったりしました。

プロジェクトについては、ただ設定するだけなく、設定直後に同期処理(git clone)が実行されるので、他の設定項目よりは時間がかかる傾向があるかもしれません。たまたまプロジェクトで試して出会えてよかったです。

なお、前述の「トラシュー1: ジョブテンプレートを実行しても「保留中」のままになる」の原因の一つである、コンテナ receptor がない場合もこの事象が発生します。この場合は、プロジェクト同期処理に必要なコンテナがないことになりますので、インストールを何回実行しても毎回タイムアウトになります。

対処: チューニング

コンテナ receptor があるのにタイムアウトになっている場合は、状況確認の間隔やリトライ回数を調整します。

inventory 内の以下の変数で調整できます。

変数名 デフォルト値 説明
controller_postinstall_async_delay 1 状態確認の間隔(秒)
controller_postinstall_async_retries 30 リトライ回数

公式ドキュメントにも本件についての記載があります。変数名が controller_configuration_async_* なので微妙に違いますが挙動としては同じようです。README.md に載ってる変数名だと controller_postinstall_async_* です。

今回は、controller_postinstall_async_delay2 に指定して、再度インストール Playbook を実行しました。

トラシュー3: 接続確認タスク Wait for the Web port to be reachable でエラーになる

一度インストールが完了した後、変数 nginx_https_port で nginx の listen ポートを変更し、再度 Playbook を実行すると、Automation Controller へのライセンス投入前の接続確認で、以下のエラーになってしまいました。

TASK [ansible.containerized_installer.automationcontroller : Wait for the Web port to be reachable] **************************
fatal: [rhel9-aap24c]: FAILED! => {"changed": false, "elapsed": 300, "msg": "Timeout when waiting for 127.0.0.1:443"}

処理の中身としては、ansible.containerized_installer.automationcontroller ロール内のタスクファイル license.yml にあるタスクで、ansible.builtin.wait モジュールが使用されています。

なお、このタスクは controller_license_file が定義されているときだけ実行されます。そのため、マニフェストファイルを指定していない場合はこのエラーは発生しません。

原因: listen ポートの変更が反映されないため

変数 nginx_https_port の値で nginx の設定ファイルを変更した後、コンテナ automation-controller-web を再起動していないためのようです。

以下詳細です。

ansible.containerized_installer.automationcontroller ロール内の containers.yml にあるタスク Create the automation controller web container で nginx の設定ファイルを生成します。そのタスクに notify: Restart controller web 指定されています。

ハンドラー Restart controller web では、ansible.builtin.systemd モジュールを利用して、サービス automation-controller-web.service を再起動します。結果的にコンテナ automation-controller-web が再起動されて、変更された nginx の設定ファイルも反映されます。

ここだけ見るとうまくいくように見えますが、再起動のハンドラーが起動する前に、接続確認のタスクがあるため、listen ポート変更すると正常に接続確認できなくなってしまいます。

一通りタスクが終わった後に、ハンドラーを起動する」という順番の仕様が考慮されていないように見えます。

対処: 一度アンインストール(暫定)

少々大げさですが、一度アンインストールしてから、再度インストールしました。

$ ansible-playbook -i inventory ansible.containerized_installer.uninstall -K
...(略)...
$ ansible-playbook -i inventory ansible.containerized_installer.install -K
...(略)...

他の方法として、接続確認のタスク Wait for the Web port to be reachable の実行中に、手動でサービス automation-controller-web.service を再起動する方法も考えらますが、タイミング勝負のため少々アクション要素があります。

なお、この事象はあくまで今回検証した ansible.containerized_installer コレクション 1.3.3 での事象のため、今後修正されるかもしれません。

その他: アンインストールしてもカーネルパラメーターの変更が残る

トラブルシューティングではないですが、気が付いたことが一点。

インストーラーが、カーネルパラメーター net.ipv4.ip_unprivileged_port_start を調整する際 /etc/sysctl.conf に、

net.ipv4.ip_unprivileged_port_start=443

のように記載されますが、アンインストールの Playbook を実行しても残ります。インストール前の値がどうだったか保存しておく術がないので、しょうがないのかなと思います。

もしかしたら他にもアンインストールで、設定が残るものもあるかもしれません。

■ 調べたこと

インストール処理の中身や、自動起動、ポート開放で気になったことをいくつか調べたので、まとめておきます。

全体

podman ps の結果は以下の通りです。概ねコンテナ名で役割がわかりそうです。

$ podman ps
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED      STATUS      PORTS       NAMES
3910331f6865  registry.redhat.io/rhel8/postgresql-13:latest                                run-postgresql        4 hours ago  Up 4 hours              postgresql
86e602e1c6e4  registry.redhat.io/rhel8/redis-6:latest                                      run-redis             4 hours ago  Up 4 hours              redis
71b5bad7d7f1  registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel8:latest  /usr/bin/receptor...  4 hours ago  Up 4 hours              receptor
84df241d5ae3  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  4 hours ago  Up 4 hours              automation-controller-rsyslog
7ffa833dd597  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  4 hours ago  Up 4 hours              automation-controller-task
344e8869af0c  registry.redhat.io/ansible-automation-platform-24/controller-rhel8:latest    /usr/bin/launch_a...  4 hours ago  Up 4 hours              automation-controller-web

後で再度触れますが PORTS 欄は空欄です。

podman info

インストールユーザー(非root)での podman info の結果は以下のとおりです。

▼クリックして展開(長いので)

$ podman info
host:
  arch: amd64
  buildahVersion: 1.33.8
  cgroupControllers:
  - memory
  - pids
  cgroupManager: systemd
  cgroupVersion: v2
  conmon:
    package: conmon-2.1.10-1.el9.x86_64
    path: /usr/bin/conmon
    version: 'conmon version 2.1.10, commit: fb8c4bf50dbc044a338137871b096eea8041a1fa'
  cpuUtilization:
    idlePercent: 99.19
    systemPercent: 0.23
    userPercent: 0.58
  cpus: 4
  databaseBackend: sqlite
  distribution:
    distribution: rhel
    version: "9.4"
  eventLogger: journald
  freeLocks: 2034
  hostname: rhel9-aap24c
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
  kernel: 5.14.0-427.35.1.el9_4.x86_64
  linkmode: dynamic
  logDriver: journald
  memFree: 144547840
  memTotal: 3836272640
  networkBackend: netavark
  networkBackendInfo:
    backend: netavark
    dns:
      package: aardvark-dns-1.10.0-3.el9_4.x86_64
      path: /usr/libexec/podman/aardvark-dns
      version: aardvark-dns 1.10.0
    package: netavark-1.10.3-1.el9.x86_64
    path: /usr/libexec/podman/netavark
    version: netavark 1.10.3
  ociRuntime:
    name: crun
    package: crun-1.14.3-1.el9.x86_64
    path: /usr/bin/crun
    version: |-
      crun version 1.14.3
      commit: 1961d211ba98f532ea52d2e80f4c20359f241a98
      rundir: /run/user/1000/crun
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
  os: linux
  pasta:
    executable: ""
    package: ""
    version: ""
  remoteSocket:
    exists: true
    path: /run/user/1000/podman/podman.sock
  security:
    apparmorEnabled: false
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: true
    seccompEnabled: true
    seccompProfilePath: /usr/share/containers/seccomp.json
    selinuxEnabled: true
  serviceIsRemote: false
  slirp4netns:
    executable: /usr/bin/slirp4netns
    package: slirp4netns-1.2.3-1.el9.x86_64
    version: |-
      slirp4netns version 1.2.3
      commit: c22fde291bb35b354e6ca44d13be181c76a0a432
      libslirp: 4.4.0
      SLIRP_CONFIG_VERSION_MAX: 3
      libseccomp: 2.5.2
  swapFree: 4111724544
  swapTotal: 4227854336
  uptime: 16h 38m 46.00s (Approximately 0.67 days)
  variant: ""
plugins:
  authorization: null
  log:
  - k8s-file
  - none
  - passthrough
  - journald
  network:
  - bridge
  - macvlan
  - ipvlan
  volume:
  - local
registries:
  search:
  - registry.access.redhat.com
  - registry.redhat.io
  - docker.io
store:
  configFile: /home/admin/.config/containers/storage.conf
  containerStore:
    number: 6
    paused: 0
    running: 6
    stopped: 0
  graphDriverName: overlay
  graphOptions: {}
  graphRoot: /home/admin/.local/share/containers/storage
  graphRootAllocated: 26164068352
  graphRootUsed: 8558268416
  graphStatus:
    Backing Filesystem: xfs
    Native Overlay Diff: "true"
    Supports d_type: "true"
    Supports shifting: "false"
    Supports volatile: "true"
    Using metacopy: "false"
  imageCopyTmpDir: /var/tmp
  imageStore:
    number: 4
  runRoot: /run/user/1000/containers
  transientStore: false
  volumePath: /home/admin/.local/share/containers/storage/volumes
version:
  APIVersion: 4.9.4-rhel
  Built: 1723107101
  BuiltTime: Thu Aug  8 17:51:41 2024
  GitCommit: ""
  GoVersion: go1.21.11 (Red Hat 1.21.11-1.el9_4)
  Os: linux
  OsArch: linux/amd64
  Version: 4.9.4-rhel

systemd 連携の概要

podman は systemd との連携機能があり、Conteinerized AAP の各コンテナは systemd 経由で起動、停止するようになっています。

インストールユーザー(非root)でユニットファイルが作成されることが特徴です。~/.config/systemd/user/ ディレクトリ配下に、各コンテナに対応するユニットファイルがあります。

$ ls -l  ~/.config/systemd/user/
total 28
-rw-r--r--. 1 admin admin  864 Sep 24 12:40 automation-controller-rsyslog.service
-rw-r--r--. 1 admin admin  849 Sep 24 12:40 automation-controller-task.service
-rw-r--r--. 1 admin admin  844 Sep 24 12:40 automation-controller-web.service
drwxr-xr-x. 2 admin admin 4096 Sep 24 12:43 default.target.wants
drwxrwx---. 2 admin admin   27 Sep 24 12:37 podman.service.d
-rw-r--r--. 1 admin admin  698 Sep 24 12:39 postgresql.service
-rw-r--r--. 1 admin admin  688 Sep 24 12:40 receptor.service
-rw-r--r--. 1 admin admin  673 Sep 24 12:39 redis.service
drwxr-xr-x. 2 admin admin   27 Sep 24 12:37 sockets.target.wants

systemctl コマンドで操作する場合は --user オプションが必要です。

systemctl コマンド使用例1:

$ systemctl list-unit-files -t service --user
UNIT FILE                             STATE    PRESET  
automation-controller-rsyslog.service enabled  disabled
automation-controller-task.service    enabled  disabled
automation-controller-web.service     enabled  disabled
dbus-broker.service                   enabled  enabled 
dbus.service                          alias    -       
dirmngr.service                       static   -       
gpg-agent.service                     static   -       
grub-boot-success.service             static   -       
podman-auto-update.service            disabled disabled
podman-kube@.service                  disabled disabled
podman-restart.service                disabled disabled
podman.service                        disabled disabled
postgresql.service                    enabled  disabled
receptor.service                      enabled  disabled
redis.service                         enabled  disabled
ssh-agent.service                     static   -       
systemd-exit.service                  static   -       
systemd-tmpfiles-clean.service        static   -       
systemd-tmpfiles-setup.service        enabled  enabled 

19 unit files listed.

systemctl コマンド使用例2:

$ systemctl status automation-controller-web.service --user
● automation-controller-web.service - Podman automation-controller-web.service
     Loaded: loaded (/home/admin/.config/systemd/user/automation-controller-web.service; enabled; preset: disabled)
     Active: active (running) since Tue 2024-09-24 12:43:57 JST; 4h 58min ago
       Docs: man:podman-generate-systemd(1)
    Process: 27457 ExecStart=/usr/bin/podman start automation-controller-web (code=exited, status=0/SUCCESS)
   Main PID: 27469 (conmon)
      Tasks: 1 (limit: 23160)
     Memory: 756.0K
        CPU: 75ms
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/automation-controller-web.service
             └─27469 /usr/bin/conmon --api-version 1 -c 344e8869af0c02b02b2f72033143527167153164ad6adc548e675c4fcfa2995f -u 344e8869af0c02b02b2f720331435271671531>
...(略)...

systemctl コマンド使用例3:

$ systemctl list-dependencies --user
default.target
● ├─automation-controller-rsyslog.service
● ├─automation-controller-task.service
● ├─automation-controller-web.service
● ├─postgresql.service
● ├─receptor.service
● ├─redis.service
● └─basic.target
●   ├─systemd-tmpfiles-setup.service
●   ├─paths.target
●   ├─sockets.target
●   │ ├─dbus.socket
●   │ └─podman.socket
●   └─timers.target
●     ├─grub-boot-success.timer
●     └─systemd-tmpfiles-clean.timer

ユニットファイルの例

systemd のユニットファイルは、インストール処理内の containers.podman.podman_containerモジュールの generate_systemd オプションの指定によって生成されます。

generate_systemd.new オプションの指定はなくデフォルトの false 扱いです。なので、インストール処理内でコンテナを create して、systemd 経由で start する、という流れです。いきなり run ではないです。

コンテナの CreateCommand を確認すると、odman container create になっていました。

$ podman inspect automation-controller-web 
...(略)...
               "CreateCommand": [
                    "podman",
                    "container",
                    "create",
                    "--name",
                    "automation-controller-web",
...(略)...

以下は、私の環境の /.config/systemd/user/automation-controller-web.service の例です。ExecStartpodman start になっていることが確認できます。

# automation-controller-web.service
# autogenerated by Podman 4.9.4-rhel
# Tue Sep 24 12:40:39 JST 2024

[Unit]
Description=Podman automation-controller-web.service
Documentation=man:podman-generate-systemd(1)
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/run/user/1000/containers

# User-defined dependencies
Requires=postgresql.service redis.service

[Service]
Environment=PODMAN_SYSTEMD_UNIT=%n
Restart=on-failure
TimeoutStopSec=90
ExecStart=/usr/bin/podman start automation-controller-web
ExecStop=/usr/bin/podman stop  \
    -t 30 automation-controller-web
ExecStopPost=/usr/bin/podman stop  \
    -t 30 automation-controller-web
PIDFile=/run/user/1000/containers/overlay-containers/344e8869af0c02b02b2f72033143527167153164ad6adc548e675c4fcfa2995f/userdata/conmon.pid
Type=forking

[Install]
WantedBy=default.target

systemd 連携による自動起動

前述のユニットファイルにある通り、Install セクションでは、WantedBy=default.target が指定されていて、systemctl enable|disable できるようになっていました。

インストール処理内では、ansible.builtin.systemd モジュールで、起動と enable されるようになっています。これにより自動起動を実現しているようです。

ただ、前述通り、ユニットファイルはユーザーレベルのものです。この場合、デフォルトではユーザーがログインすると起動、ログアウトすると停止するため、サービス提供に向きません。

どうなってるんだろうと思ったのですが、インストール処理の中で loginctl enable-linger ユーザー名 が実行されていました。これにより、システ起動時にサービスが起動するようになるようです。

参考: 14.2. systemd サービスの有効化 | Red Hat Product Documentation

ポート開放の仕組み

前述通り podman ps での表示は PORTS は空欄でした。どうやってポート開放しているのかなと思ったので調べました。

--network host でコンテナが起動されていました。

$ podman inspect automation-controller-web 
...(略)...
               "CreateCommand": [
...(略)...
                    "--network",
                    "host",
...(略)...

なお、ホスト側での ss はこんな感じでした。

$ ss -nap | grep 443        # automation-controller-web の listen 分
tcp   LISTEN 0   511   0.0.0.0:443     0.0.0.0:*      users:(("nginx",pid=27533,fd=6),("nginx",pid=27532,fd=6),("nginx",pid=27531,fd=6),("nginx",pid=27530,fd=6),("nginx",pid=27525,fd=6))                                                                                                                                                                                                                                                                                                                                                   
tcp   LISTEN 0   511      [::]:443        [::]:*      users:(("nginx",pid=27533,fd=7),("nginx",pid=27532,fd=7),("nginx",pid=27531,fd=7),("nginx",pid=27530,fd=7),("nginx",pid=27525,fd=7))                                                                              

デフォルトでは、一般ユーザーでは 443 は listen できませんが、前述通りインストール処理内でカーネルパラメーター net.ipv4.ip_unprivileged_port_start を調整しているので listen できます。

インストール処理中、ansible.posix.firewalld モジュールで firewalld の調整もしてくれます。

ストレージ・ボリューム関連

ボリューム一覧は以下の通りです。

$ podman volume  ls
DRIVER      VOLUME NAME
local       postgresql
local       redis_data
local       redis_etc
local       redis_run
local       receptor_run
local       receptor_runner
local       receptor_home
local       receptor_data

ボリュームのパスは以下の通りです。ルートレス Podman としての標準のままです。

$ ls -l ~/.local/share/containers/storage/volumes/
total 0
drwx------. 3 admin admin 19 Sep 24 12:39 postgresql
drwx------. 3 admin admin 19 Sep 24 12:39 receptor_data
drwx------. 3 admin admin 19 Sep 24 12:39 receptor_home
drwx------. 3 admin admin 19 Sep 24 12:39 receptor_run
drwx------. 3 admin admin 19 Sep 24 12:39 receptor_runner
drwx------. 3 admin admin 19 Sep 24 12:39 redis_data
drwx------. 3 admin admin 19 Sep 24 12:39 redis_etc
drwx------. 3 admin admin 19 Sep 24 12:39 redis_run

また、~/aap に用途ごとにディレクトリがあり、この配下を各コンテナがバインドマウントしています。

$ ls -l  ~/aap/
total 0
drwxrwx---. 3 admin admin 55 Sep 24 12:37 containers
drwxrwx---. 7 admin admin 75 Sep 24 12:40 controller
drwxrwx---. 2 admin admin 42 Sep 24 12:39 postgresql
drwxrwx---. 3 admin admin 17 Sep 24 12:39 receptor
drwxr-x---. 3 admin admin 52 Sep 24 12:39 tls

例えば automation-controller-web の場合は以下の通り。

$ podman inspect automation-controller-web
...(略)...
 "HostConfig": {
               "Binds": [
                    "receptor_run:/run/receptor:U,rw,rprivate,nosuid,nodev,rbind",
                    "redis_run:/run/redis:z,rw,rprivate,nosuid,nodev,rbind",
                    "/home/admin/aap/controller/etc/tower.key:/etc/tower/tower.key:ro,rprivate,rbind",
                    "/home/admin/aap/controller/etc/tower.cert:/etc/tower/tower.cert:ro,rprivate,rbind",
                    "/home/admin/aap/controller/etc/launch_awx_task.sh:/usr/bin/launch_awx_task.sh:ro,rprivate,rbind",
                    "/home/admin/aap/controller/data/job_execution:/home/admin/aap/controller/data/job_execution:rw,rprivate,rbind",
                    "/home/admin/aap/controller/data/projects:/home/admin/aap/controller/data/projects:rw,rprivate,rbind",
...(略)...

おわりに

コンテナによるインストールはデプロイが早く、ライセンスの自動適用や設定の投入も一緒にできるが便利だなと思いました。

現状、インストールがうまくいかなかったときは、一度アンイストールしてから再度インストールするほうが良いような感覚でした。

将来の AAP のバージョンで GA になったら、またチェックしたいと思います。

まとめ(再掲)

  • podman でデプロイする方式、ルートレス
  • デプロイ後にライセンスの適用や設定投入もできる
  • 各コンテナはユーザーレベルの systemd 経由で起動

試せなかったこと

興味はあったけど今回試せなかったこと一覧

  • http の禁止(https のみ)
  • 作業マシン以外へのデプロイ
  • Automation mesh 構成
  • トラシュー1 のように、インストール処理中にコンテナ receptor に異常終了した時に、インストール処理を中断させる方法

参考

Podman と systemd の連携周りでは以下の書籍を参考にさせていただきました。

www.shuwasystem.co.jp

gihyo.jp