AWXはamd64向けのイメージしか提供されてないので、Oracle CloudのAlways Free枠で使用できる4コア・RAM24GBのA1.FlexインスタンスのようなARMアーキテクチャの環境ではそのままでは利用できません。
イメージをARM環境でリビルドしてやれば動作するので、さくっと構築できるようにplaybookを作ったのでその内容についてメモしました。
ビルド済みarm64イメージのデプロイをちょっと試す
私がビルドしたarm64のイメージをDockerHubとGitHub Container Registryで公開しています。
このイメージをデプロイするだけで良いのであれば、arm64環境で以下のコマンドでデプロイできます。
$ git clone -b 0.17.0 https://github.com/ansible/awx-operator.git $ cd awx-operator/ $ export NAMESPACE=awx $ make deploy IMG=zakihmkc/awx-operator:0.17.0
※ 記事作成時点で最新は0.18.0だけど、operatorのデプロイ後カスタムリソースからpodが何故か作成されなかったので、動作確認できてる0.17.0を使ってます。
awx-operator
がデプロイされたら、以下の内容のAWX
カスタムリソースをデプロイ。
--- apiVersion: awx.ansible.com/v1beta1 kind: AWX metadata: name: awx-demo namespace: awx spec: service_type: nodeport image: zakihmkc/awx image_version: 20.0.0 image_pull_policy: Always ee_images: - name: awx-ee-arm64 image: zakihmkc/awx-ee:0.6.0 - name: AWX EE (latest) image: zakihmkc/awx-ee:0.6.0 control_plane_ee_image: zakihmkc/awx-ee:0.6.0
ノードのCPUやメモリリソースが少なくてpodがpendingになる場合は、Containers Resource Requirementsのパラメタを追加してrequests
の制限を入れてください。
AWXをビルド・デプロイするplaybook
Oracle CloudのA1.FlexシェイプのUbuntu 20.04 (4コア・RAM24GB)で動作確認しています。
デプロイ直後のまっさらな状態のUbuntu 20.04インスタンスに対して、Ansibleを使って、Dockerのインストールとイメージのbuildとpushを行い、K3sのインストールとAWXのデプロイを行います。外部アクセス用には、K3s標準のTraefikのIngressを使用します。
使い方
リポジトリのクローン
$ git clone https://github.com/zaki-lknr/awx_build_and_deploy.git $ cd awx_build_and_deploy
インベントリ
inventory-example.ini
で定義されている変数は以下の通り。
ビルドしたイメージは、registry_url
とregistry_username
を元にレジストリURLを生成しpush
されます。
ビルドは行わずに、前述手動の手順と同様にビルド済みのイメージをデプロイするだけであれば、build
ホストグループとregistry_*
をコメントアウトし、後述のイメージ名のオプションの*_image_repository
を初期値のままにしておけば、デプロイだけ処理します。
このplaybookでは動作環境としてK3sをインストールしてそこへAWXをデプロイします。K3sで標準で使用できるIngressを使って外部公開するため、アクセス用FQDNをawx_service_fqdn
に指定します。ここで指定したFQDNはDNSやhosts
ファイルを使って名前解決できるようにすればwebアクセスできます。
項目 | 説明 |
---|---|
build ホストグループ |
イメージビルドするホストを指定 |
deploy ホストグループ |
AWXをデプロイするホストを指定 (build と同じでOK) |
awx_service_fqdn |
Ingressで使用するアクセス用FQDN |
awx_namespace |
AWXをデプロイするk8sのネームスペース |
registry_username |
ビルドしたイメージをpushするレジストリのログインユーザー名 |
registry_password |
ビルドしたイメージをpushするレジストリのログインパスワード |
registry_url |
ビルドしたイメージをpushするレジストリURL (省略時はDocker Hub) |
イメージのレジストリURLに関するオプションは以下。
未指定の場合は前述の通りregistry_url
とregistry_username
を元にレジストリURLが決まりますが、これらの変数でレジストリURLを上書きできます。
自分のアカウントのレジストリへpushする場合は、exampleのインベントリファイルの設定はコメントアウトしてください。
項目 | 説明 |
---|---|
operator_image_repository |
ビルド・デプロイするawx-operator のイメージ名 |
awx_image_repository |
ビルド・デプロイするawx のイメージ名 |
awx_ee_image_repository |
ビルド・デプロイするawx-ee のイメージ名 |
リソース制限のオプションは以下。
未指定の場合はデフォルト値が使用されます。デプロイ先のノードスペックが低い場合等はlimitsの値をノードサイズに収まるように指定してください。
(例えば2コア・RAM12GBの場合は、CPU 400m・メモリ1GBとかにすれば大体行けます)
項目 | 説明 |
---|---|
web_resource_requests_cpu |
Web containerのCPU requests値 |
web_resource_requests_mem |
Web containerのメモリrequests値 |
web_resource_limits_cpu |
Web containerのCPU limits値 |
web_resource_limits_mem |
Web containerのメモリlimits値 |
task_resource_requests_cpu |
Task containerのCPU requests値 |
task_resource_requests_mem |
Task containerのメモリrequests値 |
task_resource_limits_cpu |
Task containerのCPU limits値 |
task_resource_limits_mem |
Task containerのメモリlimits値 |
ee_resource_requests_cpu |
EE control plane containerのCPU requests値 |
ee_resource_requests_mem |
EE control plane containerのメモリrequests値 |
ee_resource_limits_cpu |
EE control plane containerのCPU limits値 |
ee_resource_limits_mem |
EE control plane containerのメモリlimits値 |
バージョンに関するオプションは以下。
該当Gitリポジトリのタグorブランチ名に対応しています。
ただし、現状では指定のバージョン以外の動作は基本的に未確認。
項目 | 説明 |
---|---|
operator_version |
AWX Operatorのバージョン |
awx_version |
AWXのバージョン |
awx_ee_version |
AWX EEのバージョン |
ansible_runner_version |
Ansible Runnerのバージョン |
ansible_builder_version |
Ansible Builderのバージョン |
python_base_version |
python-base-imageのバージョン |
python_builder_version |
python-builder-imageのバージョン |
receptor_version |
Receptorのバージョン |
実行
インベントリファイルが用意できたら、ansible-playbook
コマンドで実行。
$ ansible-playbook -i inventory.ini playbook.yml
[build]
ホストグループに指定したホストに対してDockerのインストールを行い、必要な全イメージをbuildし、K3sへデプロイするイメージをpushします。
push対象のレジストリには、インベントリに指定したユーザー名とパスワードで認証を行います。
ビルドが完了したら、[deploy]
ホストグループに指定したホストへK3s
をインストールし、ビルド処理でpushしたコンテナイメージをデプロイします。
デプロイ後しばらく待てば、awx_service_fqdn
に指定したFQDNにブラウザでアクセスすればAWXの画面が表示されます。
(クラウドのセキュリティグループは別途80/TCPを許可しておいてください)
AWXへログインするには、ユーザー名はadmin
で、パスワードは以下のコマンドで確認できます。
$ kubectl get secret -n awx awx-demo-admin-password -o jsonpath="{.data.password}" | base64 -d
解説 (という名の備忘録)
AWX 20.0.0はKubernetesクラスタへデプロイするために、operatorのイメージ(awx-operator)と、AWX本体(awx)とAnsible Execution Environment for AWX(awx-ee)の3つのイメージが必要です。
awx-operator
とawx
はarm64環境でそれぞれビルドすればよいので簡単ですが、awx-ee
のイメージは、ベースイメージや内部で使用する実行用バイナリファイルもamd64版しかないため、以下のイメージのビルドも必要です。
awx-ee
のイメージビルドにはansible-runner
とansible-builder
が必要で、ansible-runner
とansible-builder
はどちらもpython-base
とansible-builder
が必要です。この4イメージはmain
ブランチや最新リリース版をビルドすれば現状は大丈夫です。イメージビルドはpython-base
/python-builder
イメージをビルドしたあとにansible-runner
/ansible-builder
をビルドします。
また、/usr/bin/receptor
としてreceptor
イメージから実行ファイルをコピーしているので、receptor
イメージもarm64環境でビルドする必要があります。
python-base
ビルド手順のドキュメントは特に見当たらなかったけど、リポジトリルートにContainerfile
があるのでこのファイルでdocker build
します。
後続のansible-runner
とansible-builder
のビルドを簡単にするために、quay.io/ansible/python-base:latest
というタグを指定しておきます。
python-builder
これもpython-base
と同様に、Containerfile
があるのでこのファイルでdocker build
します。
また、これもansible-runner
とansible-builder
のビルド用にquay.io/ansible/python-builder:latest
タグを指定します。
ansible-runner
これはMakefile
があるので、make
を使ってビルドします。ファイルをチェックするとimage
というターゲットがあるので、以下のコマンドでイメージビルドできます。
ビルドにはquay.io/ansible/python-base:latest
とquay.io/ansible/python-builder:latest
が必要なので、必ず事前にarm64版をローカルに保持しておきます。(無い場合quayからamd64版をpullしてしまうので実行時にエラーになる)
$ make image
ansible-builder
これもansible-runner
と同様にMakefile
があるのでmake
コマンドを使います。同じく'image`ターゲットがあるので、コマンドは以下です。
ansible-runner
同様に、quay.io/ansible/python-base:latest
とquay.io/ansible/python-builder:latest
が必要なので事前にarm64版をビルドしておきます。
$ make image
receptor
receptorは他よりちょっとハマりがあって、2022.03時点の最新リリース版のv1.1.1
だと、ベースイメージにcentos:8
が指定されており、CentOS 8はすでにサポート終了してYumリポジトリが無効になっているため、以下のエラーメッセージでイメージビルドに失敗します。
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
ということで1.1系はこの状態っぽいので、1.0系を使うとよさげ。
現在1.2の開発が行われてるっぽいですが、最初に試した2月時点だと、golangのインストールをパッケージでなく RUN curl -LO https://go.dev/dl/go1.16.13.linux-amd64.tar.gz
を実行して行っており、当時はダウンロードするバイナリのURLをarm64版に修正するなど試したりして回避してたので、開発版や1.2は様子見で、少し古いリリース版を使うのが現状では手間が少なそうです。
awx-ee
依存する5つのarm64版イメージビルドが完了したらawx-eeをビルドすればOK。これらの依存イメージはpushする必要はなく、ローカルにあればそれをベースイメージとしてビルドします。
awx-eeのビルドはREADMEに書かれており、tox
コマンドを使ってDockerの場合は以下を実行します。
$ tox -edocker
ただawx-eeのイメージは原因が結局よくわからなかったんだけど、これでビルドしたイメージでデプロイしたAWXで、(Demoを含む)ジョブテンプレート実行時に以下のPermissionErrorが発生しました。
Traceback (most recent call last): File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/jobs.py", line 449, in run self.pre_run_hook(self.instance, private_data_dir) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/jobs.py", line 979, in pre_run_hook RunProjectUpdate.make_local_copy(job.project, private_data_dir, scm_revision=job_revision) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/awx/main/tasks/jobs.py", line 1380, in make_local_copy source_branch = git_repo.create_head(tmp_branch_name, p.scm_revision) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/git/repo/base.py", line 386, in create_head return Head.create(self, path, commit, force, logmsg) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/git/refs/symbolic.py", line 543, in create return cls._create(repo, path, cls._resolve_ref_on_create, reference, force, logmsg) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/git/refs/symbolic.py", line 510, in _create ref.set_reference(target, logmsg) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/git/refs/symbolic.py", line 326, in set_reference assure_directory_exists(fpath, is_file=True) File "/var/lib/awx/venv/awx/lib64/python3.9/site-packages/git/util.py", line 177, in assure_directory_exists os.makedirs(path, exist_ok=True) File "/usr/lib64/python3.9/os.py", line 225, in makedirs mkdir(name, mode) PermissionError: [Errno 13] Permission denied: '/var/lib/awx/projects/_6__demo_project/.git/refs/heads/awx_internal'
検索するとIssueでも見つかったけど、結局どう解決したかわからず…
同じメッセージに遭遇したけど、、、
— z a k i 🌈🌉 (@zaki_hmkc) 2022年3月14日
AWX in K8s: Permission denied error when syncing inventory from project · Issue #9733 · ansible/awxhttps://t.co/3n2gkNv5Wg
いろいろ試行錯誤(↑のツリー参照)した結果、k8sへデプロイした際にawx-eeの実行ユーザーがrootになってるのがマズイっぽい。
AWXのpodは、awxとawx-eeの複数コンテナから構成されており、awxコンテナはuid=1000(awx)
で動作しているのに対して、awx-eeコンテナはuid=0(root)
で動作した状態で、両方のコンテナからemptyDirで/var/lib/awx/projects
を共有している、というpod構成。
ジョブテンプレート実行時には、awx-eeコンテナでリポジトリをcloneするため、.git
以下にroot権限でGitの制御ファイルが作成され、このファイルをawxコンテナからの参照(更新?)時に権限エラーになっている、というのが原因のようでした。
この問題を回避するため、コンテナの実行権限をコントロールできたら早そうだけどOperatorのカスタムリソース経由のためだいぶ厳しそうだったので、コンテナビルドの段階で実行ユーザーの指定を入れました。
具体的には、一旦awx-eeイメージを普通にビルドし、そのawx-eeイメージをベースイメージとして、更にUSER 1000
だけ指定したDockerfileでビルドするというもの。この追加のイメージであれば、実行時にawxコンテナと同じuid=1000で動作するため、ジョブテンプレートも正常に動作しました。
awx
これはMakefile
はあるけど、使い方がよくわからなかった。docker-compose
でイメージビルドできるっぽいけど多分Docker Compose環境用らしく、K8sへデプロイしてもストレージドライバ周りでエラーが出たので使えなかった。
(ブログ作成時に改めてよくみたらawx-kube-dev-build
というターゲットがK8s用イメージビルドかも…未確認)
リポジトリ内のファイルをチェックすると、Dockerfile
を生成してるplaybookがtools/ansibleディレクトリ以下にあるので、このplaybookを使ってイメージビルドを確認できた。実行するコマンドは以下の通り。
$ ansible-playbook build.yml
インベントリファイルなどで以下の変数を定義して実行時に指定すれば、このplay実行によってレジストリへのpushも実行される。
[all:vars] push=1 registry=docker.io awx_image=zakihmkc/awx awx_image_tag=20.0.0
ただ今回作った自作のplaybookでは、レジストリとイメージパスを分割で定義されると都合が悪かったのでこの機能は使わず、自前でpushしてます。
awx-operator
Makefile
があるのでmake
コマンドでビルドできます。
ansibleディレクトリやplaybooksディレクトリはあるんだけど、ビルド用のplaybookファイルは見当たらなかったので、多分make
するしかないかも。以前デプロイのつもりでミスってビルドしてしまったこともあるので…(笑)
この前make deployじゃなくてmakeしたらイメージビルド始まったから何とかなるだろうきっと(適当
— z a k i 🌈🌉 (@zaki_hmkc) 2022年2月10日
ターゲットはdocker-build
で、IMG
パラメタを指定すれば、ビルドするイメージのタグも指定できるので、自分のレジストリへpushするようにタグ指定しておくと便利です。
$ make docker-build IMG=zakihmkc/awx-operator:0.17.0
試してないけどmake docker-push
でpushもできると思う。
参考情報
2月中旬にAWX 19.5.1のときに試した作業ログ。
CentOS 8のリポジトリがクローズした直後だったらしく、タイミングが良かったのやら悪かったのやら…(笑)
あと、去年の時点で同じようにarm64環境(Raspberry Pi)向けにビルド・デプロイされてる方もいらっしゃいました。
receptorのバイナリ取得がシンプルで良いですね。。
あと今回はコンテナ操作が多かったですが、発売されたばかりのこちらの本にDockerやKubernetesで使えるサンプルコードがたくさん載ってるので、使い方をさっと確認できて便利でした(ステマ)