てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible/AAP] Automation mesh でコントロールノードと実行ノードの分離を試してみた

はじめに

Red Hat Ansible Automation Platform(以下AAP) 2.1 では、スケーラビリティと信頼性を向上させる Automation mesh という機能が導入されました。

AAP1.2 (Ansible Tower としては3.8) までにあった Isolated Node 相当の機能を備えつつ、さらに機能強化されたようなかたちでしょうか。

この記事では、簡単な構成で試したことをまとめます。はじめて調べて試したレベルですので、なにか間違い等あれば @akira6592 までご連絡いただけると助かります。

なお、レッドハットさんの以下のウェビナーを聞いて概要をつかめたので、やってみようと思いました。めちゃくちゃ参考になりました、ありがとうございます!

最新 Ansible Automation Platform 2.1 (AAP 2.1 ) の概要紹介、最新アップデート、実機デモ

珍しく長い記事です。

■ 1. Automation mesh におけるノードの種類

Automation mesh の構成では、それぞれのノードに役割があります。

ノードの役割 説明
コントロールノード(Control node) 司令塔。Automation Controller の Web UI や API の提供し、実行ノード(後述)にジョブの実行を指示する。プロジェクトの更新のようなコントロールプレーンの処理はこのノード内で行われる
実行ノード(Execution node) 実際にジョブを実行するノード。コントロールノードからの指示を受ける
ホップノード(Hoe node) コントロールノードと実行ノードの間を取り持つノード
ハイブリッドノード(Hybrid node) コントロールノードと実行ノードの役割を兼ね備えたノード。AAP 2.1 のインストーラーでは、デフォルトで localhost がハイブリッドノードになる

各ノードは必ず分離しといけないというわけではなく、環境の状況に応じて使い分けます。

たとえば、シンプルにハイブリッドノードだけで事が足りることもあるでしょうし、コントロールノード、と実行ノードを分けたほうがいいこともあるでしょう。はたまた、ホップノードを挟んで延伸したほうがいいここともあるでしょう。

■ 2. 今回の環境 (コントロールノードと実行ノードの分類)

この記事ではコントロールノードと実行ノードそれぞれ1台ずつの構成をとります。ホップノードは挟みません。

mesh と呼べるほどではないですが、これまでハイブリッドノード構成から役割を分離する構成として、最低限の一番シンプルな構成で試してみよう、というのが趣旨です。

登場人物やそれぞれのノードと役割は以下のとおりです。

f:id:akira6592:20220321214014p:plain
役割と動作

各動作の説明です。

No. 動作 説明
(1) ブラウザからジョブテンプレート実行指示 Automation Controller の利用者が Web UI や API を利用して、ジョブテンプレートの実行を指示する
(2) ジョブテンプレート実行開始 利用者からの指示によってジョブテンプレートの実行を開始
(3) プロジェクト更新用EEイメージpull プロジェクト更新に利用する EE(Execution Environment) のイメージを(手元になければ)pullする。利用するイメージは Automation Controller の画面の [実行環境] > [Control Plane Execution Environment] で定義されている registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest
(4) プロジェクト更新用EE起動 プロジェクト更新用EEを起動する
(5) プロジェクト更新 プロジェクトの SCM タイプが git の場合は、リポジトリからプロジェクトを更新する
(6) コレクションダウンロード プロジェクト内の collections/requirements.ymlに利用するコレクションが定義されている場合にコレクションをダウンロードする。デフォルトでは Ansible Galaxy から(今回の構成も)
(7) ジョブ実行指示 コントロールノードから実行ノードに対してジョブの実行を指示する。デフォルトでは TCP 27199 ポートを利用する
a. ダイナミックインベントリ更新用EEイメージpull ダイナミックインベントリ(インベントリ内の「ソース」)があり「起動時の更新」が有効の場合はイメージをpull。デフォルトでは Control Plane Execution Environment に定義の registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest を利用?(Default Execution Environment と同じイメージなので区別が付かない・・ )
b. ダイナミックインベントリ更新用EE起動・更新 a. の続きでダイナミックインベントリを更新。(7) と a. b. の順序関係が分からずこのあたりは数字表記ではない・・
(8) ジョブ実行用EEイメージpull ジョブ実行に利用する EE のイメージを(手元になければ)pullする。利用するイメージは Automation Controller の画面の [実行環境] > [Default Execution Environment] で定義されている registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest 。結果的にデフォルトでは Control Plane Execution Environment と同じイメージ
(9) ジョブ実行用EE起動 ジョブ実行用のEEを起動する
(10) Playbookによる操作 Playbook 実行による操作。今回は Cisco IOSルーターに対して SSH で操作する

今回は試せていませんが、ダイナミックインベントリの更新は、実行ノード側でされるそうです。

なお、点線で示しているとおりコントロールノードからマネージドノードへ直接アクセスできない構成です。マネージドノードとアクセスできる側に実行ノードを置くことで、コントロールノードから間接的にマネージドノードを制御できるようになります。

今回構築するコントロールノードと実行ノード1台ずつの構成では、信頼性は特に向上しないと思いますが、事情があってAutomation Controller から直接マネージドノードにアクセスできないという場合には、解決策になりそうです(公式ブログ What's new: an introduction to automation mesh)でいうDesign for your enterprise)。

■ 3. 下準備

RHEL を2台(コントロールノード、実行ノード)用意した状態からはじめます。

3.1. subscription-manage による作業

subscription-managerregisterattach をして、AAP をインストールできる状態にしておきます。コントロールノード、実行ノードともに必要な作業です。(後述しますが今回AAPのインストーラーはバンドル版ではなく、通常版を利用します。)

# コントロールノード・実行ノード両方
sudo subscription-manager register           # 要ログイン
sudo subscription-manager list --available   # AAPが含まれるプールIDを控える
sudo subscription-manager attach --pool AAPが含まれるプールID

実行ログ

$ sudo subscription-manager register
Registering to: subscription.rhsm.redhat.com:443/subscription
Username: (ユーザー名を入力)
Password: (パスワードを入力)
The system has been registered with ID: xxxxx
The registered system name is: xxxxx
$ sudo subscription-manager list --available
  (いろいろPoolが表示される)
$ sudo subscription-manager attach --pool AAPが含まれるプールID
Successfully attached a subscription for: Red Hat Developer Subscription for Individuals

加えて、AWS 側に構築したコントロールノード側は明示的にリポジトリ有効化をしておきます。(参考ツイート、ありがとうございます)

# コントロールノード(AWS)側のみ
sudo subscription-manager config --rhsm.manage_repos=1

3.2. SSHキーの接続

あとのインストールの中で、コントロールノードからノードに Ansible による SSH 接続が行われます。そのため、認証できる状態にしておく必要があります。

今回は公開鍵認証方式で準備します。キーペアが未作成、未登録の状態から始めているので、以下コマンドでキーペアを作成して、実行ノードに登録します。

# コントロールノード側のみ
ssh-keygen -t rsa
ssh-copy-id admin@実行ノードのグローバルIP

実行ノードに対して Ansible からパスワード認証でログインできる状態であれば特にこの作業は不要です。

■ 4. インストール

コントロールノード側で作業します。

4.1. インストーラーの準備

Automation Controller のインストールには AAP のインストーラーを利用します。

AAP 2.1 の公式ドキュメントの「RED HAT ANSIBLE AUTOMATION PLATFORM インストーラーの選択および取得」を参考にして、インストーラーをダウンロードして「コントロールノード」に配置します。

今回はバンドル版ではないインストーラansible-automation-platform-setup-2.1.1-1.tar.gz を利用します。

配置後、解凍して、ディレクトリを移動します。

# コントロールノード側作業
tar xvzf ansible-automation-platform-setup-2.1.1-1.tar.gz
cd ansible-automation-platform-setup-2.1.1-1

4.2. inventory の修正(構成の指定)

AAP のインストーラーは、設定ファイルとしてインベントリファイル inventory を利用します。先ほど移動したディレクトansible-automation-platform-setup-2.1.1-1 にあります。

このファイルの中で、コントロールノード、実行ノードのホスト、各種パスワードなどの指定をします。

今回の構成は、公式ドキュメント「Red Hat Ansible Automation Platform 自動化メッシュガイド」内の「単一の実行ノードを持つ単一ノードのコントロールプレーン」と同じなので、その inventory をベースにしてます。

ポイントだけ抜粋します。

[automationcontroller]
localhost ansible_connection=local

[automationcontroller:vars]
node_type=control
peers=execution_nodes

[execution_nodes]
rhel84ace2 ansible_host=実行ノードのグローバルIP ansible_user=admin ansible_ssh_private_key_file=/home/ec2-user/.ssh/id_rsa  ansible_become=yes ansible_become_password=昇格パスワード

# ...(略)...
[all:vars]
admin_password='Automation Controllerへのadminパスワード'

# ...(略)...
pg_password='DBのパスワード'

# ...(略)...
registry_url='registry.redhat.io'
registry_username='registry.redhat.ioへのユーザー名'
registry_password='registry.redhat.ioへのパスワード'

各セクションでの指定の説明は以下のとおりです。なお、今回インストーラーはコントロールノードで実行するため localhost はコントロールノードを指します。

セクション 説明
[automationcontroller] localhost がデフォルトで定義されていてそのまま利用
[automationcontroller:vars] 今回は localhost をコントロールノードとして分離したいので node_type=control を指定。デフォルトは node_type=hybrid 相当で、ハイブリッドノード(コントロールノード兼実行ノード)になる
[execution_nodes] 実行ノードを指定する。インストーラー内部で Playbook が呼ばれ、ここで指定したノードに接続、インストールするため、Ansible的なお作法で接続できるようにしておく必要がある。要 root 権限。利用するユーザーや権限に応じて要変更
[all:vars] 特にノードの構成とは関係なく定義するもの。デフォルトのハイブリッドノードの構成でインストールするときと同じ

execution_nodes グループに所属するホストに対して、対応する SSH ホストキーがコントロールノード上に登録されていない場合、ホストキーチェックで一時停止します。これを防ぐには、あらかじめホストキーを登録しておくか、ansible.cfghost_key_checking=False を指定するなどして対策をしておきます。Ansibleの一般的な対応方法と同じです。

また、インストール中にコントロールノードから実行ノードへのレセプター経由の通信テストが行われます。そのため、あらかじめ実行ノードへの通信経路上で SSH だけでなくTCP 27199ポートが許可されるようにしておく必要があります。

4.3. インストーラーの実行

それでは、インストーラの実行です。ansible-automation-platform-setup-2.1.1-1 ディレクトリのまま以下のコマンドを実行します。

sudo ./setup.sh

今回の環境では、15-20分ほどかかりました。

初めて実行したときは以下のエラーで止まってしまいました。実行ノードへの TCP 27199 は開放していたのですが・・。

TASK [ansible.automation_platform_installer.receptor : Validate connectivity for Mesh peers] ***
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (10 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (9 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (8 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (7 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (6 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (5 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (4 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (3 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (2 retries left).
FAILED - RETRYING: [localhost]: Validate connectivity for Mesh peers (1 retries left).
failed: [localhost] (item=rhel84ace2) => {"ansible_loop_var": "item", "attempts": 10, "changed": true, "cmd": ["receptorctl", "--socket", "/var/run/awx-receptor/receptor.sock", "ping", "実行ノードのグロバル", "--count", "1"], "delta": "0:00:00.137918", "end": "2022-03-19 06:49:42.683413", "failed_when_result": true, "item": "rhel84ace2", "msg": "non-zero return code", "rc": 2, "start": "2022-03-19 06:49:42.545495", "stderr": "", "stderr_lines": [], "stdout": "Error: no route to node", "stdout_lines": ["Error: no route to node"]}
...ignoring

...(略)...

TASK [ansible.automation_platform_installer.receptor : Report error when mesh connectivity issue is detected] ***
fatal: [localhost]: FAILED! => {"changed": false, "msg": "An error was detected on Controller Mesh network. Please verify the task output above for further details."}
skipping: [rhel84ace2] => {"changed": false, "skip_reason": "Conditional result was False"}

...(略)...

PLAY RECAP *********************************************************************
localhost                  : ok=258  changed=129  unreachable=0    failed=1    skipped=141  rescued=0    ignored=7   
rhel84ace2                 : ok=77   changed=35   unreachable=0    failed=0    skipped=53   rescued=0    ignored=1  

特に何もせず、もう一度インストーラーを実行したら最後まで正常に完了したため、ポート開放状況の問題ではなさそうででした。

正常完了すると最後はこんなログが表示されました。

PLAY RECAP *********************************************************************
localhost                  : ok=244  changed=53   unreachable=0    failed=0    skipped=162  rescued=0    ignored=0   
rhel84ace2                 : ok=68   changed=10   unreachable=0    failed=0    skipped=62   rescued=0    ignored=0   

The setup process completed successfully.
Setup log saved to /var/log/tower/setup-2022-03-19-10:16:41.log.

権限昇格不足だとこんなエラーに

今回の inventory[execution_nodes] で指定したユーザーの場合、ansible_become による権限昇格が必要でしたが、指定し忘れたときは以下のエラーが表示されました。内部で uid でチェックしているようです。

TASK [ansible.automation_platform_installer.config_dynamic : Ensure user is root] ***
skipping: [localhost] => {"changed": false, "skip_reason": "Conditional result was False"}
fatal: [rhel84ace2]: FAILED! => {"changed": false, "msg": "UID on remote machine is 1000 (0 required). Check Ansible connection and become settings."}

4.5. 構成図の出力(オマケ)

オマケ的な位置づけですが、inventory で指定した、各ノードの構成図を Graphviz の dot ファイルで生成する機能が、インストーラーにあります。

 ./setup.sh -- -t generate_dot_file

この方法は、インストーラー内で実行される Playbook の構成図作成処理に generate_dot_file タグが付いているため、そのタグを指定しています。インストーラーのコマンドの -- の後に、インストーラー内部の ansible-playbook コマンドのオプションを渡せる性質を利用しています。構成図作成処理には never タグも付いているため、デフォルトでは図が作成されません。

今回の構成の場合は、以下の mesh-topology.dot が生成されました。

$ cat mesh-topology.dot 
strict digraph "" {
    rankdir = TB
    node [shape=box];
    subgraph cluster_0 {
        graph [label="Control Nodes", type=solid];
        {
            rank = same;
            "localhost";
        }
    }

    "rhel84ace2";
    "localhost" -> "rhel84ace2";
}

描画するこのようになります。(こちらのサイトを利用)

f:id:akira6592:20220321214236p:plain:w300
コントロールノード、実行ノードそれぞれ1台のシンプルな構成

なお、inventory[automationcontroller:var] で、node_typehybridcontrol 以外の値を指定したときは以下のエラーが表示されました。実際はただのスペルミスでした。

TASK [Parse Mesh] **************************************************************
fatal: [localhost]: FAILED! => {"msg": "Receptor node localhost has an invalid node_type for group automationcontroller, it must be one of the following: hybrid, control"}

この構成図の作成機能でも、ファクト収集が実行され、実行ノードへのSSH接続がされます。そのため、実際のインストールの前に、構成図を出力して、接続や構成の確認するのはアリかもしれません。

■ 5. 状態確認

インストールが無事にできたようなので、いろいろ状態を確認します。すべてコントロールノードでの作業です。

5.1. API による状態確認

まず手始めに API での確認です。

API/api/v2/ping/を叩くと、インスタンスグループとして各ノードの情報が表示されます。認証情報も不要なので、とても手軽に確認できます。

コントロールノードに対してGETで実行します。

https://コントロールノードのグローバルIP/api/v2/ping/

結果は以下のとおりです。instances 配下にノードが2台あり、node_type が実行ノードでは、execution、コントロールノードでは control であることが分かります。

{
    "ha": false,
    "version": "4.1.1",
    "active_node": "localhost",
    "install_uuid": "xxx",
    "instances": [
        {
            "node": "実行ノードのグローバルIP",
            "node_type": "execution",   // ポイント
            "uuid": "yyy",
            "heartbeat": "2022-03-19T10:14:06.737391Z",
            "capacity": 57,
            "version": "ansible-runner-2.1.1"
        },
        {
            "node": "localhost",
            "node_type": "control",   // ポイント
            "uuid": "zzz",
            "heartbeat": "2022-03-19T10:14:06.678438Z",
            "capacity": 55,
            "version": "4.1.1"
        }
    ],
    "instance_groups": [
        {
            "name": "controlplane",
            "capacity": 55,
            "instances": [
                "localhost"
            ]
        },
        {
            "name": "default",
            "capacity": 57,
            "instances": [
                "実行ノードのグローバルIP"
            ]
        }
    ]
}

なお、ハイブリッドノードで構築(デフォルト)した場合、instancesnode_type の値は hybrid になります。

5.2. receptorctl コマンドによる状態確認

Automation mesh 内のノード感の通信状況のなどの操作をする receptorctl というコマンドがあります。 前述のウェビナーで知りました。

pingtraceroutestatus を確認します。

ping の結果は以下のとおりです。正常に返ってきています。

$ sudo su - awx   # awx ユーザーに切り替え
$ receptorctl --socket /var/run/awx-receptor/receptor.sock ping 実行ノードのグローバルIP
Reply from 実行ノードのグローバルIP in 139.429964ms
Reply from 実行ノードのグローバルIP in 140.613656ms
Reply from 実行ノードのグローバルIP in 139.723559ms
Reply from 実行ノードのグローバルIP in 139.933604ms

通信経路上で TCP 27199 を閉めたり、実行ノード上で sudo systemctl stop receptor すると、Error: timeoutError: no route to node になりました。

traceroute の結果は以下のとおりです。ホップノードを挟んでいないのであまりおもしろい結果ではないです。

$  receptorctl --socket /var/run/awx-receptor/receptor.sock traceroute 実行ノードのグローバルIP
0: localhost.localdomain in 76.941µs
1: 実行ノードのグローバルIP in 139.982863ms

あくまで Automation mesh のノードとしての経路を示すので、IPレベルの traceroute とは経路の見え方が異なります。

status の結果は以下のとおりです。正しく認識していそうな表示です。Cost は、メッシュ構成のどの経路を優先するかを決めるもののようです。ルーティングと似ていますね。

$ receptorctl --socket /var/run/awx-receptor/receptor.sock status
Node ID: localhost.localdomain
Version: 1.1.1
System CPU Count: 2
System Memory MiB: 7556

Connection            Cost
実行ノードのグローバルIP        1

Known Node            Known Connections
実行ノードのグローバルIP        {'localhost.localdomain': 1}
localhost.localdomain {'実行ノードのグローバルIP': 1}

Route                 Via
実行ノードのグローバルIP        実行ノードのグローバルIP

Node                  Service   Type       Last Seen             Tags
localhost.localdomain control   StreamTLS  2022-03-19 11:16:39   {'type': 'Control Service'}
実行ノードのグローバルIP        control   StreamTLS  2022-03-19 20:07:28   {'type': 'Control Service'}

Node                  Secure Work Types
localhost.localdomain local, kubernetes-runtime-auth, kubernetes-incluster-auth
実行ノードのグローバルIP        ansible-runner

なお、receptorctl --help を表示すると、他にも connectreloadversionwork というコマンドがありました。

Commands:
  connect     Connect the local terminal to a Receptor service on a remote...
  ping        Ping a Receptor node.
  reload      Reload receptor configuration.
  status      Show the status of the Receptor network.
  traceroute  Do a traceroute to a Receptor node.
  version     Show version information for receptorctl and the receptor node
  work        Commands related to unit-of-work processing

5.3. Web UI にる状態確認

今度は、Automation Controller の Web UI(コントロールノード)での確認をします。

ライセンス認証がまだの場合は済ませておきます。今回はマニフェストファイルを利用しました。

パッと見はハイブリッドノードで構築したときと変わりませんが、違いはインスタンスグループ画面に出ます。

[管理] > [インスタンスグループ] 画面には、control planedefault というインスタンスグループが表示されます。この内 default をクリックします。

f:id:akira6592:20220321215237p:plain
インスタンスグループ default をクリック

インスタンスグループの詳細画面が表示されるので、インスタンス タブをクリックします。

f:id:akira6592:20220321214804p:plain
インスタンスグループ default で「インスタンス」をクリック

インスタンスの一覧が表示されます。実行ノードとして指定したノードがあることが分かります。インストーラーの inventoryansible_host 変数に指定した実行ノードのグローバルIPアドレスの値が、インスタンス名として利用されていました。

f:id:akira6592:20220321215129p:plain
インスタンス一覧

なお、ハイブリッドノードとして構築した場合はこの画面では localhost のみでした。

更にインスタンス名をクリックすると、詳細が表示されます。定期的にヘルスチェックが行われるようで、状態は良好のようでした。眺めてるとヘルチェックは1分間隔のようでした。

f:id:akira6592:20220321215351p:plain
実行ノードインスタンスの詳細

あくまで Web UI を持つのはコントロールノードなので、実行ノードには http アクセスできません。

5.4. パケットレベルのコマンドによる状態確認(オマケ)

これはオマケ的な扱いですが、実行ノード上で tcpdump を眺めていると、コントロールノードとコネクションがはられた状態のまま、10秒間隔でパケットが飛んでいました。 ポーリングのようなものでしょうか。Automation Controller の Web UI で確認できるヘルスチェックの間隔ともまた異なるようです。

契機となるパケットの向きは、以下のように [コントロールノード] > [実行ノード:27199] のときもあれば、逆の時もありました。なにか条件によって変わるのかもしれませんが、詳細は不明です。rhel84ace2 が実行ノードです。

19:56:34.311143 IP コントロールノードのグローバルIP.33580 > rhel84ace2.27199: Flags [P.], seq 341:574, ack 241, win 849, options [nop,nop,TS val 1363547663 ecr 2963536384], length 233
19:56:34.311176 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [.], ack 574, win 1432, options [nop,nop,TS val 2963542674 ecr 1363547663], length 0
19:56:34.381586 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [P.], seq 241:467, ack 574, win 1432, options [nop,nop,TS val 2963542744 ecr 1363547663], length 226
19:56:34.521230 IP コントロールノードのグローバルIP.33580 > rhel84ace2.27199: Flags [.], ack 467, win 849, options [nop,nop,TS val 1363547874 ecr 2963542744], length 0
19:56:44.310948 IP コントロールノードのグローバルIP.33580 > rhel84ace2.27199: Flags [P.], seq 574:807, ack 467, win 849, options [nop,nop,TS val 1363557663 ecr 2963542744], length 233
19:56:44.310969 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [.], ack 807, win 1432, options [nop,nop,TS val 2963552674 ecr 1363557663], length 0
19:56:44.382521 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [P.], seq 467:693, ack 807, win 1432, options [nop,nop,TS val 2963552745 ecr 1363557663], length 226
19:56:44.522032 IP コントロールノードのグローバルIP.33580 > rhel84ace2.27199: Flags [.], ack 693, win 849, options [nop,nop,TS val 1363557875 ecr 2963552745], length 0
19:56:54.311047 IP コントロールノードのグローバルIP.33580 > rhel84ace2.27199: Flags [P.], seq 807:1040, ack 693, win 849, options [nop,nop,TS val 1363567664 ecr 2963552745], length 233
19:56:54.311080 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [.], ack 1040, win 1432, options [nop,nop,TS val 2963562674 ecr 1363567664], length 0
19:56:54.383541 IP rhel84ace2.27199 > コントロールノードのグローバルIP.33580: Flags [P.], seq 693:919, ack 1040, win 1432, options [nop,nop,TS val 2963562746 ecr 1363567664], length 226
19:56:54.523149 IP コントロールノードのグローバルip.33580 > rhel84ace2.27199: Flags [.], ack 919, win 849, options [nop,nop,TS val 1363567876 ecr 2963562746], length 0

逆のときの例(別の環境ですが rhel84ace が実行ノード) https://twitter.com/akira6592/status/1504827993528889344/photo/1

■ 6. 動作確認1: Demo Job Template

ようやく、ジョブテンプレートの実行です。なるべく単純なもので試したかったので、デフォルトで存在するジョブテンプレートを試しました。

デモプロジェクト Demo Project (リポジトリ https://github.com/ansible/ansible-tower-samples)を参照し、localhost で debug メッセージを表示するだけのものです。

6.1. プロジェクト更新がいつの間に失敗

さてジョブを実行しよう、と思ったのですが、プロジェクトの更新が失敗していることに気が付きました。とくに更新の操作はしていませんが。詳細は不明です。

f:id:akira6592:20220321214400p:plain
Demo Project の初期のエラー

更新を再実行したら正常になりました。

6.2. ジョブテンプレート実行

気を取り直して、Web UI から Demo Job Template を起動します。

結果はこちら。

f:id:akira6592:20220321214443p:plain
Demo Job Template の起動

うまくいったようです。

若干気になるのが、ジョブ実行画面の詳細画面で以下のメッセージが表示されている点です。

Task was marked as running but was not present in the job queue, so it has been marked as failed.

f:id:akira6592:20220321220234p:plain
気になるメッセージ

再実行したら先のメッセージは表示されなくなりました。何度か試して見る限り、実行ノードにイメージがない状態でpullからはじめるとこのエラーが表示される傾向がありました。再実行で解消しても、イメージを削除して再実行すると再現しました。

f:id:akira6592:20220321220341p:plain
再実行で解消

イメージpullなどの様子

ジョブテンプレート実行によってイメージが pull されることなどを確認しました。それぞれ awx ユーザーでの確認です。

コントロールノード上

ジョブの実行前は何もイメージがない状態です。

# コントロールノード
$ podman images
REPOSITORY  TAG         IMAGE ID    CREATED     SIZE

ジョブ実行中の podman ps です。これはプロジェクト更新によるもののはずです。特に利用するイメージを指定していないため、実行環境 Control Plane Execution Environment で指定された registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest が利用されています。

# コントロールノード
$ podman ps
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED       STATUS           PORTS       NAMES
16c6fdd371a7  registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest  ansible-playbook ...  1 second ago  Up 1 second ago              ansible_runner_8

ジョブ実行後、イメージが残っています。

# コントロールノード
$ podman images
REPOSITORY                                                            TAG         IMAGE ID      CREATED     SIZE
registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8  latest      2fa77afffbf6  4 days ago  1.17 GB

実行ノード上

ジョブの実行前は何もイメージがない状態です。

# 実行ノード
$ podman images
REPOSITORY  TAG         IMAGE ID    CREATED     SIZE

ジョブ実行中の podman ps です。これはジョブ本体の実行によるもののはずです。特に利用するイメージを指定していないため、実行環境 Default Execution Environment で指定された registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest が利用されています。結果的に Control Plane Execution Environment で指定したイメージと同じになっています。

# 実行ノード
$ podman ps
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED                 STATUS                     PORTS       NAMES
36745a921bc9  registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest  ansible-playbook ...  Less than a second ago  Up Less than a second ago              ansible_runner_9

ジョブ実行後、イメージが残ってます。

# 実行ノード
$ podman images
REPOSITORY                                                            TAG         IMAGE ID      CREATED     SIZE
registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8  latest      2fa77afffbf6  4 days ago  1.17 GB

■ 7. 動作確認2: 家の中のマネージドノードを操作するジョブテンプレート

いよいよ、本命のジョブテンプレートの実行を試します。マネージドノードとなる Cisco IOS の機器は、コントロールノードがら IP 的に直接アクセスできない家の中にあります。

7.1. 各種設定

先程試したデモ用とは異なり、以下の工夫を仕込みます。

  • ジョブの実行の EE には Minimal execution environment で定義している、registry.redhat.io/ansible-automation-platform-21/ee-minimal-rhel8:latestを利用
    • この EE には cisco.ios コレクションは含まれていない
  • collections/requirements.yml によるコレクションのダウンロード
    • これにより、Minimal execution environment でも cisco.ios コレクションが利用できるようになる
  • スタティックなインベントリ定義に加え、ダイナミックなインベントリプラグイン azure.azcollection.azure_rm を利用
    • マネージドノードが家の機器であることをわかりやすくするため、実際に操作するマネージドノードはスタティックに定義
    • azure.azcollection.azure_rm の方は、ダイナミックインベントリの更新がどのノードで行わるかの確認用

プロジェクト設定

git 連携のプロジェクトを作成します。

collections/requirements.yml には、cisco.ios コレクションをダウンロードするための定義をしてあります。コントロールノード上でこの定義にしたがってダウンロードされます。

---
collections:
  - name: cisco.ios
    version: 2.8.0

他、show コマンドを実行して debug 表示するだけの Playbook などがあります。

認証情報設定

2つの認証情報を作成します。

  1. Cisco IOSルーターへの接続に利用する認証情報(タイプ: マシン)
  2. azure.azcollection.azure_rm インベントリプラグイン用の認証情報(タイプ: Microsoft Azure Resource Manager)

インベントリー設定

インベントリーオブジェクトとして inv_main を作成し、その中にスタティック定義とダイナミックな定義(インベントリソース)をします。

  1. 家の Cisco IOSルーター ios01 を定義
    • ansible_host 変数に 192.168.1.11 を指定、このアドレスはコントロールノードからはアクセス不可だが、実行ノードからはアクセス可
  2. azure.azcollection.azure_rm インベントリプラグインを利用するインベントリソースを定義
    • 認証情報には、先程作成した タイプ Microsoft Azure Resource Manager の認証情報を指定
    • 「起動時の更新」にチェックを入れる
    • 実行環境は特に指定しない
    • 前述の通り、こちらはダイナミックインベントリ更新がどのノードでされるかの確認用なので、ジョブからは利用しない

f:id:akira6592:20220321215533p:plain
ソースの設定

ジョブテンプレート設定

これまで作成した、インベントリー、プロジェクト、認証情報を指定します。

Playbook には、Cisco IOSルーターに show コマンドを実行して debug 表示するだけのものを指定します。show コマンドの実行には、cisco.ios コレクションのモジュールを利用します。

また、実行環境には Minimal execution environment を指定します。イメージは registry.redhat.io/ansible-automation-platform-21/ee-minimal-rhel8:latest です。 デフォルトの Default execution environment 定義したイメージ registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest とは異なり、cisco.ios コレクションが入っていません。ですが、前述の通り、プロジェクト内の collections/requirements.ymlcisco.ios を定義しているため、動的にダウンロード後に利用可能になるという仕組みです。

ジョブテンプレートの設定として「インスタンスグループ」もありますが、今回は指定なしにしてみます。

f:id:akira6592:20220321215639p:plain
ジョブテンプレートの作成

7.2. ジョブテンプレート実行

さて、実行です。通常通りジョブテンプレートを実行します。うまく実行できたようです。

f:id:akira6592:20220321215729p:plain
ジョブテンプレートの実行結果 - 出力

f:id:akira6592:20220321215851p:plain
ジョブテンプレート実行結果 - 詳細

実行ノード上での awx ユーザーでいくつか確認します。

イメージpullなどの様子

コントロードノード上

ジョブ実行中の podman ps は以下の通りです。おそらくプロジェクト更新と、collections/requirements.yml の定義に基づくコレクションのダウンロードしているものかと思います。

# コントロールノード
$ podman ps
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED         STATUS             PORTS       NAMES
3cf5dcde1a65  registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest  ansible-playbook ...  19 seconds ago  Up 19 seconds ago              ansible_runner_230

実行ノード上

ジョブ実行中の podman ps です。 2段階あります。

1段階目は、ダイナミックインベントリの更新です。COMMANDansible-inventory になっていることからそう判断しました。タイミング的には、コントロールノード側で処理のあとでした。

# 実行ノード
$ podman images
CONTAINER ID  IMAGE                                                                        COMMAND               CREATED        STATUS            PORTS       NAMES
5e0850bc6a5f  registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8:latest  ansible-inventory...  9 seconds ago  Up 9 seconds ago              ansible_runner_231

2段階目は、実際のジョブの実行です。ジョブテンプレートの実行環境で指定した、ee-minimal-rhel8 のほうのイメージのコンテナが起動していることが分かります。

# 実行ノード
CONTAINER ID  IMAGE                                                                      COMMAND               CREATED        STATUS            PORTS       NAMES
e663d893937f  registry.redhat.io/ansible-automation-platform-21/ee-minimal-rhel8:latest  ansible-playbook ...  3 seconds ago  Up 3 seconds ago              ansible_runner_229

ジョブ実行後、イメージが残ってます。

# 実行ノード
$ podman images
REPOSITORY                                                            TAG         IMAGE ID      CREATED     SIZE
registry.redhat.io/ansible-automation-platform-21/ee-supported-rhel8  latest      2fa77afffbf6  6 days ago  1.17 GB
registry.redhat.io/ansible-automation-platform-21/ee-minimal-rhel8    latest      d8b3521c4042  6 days ago  394 MB

インベントリーの確認

ジョブテンプレート実行後、想定通り azure.azcollection.azure_rm インベントリプラグインによるホストが追加されました。

f:id:akira6592:20220321215959p:plain
Azure 上の VM が追加されている

collections/requirements.yml の定義 ないとエラー(オマケ)

なお、collections/requirements.yml を削除して再実行したら、想定通りモジュールが見つからない旨のエラーになりました。EE Minimal execution environment で実行されたことが、このことからも分かります。

まとめと・雑感

長くなりましたが、AAP 2.1 で導入された Automation mesh を試しました。シンプルにコントロールノード、実行ノードそれぞれ1台ずつの構成でした。

分離させることによって、なにがどちらのノードの実行させるのかが、調べたり試したりすることによって少し理解できいました。

今回の構成では、コントロールノードが直接アクセスできない構成でも、実行ノードを経由することによって制御可能になる、という点がメリットだと思います。

実行ノードが社内LANにより近い側に置かれると思いますが、依然としてコンテナレジストリへのアクセスが必要なのでインターネット接続性が必要です。もし何らかの事情で、インターネット接続性がない場合は、イメージ予めローカルに置いておくか、アクセスできる範囲に Private Automation Hub や GitLab などのコンテナレジストリを配置するかという形にになるかと思います。

今回はじめて Automation mesh を試しましたが、まだ以下の疑問が残っています。機会があれば調べてみたいと思います。

  • 実行ノードでコンテナレジストリにアクセスするための認証情報はどこからくるのか
    • 毎回 コントロールノードからくるのか、インストール時に実行ノード側に保存されるのか
  • 各ノードを追加、削除する方法
  • ジョブ実行時の例のメッセージの詳細
    • Task was marked as running but was not present in the job queue, so it has been marked as failed.

  • ダイナミックインベントリ更新に利用されるデフォルトイメージは Default Execution Environment のものか Control Plane Execution Environment のものか
    • 実質同じイメージであり、変更もできないのであまり気にする必要もなさそう

参考資料

www.ansible.com www.ansible.com access.redhat.com events.redhat.com