zaki work log

作業ログやら生活ログやらなんやら

[AWX / AAP] ジョブの実行をリモートのKubernetesクラスタで行う

デフォルトでは、ジョブの実行はAWXをデプロイしているKubernetesクラスタ上でpodがデプロイされて行われる。設定によって、podをデプロイするクラスタを、異なるクラスタ(AWXをデプロイしていないクラスタ)へ変更することができる。

本記事内では便宜上、AWXをデプロイしているクラスタを「ローカルクラスタ」、ジョブ実行のpodをデプロイするクラスタを「リモートクラスタ」と称する。(この記事内のローカルルール)

  • 2022.08.25: エラーパターンを追記

リモートクラスタ設定

ローカルクラスタからの接続に必要なリソースを作成する。
以下も参照。

アクセス用ServiceAccountの作成

ローカルクラスタからリモートクラスタへの接続用のServiceAccountを作成する。
AWXからはこのServiceAccountのトークンを使って認証してpodをデプロイする、という動作。

ServiceAccountに対するロールの設定は暫定(不要なものもついてる)ので、運用のときは必要最小限の権限にすることを検討すること。

NamespaceとServiceAccountの作成は以下の通り。
このNamespaceはジョブのpodをデプロイする場所になる。

[zaki@k8s-master ~]$ kubectl create namespace awx-exec
namespace/awx-exec created
[zaki@k8s-master ~]$ kubectl create serviceaccount awx-user -n awx-exec
serviceaccount/awx-user created

Roleの作成と、ServiceAccountへのRoleBinding作成は以下。(ロールの割り当て)

[zaki@k8s-master ~]$ kubectl create role awx-role -n awx-exec --verb=* --resource=* 
role.rbac.authorization.k8s.io/awx-role created
[zaki@k8s-master ~]$ kubectl create rolebinding awx-rolebind -n awx-exec --role=awx-role --serviceaccount=awx-exec:awx-user
rolebinding.rbac.authorization.k8s.io/awx-rolebind created

CLIでやるとこのとおりだけど、マニフェストなら以下の通り。

---
apiVersion: v1
kind: Namespace
metadata:
  name: awx-exec
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: awx-user
  namespace: awx-exec
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: awx-role
  namespace: awx-exec
rules:
- apiGroups:
  - ""
  resources:
  - '*'
  verbs:
  - '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: awx-rolebind
  namespace: awx-exec
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: awx-role
subjects:
- kind: ServiceAccount
  name: awx-user
  namespace: awx-exec

アクセストークンの取得

Kubernetes v1.24以降は以下のコマンドで。
出力は1行になっていて、この内容をAWXに登録する。

[zaki@k8s-master ~]$ kubectl create token awx-user -n awx-exec 
eyJhbGciOiJ ......

zaki-hmkc.hatenablog.com

v1.23以前のSecretリソース内のトークンを使う場合は、以下の「APIトークン指定」の項を参照。

zaki-hmkc.hatenablog.com

AWXの設定

AWXでリモートクラスタでジョブを実行するための設定。

認証情報の作成

リモートクラスタへの接続情報は、「認証情報」で設定を作成する。

名前は適当に入力し、「認証情報タイプ」は「OpenShift または Kubernetes API Bearer トークン」を選択する。

追加の入力項目に、APIサーバーのアドレス、作成したServiceAccountのトークン、クラスタの証明書を入力する。

エンドポイントはAPIサーバーのアドレスを入力。kubectlコマンドが使えるならkubectl cluster-infoでも確認できる。

[zaki@k8s-master ~]$ kubectl cluster-info
Kubernetes control plane is running at https://k8s.example.org:6443  # <- これ
CoreDNS is running at https://k8s.example.org:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

証明書は、kubeconfigファイル(デフォルトで$HOME/.kube/config)からcluster以下にあるcertificate-authority-dataの内容をbase64デコードするか、クラスタ上の各Namespaceにあるkube-root-ca.crtConfigMapから抜き出す。
ConfigMapから取得する場合は以下のコマンドを使えば簡単に取り出せる。(-o yamlの結果の場合は行頭にスペースがあるので削る。スペースがあるとエラーになる)

[zaki@k8s-master ~]$ kubectl get cm kube-root-ca.crt -o jsonpath='{.data.ca\.crt}'
-----BEGIN CERTIFICATE-----
[snip]
-----END CERTIFICATE-----

もしエンドポイントがIPアドレス形式だったり証明書の検証ができない場合は、下部の「SSLの検証」のチェックを外す。(その際証明書データは不要…と思う)

インスタンスグループの追加

ここから実行ノードの追加の設定。
メニューの「インスタンスグループ」で「追加」押下。

AAPの場合は「コンテナ―グループの追加」と「インスタンスグループの追加」の2択になるので、コンテナ―グループを選択。

新規コンテナグループの作成画面になるので、適当な名称を入力し、「Pod 仕様のカスタマイズ」をチェックする

Pod仕様のカスタマイズフィールドが表示されるので、以下を修正する。

  • metadata.namespace: デプロイするNamespace名。前述の例の場合awx-exec
  • spec.serviceAccountName: トークン取得に使用したServiceAccount名。前述の例の場合awx-user

これでリモートクラスタ自体の設定と、リモートクラスタへの接続情報の設定が完了。

ジョブの設定

ここから、リモートクラスタで実行したいジョブに、クラスタの指定を行う。
といってもジョブテンプレートの「インスタンスグループ」に追加設定するだけ。

🔍アイコンを押下し、先ほど作ったインスタンスグループを選択して、ジョブテンプレートを保存すればOK

実行

準備ができたらジョブテンプレートを普通に実行。
このとき、リモートクラスタの方で-w (watch)を付加してpodの状態を見ておくと、ジョブのpodがデプロイ・実行される状況を確認できる。
初回はイメージのダウンロードが必要なので時間がかかるが、2度目からすぐ実行(Running状態)になる。

[zaki@k8s-master ~]$ kubectl get pod -n awx-exec -w
NAME                     READY   STATUS    RESTARTS   AGE
automation-job-3-rgjqz   0/1     Pending   0          0s
automation-job-3-rgjqz   0/1     Pending   0          0s
automation-job-3-rgjqz   0/1     ContainerCreating   0          0s
automation-job-3-rgjqz   0/1     ContainerCreating   0          0s
automation-job-3-rgjqz   1/1     Running             0          2m31s
automation-job-3-rgjqz   1/1     Terminating         0          2m39s

...

AWXのUIでもこの通りジョブの実行を確認できる。

エラーのパターン

設定不備などで発生するエラーの内容メモ。

トークンが不正

トークンの期限が切れていたり、誤っていると発生。

Error creating pod: Unauthorized

NamespaceやServiceAccountが存在しない

インスタンスグループの「Pod仕様のカスタマイズ」で入力したNamespaceやServiceAccountが存在しない場合は、トークン不正と同じUnauthorizedエラーが出力された。

Error creating pod: Unauthorized

証明書が不正

誤った証明書やSSL検証ができない場合に発生。
SSLの検証」をオフにすれば回避できる

Error creating pod: Post "https://k8s.example.org:6443/api/v1/namespaces/awx-exec/pods": x509: certificate signed by unknown authority

ServiceAccountに権限が足りない

bindしたroleに、podをデプロイする権限がないと発生。

Error creating pod: pods is forbidden: User "system:serviceaccount:awx-exec:awx-user" cannot create resource "pods" in API group "" in the namespace "awx-exec"

実行環境のイメージの取得に失敗

実行環境として指定したイメージがリポジトリ上に無い場合や、認証が必要なリポジトリなのにその認証に失敗した場合などで発生。

Error creating pod: container failed to start, ImagePullBackOff

ImagePullBackOffの詳細は、Kubernetesクラスタ側で kubectl get eventを実行して詳細を確認できる。

例えばイメージのpullに認証が必要なのに認証できていない場合は以下。

7m47s       Warning   Failed      pod/automation-job-28-jz6mk   Failed to pull image "zakihmkc/priv-httpd:latest": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/zakihmkc/priv-httpd:latest": failed to resolve reference "docker.io/zakihmkc/priv-httpd:latest": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

環境

  • AWX: 21.3.0
  • AAP: 2.1.1 (Automation Controller 4.1.1)
    • on RHEL8.6
  • リモートクラスタ: Kubernetes 1.24.3 (kubeadmで構築)