AWX17.xをクラスタ(HA)構成にする方法

# 概要

　ターゲットノードが多くなると時間短縮を図るために複数台のAWXによる並列実行が必要不可欠になります。しかし、AWXのクラスタ構成手順で調べても公式ドキュメントはTowerの構築手順しかない。また、AWX 18.xからは公式インストーラがKubernetes(k8s)ベースになるので、すぐにk8sへ移行できないユーザも多くいると思いますので、従来のdocker-composeのクラスタ構成手順を残したいと思います。

# アーキテクチャ

[Ansible Towerリファレンス](https://docs.ansible.com/ansible-tower/3.8.2/html_ja/administration/clustering.html)の画像をそのまま拝借。
DBは一つ。あとはすべてのホストごとにawx_task、awx_redis、awx_webが集約されます。
logstashなどでログを収集している場合は、各ホストごとそれぞれにコレクターを配置する必要があります。
![tower-clustering-visual.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/d5773911-c8ad-3dd5-04ac-292e9762a37b.png)

# 手順

現時点最新版[Githubのawx17.1.0のinstaller](https://github.com/ansible/awx/tree/c1ab815c80cac96508d9779d92bc1280d0347627)を用います。
ただし、公式のインストーラはクラスタ構成に完全対応していないため、少し修正が必要になります。
[公式からの差分はこちら](https://github.com/comefigo/awx/commit/41f571a941e6093d343628ad29b66e15fc9d5175)を参照ください。

1. DB(PostgreSQL)を準備します。  
  下記の`pg_hostname`を設定するとインストーラはDBコンテナを生成しなくなるので、個別で準備する必要があります。
2. ターゲットノードとコントロールノードに以下のものをインスコします。
    - コントロールノード
        - Python3(2.10.xも動作した)
        - Ansible
    - ターゲットノード
        - Python3
        - Docker
        - docker-compose
        - pip docker-compose, docker
3. [修正版の公式インストーラ](https://github.com/comefigo/awx/commit/41f571a941e6093d343628ad29b66e15fc9d5175)の`installer/inventory`の以下の変数を環境に合わせて修正します。
    - towerグループのホスト名とIP（ホスト名必須）
    - ansible_user･･･ホストのユーザ名
    - ansible_python_interpreter･･･Pythonのバージョンに合わせて修正
    - ansible_ssh_private_key_file･･･SSH鍵のファイルパス
    - pg_hostname･･･PostgreSQLのホスト名またはIP
    - admin_password･･･AWXの管理者の初期パスワード
4. インストーラを実行する。

    ```command:awx/installer/inventory
    > ansible-playbook -i inventory installer.yml
    ```
5. 一通りインストールが完了すれば、ログインできるようになります。
Username: `inventoryのadmin_user`
Password: `inventoryのadmin_passowrd`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/fde500df-94f2-2067-be35-612d35fa5152.png)

6. Instance groupsで以下のようになっていることを確認します。
Instance groupの名前は必ずtowerになっています。別途作ることができるようですが、ここでは割愛します。
Instancesが作成したAWXホスト数になっていればOKです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/39b9da8c-2bc6-ef27-ede9-ed1a85cb9241.png)

7. すべてのホストのUsed capacity 0%であることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/2db3fa6a-f8bd-f03e-0480-80f64cff11e8.png)

8. サンプルのテンプレートの同時実行(Concurrent Jobs)を有効にし、**複数回**「Launch」もしくは「Relaunch」ボタンを押してください。
※バグなのかわかりませんが、テンプレートの編集で同時実行に変更しても保存されず、一度テンプレートを実行後に再度編集すると反映されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/2bc32983-62f9-f696-6afa-289c9c462fe4.png)

9. 各インスタンスでジョブが実行されたことを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/e5de3bbd-e7d5-f2b9-3cd4-ec2029cd75b1.png)

# 変更点の説明

公式インストーラに修正を加えた箇所を説明します。

### すべてのホスト名（awx_taskのホスト名）が異なること

`installer/roles/local_docker/templates/docker-compose.yml.j2`のawx_taskのhostnameがすべて異なるように修正しました。
また、それだけではなく、`installer/roles/local_docker/templates/tower_settings.py.j2(/etc/tower/settings.py)`の`CLUSTER_HOST_ID`が各awx_taskのホスト名と一致するように修正しました。

`SYSTEM_UUID`も重複しないように修正しました。最新のコードは`SYSTEM_UUID = "{{ inventory_hostname | to_uuid }}"`になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/d6310655-a748-4e67-fd30-9c36376d9717.png)

### Migrate処理は1ホストのみ

インストーラの途中にあるDBの初期化処理は1つのホストのみで実行するように修正しました。
同時実行するとエラーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30522/b737c8de-48f4-ae6c-b09c-5c9d1aa870cf.png)

# サンプルコード

上記の手順をVSCodeのRemote Containerですべてデプロイできるように[サンプルコード](https://github.com/comefigo/ansible-awx-ha)を準備しましたので、必要な方は是非お使いください。
なお、Amazon Linux2のみテストしたので、それ以外の環境は必要に応じて変更してください。
実施手順は[サンプルコードのReadme.md](https://github.com/comefigo/ansible-awx-ha/blob/master/Readme.md)を参照ください。

質問はTwitter、Slack(ansiblejp)、コメントでお気軽にくださいませ。