Automation Mesh / Receptor / ansible-runner のペイロード転送を追う
この記事の前提
- 本記事は公式ドキュメントや upstream(Receptor / ansible-runner 等)の仕様・ソースコードをもとにしたAIを活用した机上調査に基づく内容です。
- Ansible Automation Platform 2.6(コンテナ版) を前提としています。
動画
当記事の内容を動画にしました。理解の一助にご参照ください。
はじめに
Ansible Automation Platform(AAP)の Automation Mesh を使うと、Control Node と Execution Node を別のネットワークに置いて、離れた環境で Ansible ジョブを実行できます。
NW-A Control Node
NW-B Hop Node
NW-C Execution Node
構成としては Automation Mesh の基本系です。
ここで次のような疑問が浮かび上がります。
Control Node にある Playbook や Inventory は、どうやって Execution Node まで届いているのか?
Execution Node が Git を直接叩いているのか。Playbook ファイルだけが飛んでいるのか。そもそも Automation Mesh は何を運んでいるのか。
この記事では、その中身を Receptor と ansible-runner の動作から追いかけます。
1. 全体像
先に結論の図を置きます。
ポイントを先に3つ挙げておきます。
- Automation Mesh が運ぶのは Playbook ファイルではなく、実行コンテキスト一式
- EE のコンテナイメージだけは Mesh を通らない
- 認証情報も一緒に運ばれ、一時的に Execution Node のディスクに置かれる
以降で、この3点がなぜそうなるのかを順に見ていきます。
2. 中心にあるのは ansible-runner の3フェーズ
仕組みを理解する近道は、ansible-runner の transmit / worker / process を押さえることです。
ansible-runner の公式ドキュメントでは、リモートジョブ実行が次の3段階で説明されています。
| フェーズ | 役割 |
|---|---|
transmit |
ジョブ実行に必要なデータを、送信用のバイナリストリームに変換する |
worker |
受信したストリームを展開し、実際にジョブを実行する |
process |
実行結果のストリームを受け取り、イベント処理と artifacts の保存を行う |
ドキュメントには、ローカルで3フェーズを繋いで動かす例が載っています。
ansible-runner transmit ./demo -p test.yml \
| ansible-runner worker \
| ansible-runner process ./demo
そして、この真ん中のパイプを Receptor に置き換えたものが AAP の姿です。
ansible-runner transmit ./demo -p test.yml \
| receptorctl --socket ./control.sock work submit -f --node primary -p - ansible-runner \
| ansible-runner process ./demo
「Receptor はパイプの代わりをしている」 と捉えると、一気に見通しが良くなります。
3. Control Node で何が作られるのか
ジョブが起動されると、Control Node 側で実行に必要なデータが準備されます。ansible-runner ではこれを private_data_dir として扱います。
private_data_dir/
├── env/
│ ├── envvars … 環境変数
│ ├── extravars … extra_vars
│ ├── passwords … 解決済みの認証情報
│ ├── settings … タイムアウト等
│ └── ssh_key … SSH 秘密鍵
├── inventory/ … Controller が生成した静的インベントリ
├── project/ … playbook / roles / collections 一式
└── artifacts/ … 空。結果を受け取る器
ここで大事なのは、運ばれるのは Playbook ファイル単体ではないということです。
「Playbook を実行するために必要な実行コンテキストを丸ごと固めて送る」——これが transmit の仕事です。
そして project/ の中身は、Control Node 側で完了した project update の成果物です。
AWX(AAP の upstream)では、ノードごとに担当するタスクの種別が work type として定義されています。
| work type | 用途 | 実行場所 |
|---|---|---|
local |
project update・management job | Control / Hybrid Node |
ansible-runner |
ユーザースペースジョブ | Execution Node |
kubernetes-runtime-auth |
Container Group 上のジョブ | OCP |
Execution Node は ansible-runner work type をアドバタイズし、Control Node は local をアドバタイズします。この振り分けが「Playbook は Exec、project update は Control」という挙動の実装上の根拠と考えられます。
4. transmit が送れる形に変換する
transmit は private_data_dir と実行パラメータを、リモートの Worker が受け取れるストリームへ変換します。公式ドキュメントでは 圧縮されたバイナリストリーム と説明されています。
Control Node
private_data_dir
│
▼
transmit
│
▼
圧縮バイナリストリーム
「tar.gz で送っている」という説明を見かけますが、正確ではありません。公式の表現は「compressed binary stream」で、tar.gz とは限りません。
なお、この transmit ↔ worker 間のワイヤプロトコルは現時点で正式に仕様化されていません。バージョン間で内部形式が変わりうる前提で扱うのが安全です。
5. Receptor が Work Unit として運ぶ
生成されたストリームは、Receptor の Work Unit のペイロードとして Mesh に投入されます。
Control Node
│ Receptor(27199/tcp・TLS)
▼
Hop Node
│ Receptor(27199/tcp・TLS)
▼
Execution Node
Receptor 側から見ると、work submit によって一意の Unit ID が振られた Work Unit が起動します。--node を指定してリモート投入した場合、ローカル側とリモート側にそれぞれ Work Unit が生成され、別々の Unit ID を持ちます。
Receptor のドキュメントによれば、stdin は投入されたペイロードのコピーであり、ローカル側とリモート側で同じ内容になります。つまり、Work Unit のディレクトリを覗けば、実際に何が転送されたのかを目で確認できます。
6. Hop Node はジョブを実行しない
Automation Mesh を理解するうえで重要なポイントです。
Control Node
│
▼
Hop Node ← ここでは何も実行されない
│
▼
Execution Node
AAP のドキュメントでも、Hop Node は jump host に似た役割で、Execution Node へ通信をルーティングするノードと定義されています。Automation の実行はできません。
Hop Node
├─ ansible-playbook を実行しない
├─ EE イメージを必要としない
├─ ペイロードを開かない(Receptor の中継ノードとしてルーティングのみ)
└─ ジョブ実行キャパシティを持たない
Hop Node における Podman と EE イメージの要件
コンテナ版 AAP では Receptor 自体が Podman コンテナとして稼働するため、Hop Node にも Podman が必要です。
ただし、Hop Node ではジョブを実行しないため、Execution Environment(EE)のコンテナイメージの配置は不要です。
7. Execution Node で worker が動く
ペイロードが Execution Node に到達すると、Receptor が work-command として ansible-runner worker を起動します。
Execution Node 側の receptor 設定には、次のような定義が入っています。
- work-command:
worktype: ansible-runner
command: ansible-runner
params: worker
allowruntimeparams: true
worker は受け取ったストリームを展開して private data directory を再現し、その上でジョブを実行します。
起動の連鎖は入れ子になっています。並列ではありません。
Execution Node
└── Receptor(work-command として worker を起動)
└── ansible-runner worker
└── Podman
└── Execution Environment
└── ansible-playbook
└── Managed Host へ SSH / WinRM
トラブルシュートのとき、この階層のどこで止まっているかを意識すると切り分けが速くなります。
8. EE イメージだけは Mesh を通らない
ここが閉域設計で一番効いてくる点です。
Automation Mesh は Execution Environment のコンテナイメージを運びません。
ジョブ実行データ
│ Automation Mesh / Receptor
▼
Execution Node
EE イメージ
│ ★別途用意が必要(Mesh の外側)
▼
Execution Node
したがって、Execution Node を完全な閉域に置く場合、EE イメージの供給方法を別途決める必要があります。
| 方式 | 内容 | 向いているケース |
|---|---|---|
| 事前 load |
podman save / podman load で手動配置 |
PoC・Exec Node が少数 |
| 閉域内レジストリ | Private Automation Hub / Harbor / ECR 等を NW-C に配置 | 本番・継続運用 |
| Proxy 経由 | HTTP proxy でレジストリに到達させる | ポリシーが許すなら最も楽 |
事前 load 時の注意点(コンテナ版 AAP)
コンテナ版 AAP では Receptor / worker が動作するユーザーコンテキストの Podman ストレージから EE イメージを参照します。root ユーザーで podman load しても、実行ユーザー(例: awx 等の専用ユーザー)のストレージにイメージが登録されていないと「イメージが見つからない」エラーになるため、ロード時の実行ユーザー環境に注意が必要です。
9. 実行結果は逆方向へ戻る
通信は一方向ではありません。
Control Node
│ ① payload(transmit)
▼
Execution Node
│ ② events / artifacts(worker が生成)
▲
Control Node(process が受け取る)
worker はジョブイベントや artifacts を含む結果ストリームを生成し、process がそれを受け取って通常のコールバックとイベント処理を行います。
Control Node 側ではこれが job_event として DB に書き込まれ、Web UI にほぼリアルタイムで表示されます。
なお、worker は artifacts をファイルとして書き出さず、ストリームで返します。最終的にファイルとして保存するのは process 側です。
10. Execution Node には何が残るのか
運用上かなり重要なポイントです。
worker は受信データを Execution Node 側の private data directory に展開して実行します。公式ドキュメントによれば、
-
--private-data-dirを指定しない場合 → 一時ディレクトリに展開し、実行終了時に削除 - 指定した場合 →
--deleteの有無などによって残存期間が変わる
という挙動になります。
したがって、
- ❌ 「Execution Node には何も書かれない」 → 誤り
- ❌ 「必ず特定のパスに永続的に残る」 → 誤り
どちらも正確ではありません。展開先とライフサイクルは receptor / runner の設定に依存します。
認証情報がディスクに載る
ここは見落とされがちですが、閉域設計では無視できません。
展開される env/ には、次のものが含まれます。
env/
├── passwords ← Vault 等から解決済みの認証情報
└── ssh_key ← SSH 秘密鍵
つまり、ジョブ実行中は Execution Node のディスク上に認証情報が平文で存在する可能性があります(通常、実行後に削除されます)。
「閉域に置いてあるから安全」とは限りません。次のような対策を検討する価値があります。
- 展開先ディレクトリの権限確認
- 可能なら tmpfs 化
- ディスク暗号化
- Execution Node 自体へのログイン権限の絞り込み
11. なぜ Execution Node から Git に繋がらなくても動くのか
ここまで理解すると、閉域構成が成立する理由が見えてきます。
Git / SCM
│ HTTPS
▼
Control Node ← project update はここ
│ Receptor
▼
Hop Node
│ Receptor
▼
Execution Node ← Git 到達性は不要
▼
Execution Environment
▼
Managed Host
Execution Node が Git サーバーへアクセスできなくても、Control Node 側で取得・準備したジョブ実行データを渡せば Playbook は実行できます。
requirements.yml による collection / role の取得も project update 時に Control Node 側で解決され、project/ に展開された状態で転送されるため、Execution Node に Galaxy / Automation Hub への到達性も通常は不要と考えられます。
逆に注意すべき点:動的インベントリは Control Node で同期される
AWS / VMware / ServiceNow などの inventory source を使っている場合、Inventory Update も Control Node 側で実行されます。
「Execution Node は閉域でいい」と設計したのに、inventory source の API が NW-C 内にしかなく、Control Node から到達できずに Inventory Update が失敗する——これは踏みやすい落とし穴です。
回避策としては、インベントリをプロジェクト内のファイルとして持つ、あるいは Execution Node 上で動く Job Template から awx.awx.host モジュール等で登録する、といった方法があります。
また、Playbook が実行中に外部サービスへアクセスする場合は、その到達性が Execution Node 側の要件になります。delegate_to: localhost の localhost は Control Node ではなく Execution Node 上の EE コンテナ内である点も、Tower 時代の感覚だと外しやすいポイントです。
12. 大きな Playbook / Collection の影響
この仕組みから、性能面の論点も導かれます。
現在の仕組みでは、プロジェクトは Execution Node にキャッシュされず、ジョブごとに毎回転送されると考えられます。
したがって、
Playbook
Roles
Collections
その他の実行データ
が肥大化すると、転送量とジョブ開始までのレイテンシに直接影響します。
特に、
- 巨大なバイナリをリポジトリに含めている
- 不要な collection まで
requirements.ymlに入っている
といったケースでは、Mesh 経路(NW-B / NW-C)の帯域を意識する必要があります。
また、Git リポジトリの履歴が肥大化している場合は、Control Node 上での project update(git clone / git fetch)の所要時間が伸び、結果としてジョブ全体の開始が遅れます。これは Mesh の転送量ではなく Control Node 側のボトルネックですが、見落としやすいポイントです。
「Playbook の実行時間」だけでなく「ジョブが Execution Node で実行可能になるまでの時間」も見る——これが Mesh 構成での性能設計の勘所です。
13. Hop Node の冗長化を考える理由
構造から自然に導かれるもう一つの論点です。
┌── Hop 1 ──┐
Control Node ─┤ ├─ Execution Node
└── Hop 2 ──┘
Hop Node が落ちるとストリームが切れ、実行中のジョブは救済されずに失敗する可能性が高いと考えられます。単一 Hop は SPOF になりえます。
Automation Mesh は peer-to-peer の接続で構成されるため、複数の経路を用意できます。閉域やファイアウォールをまたぐ環境では、設計段階で次を検討しておくことをお勧めします。
- どこからどこへ接続するか(ピアリングの向き)
- どのノードを peer にするか
- Hop Node を何台置くか
- どの経路を冗長化するか
なお、ピアリング確立後の通信は双方向になります。論理的なジョブの流れ(Control → Exec)と、TCP コネクションの向きは独立しているので、ファイアウォールポリシーに合わせて逆方向ピアリングを選ぶこともできます。
14. 実際に確認してみるには
理屈だけだとイメージしづらいため、手元で追跡・確認する際のアプローチ例を整理しておきます。
※ 以下のコマンド例におけるソケットパスやコンテナ名などは環境・バージョンによって異なる場合があります。実環境に合わせて適宜調整してください。
Mesh の状態を見る
# Control Node 上
podman exec -it automation-controller-task aap-manage list_instances
receptorctl --socket ~/aap/receptor/run/receptor.sock status
Work Unit を追う
Job の詳細画面に Work Unit ID が表示されます。
receptorctl --socket ~/aap/receptor/run/receptor.sock work list
receptorctl --socket ~/aap/receptor/run/receptor.sock work results <unit-id>
ペイロードの中身を自分で作ってみる
AAP を使わずに、ansible-runner 単体で同じことを再現できます。
# transmit の出力をファイルに落として中身を見る
ansible-runner transmit ./demo -p test.yml > payload.bin
ls -lh payload.bin
これを展開してみると、「何が Execution Node に渡っているのか」が実感として掴めます。認証情報が含まれうることも、ここで確認できます。
15. まとめ
AAP の Automation Mesh におけるジョブ実行は、単純な「ネットワーク越しの Playbook コピー」ではありません。
① Control Node での実行コンテキスト組み立て
private_data_dir への Playbook・Inventory・環境変数・認証情報の集約。project update および inventory update も Control Node 側で実行。
② transmit による送信用ストリームへの変換
圧縮バイナリストリームへの変換。転送対象は Playbook 単体ではなく実行コンテキスト一式。
③ Receptor による Work Unit 転送
Hop Node は中継のみを担当(ペイロードの開封やジョブ実行はなし。ただし Receptor 稼働用の Podman は必要)。
④ Execution Node の worker による展開と実行
ansible-runner worker → Podman → Execution Environment → ansible-playbook という入れ子構造での実行。EE イメージ自体は Mesh を通らないため、別途事前配置が必要。
⑤ process への結果返却
ジョブイベントと artifacts を結果ストリームとして Control Node の process へ返却・処理。
おわりに
Automation Mesh の構成を設計するとき、
「Control Node と Execution Node が通信できればいい」
だけで終わらせず、
「ジョブ実行データがどこで作られ、どの経路を通り、どこに展開され、どこで実行され、結果がどう戻るのか」
まで追いかけると、設計上の論点が一本の流れとして見えてきます。
- Git 接続要件
- 動的インベントリの到達性
- Firewall 要件
- Receptor の peer 設計
- Hop Node の冗長化
- Execution Node のディスク容量と保護
- Execution Environment の配置方法
- ジョブ開始までのレイテンシ
Automation Mesh を「ネットワークの仕組み」としてだけ見るのではなく、 「ジョブを Work Unit として実行ノードまで届ける仕組み」 として捉える。これが内部動作を理解するうえでの一番の近道だと思います。
参考
- Remote job execution — Ansible Runner Documentation
- ansible-runner/docs/remote_jobs.rst (devel)
- Workceptor — Receptor Documentation
- receptorctl work submit — Receptor Documentation
- Red Hat Ansible Automation Platform 2.6 Documentation — Containerized installation / Automation mesh
