目次
やりたかったこと
AWX の 18.0
から、インストールには AWX Operator の利用、すなわち Kubernetes や OpenShift 上へのデプロイが推奨されるようになりました。それ以前のバージョンでは Docker Compose ベースのデプロイも選択肢として用意されていましたが、現在では(開発やテスト目的を除いて)非推奨になっています。
とはいえ、気軽に使いたいだけ、シングルノードの可用性で充分、などの軽めのユースケースに対しては、すでに Kubernetes を使っている環境でない限り、AWX のためだけに Kubernetes 環境を作る(そして運用していく)のも少々大袈裟で大変です。かといって、公式のインストール手順 で気軽に試せる手段として紹介されている minikube は、プロダクション用途が想定されていない開発や学習用のツールのため、AWX をもう一歩踏み込んで日常的に使っていきたい場合には、逆に少し心許ないところがあります。
そんなわけで、ふたつの選択肢の間でほどよく使えるように、
- シングルノード で
- 外部からもアクセス できて
- データも永続化 できて
- それなりに手堅く 使っていける
感じのを、K3s で作ることにしました。
AWX on minikube, K3s, MicroK8s, or k0s
AWX を 公式のインストール手順 に従って minikube で構成した場合、実際に日常で使っていける AWX としての仕上がりを期待してしまうと、現実とは少しギャップが生じます。
minikube はもともとローカル環境での学習や開発を目的にしたツールのため、その目的に沿った利用であれば非常に軽量かつ快適に利用でき、事実、たいへん便利です。一方で、根本的にはプロダクション用途が想定されていないこともあり、外部からのアクセスやデータの永続性に関しては機能が限定的で、学習用途からもう一歩踏み込んだ利用には少し不安感が出てきます(オプションでコントロールは可能ですが、そもそものツールの仕様上、ネットワークが少し複雑になりがちです)。
対して K3s は、いわゆる Kubernetes の軽量版ディストリビューションのひとつで、IoT やエッジコンピューティングなどのユースケースではプロダクション用途も想定されています。元の Kubernetes と比較すると軽量化のために機能が削減されてはいますが、シングルノードでも構成でき、今回のように、
- プロダクション用途でも使える
- なるべく手軽(凝った使い方ができなくてもよい)に
- すぐ使い始められる Kubernetes 環境
としても、とてもよい選択肢です。もちろんマルチノード構成も組めるので、さらに本格的な構成や様々な使い方にも対応できます。
類似のディストリビューションではほかにも MicroK8s、k0s などがあります。どちらもシングルノードで動作させられますが、前者はフル機能な Kubernetes になるのでちょっと過剰、後者は日が浅いのでちょっと見送り…… な感じで、今回は K3s に落ち着いています。
目指す AWX の形
手軽とはいいつつまじめに使える状態には仕上げたいので、ほどよいバランスを目指して、今回の AWX は次のような要件で考えます。
- 1 台の CentOS 8 上で動作する
- HTTPS で外部からアクセスできる
- データが永続化される
- ローカルディスク上(
hostPath
)でよい - その代わり PV を消してもデータがホスト上に残ってほしい
- ローカルディスク上(
- パスワード類をあらかじめ指定できる
- 全損しても元のデータと元のパスワードで作り直せばきれいに復元されてほしい
- コンポーネントのバージョンを指定できる
- 全損したときに任意のバージョンで復元できてほしい
まとめると、今回は データやパスワードのオーナシップを人間側に寄せる ことを要件にしています。パスワード類は事前に指定しなければランダム文字列で生成されますが、データをそのままに丸ごと作り直したい場合などに多少面倒になる(古い PostgreSQL の認証情報を別のシークレットで渡す必要がある)ので、決め打ちできるようにしてしまっています。
ただし、理想を言えばこの要件はむしろ悪手 で、データにしてもパスワードにしても、障害時のリカバリを含め、本来はなるべく人間の制御下からは離す方向で考えるほうが望ましいでしょう(後述しますが AWX Operator も組み込みでバックアップとリストアの仕組みが実装されているようで、それらを併用すれば人間の管理負荷も削減できそうです)。
ホストの準備と K3s の導入
今回は CentOS 8 をホストとして利用するため、ミニマム構成でインストールして適当に用意します。ハードウェアの最小要件は Ansible Tower のドキュメント では 2 CPU / 4 GB RAM ですが、今回は大きめに 4 CPU / 8 GB RAM にしています。
K3s のドキュメント に従って、Firewalld を無効化して停止します。
sudo systemctl disable firewalld --now
K3s のインストールスクリプトをダウンロードして実行します。kubectl
用に作成される設定ファイル(/etc/rancher/k3s/k3s.yaml
)を作業用の一般ユーザからも読み取れるようにするため、ここでは --write-kubeconfig-mode 644
オプションを与えています(ドキュメントに記載 があります)。
curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644
完了すると、バイナリの導入のほか種々の設定が行われ、K3s が利用できる状態になります。Systemd にもサービス K3s が登録され、自動起動が有効化されます。また、kubectl
コマンドも利用できるようになります(この kubectl
の実体は、/usr/local/bin/k3s
へのシンボリックリンクで、既定で /etc/rancher/k3s/k3s.yaml
を読むなど、いくつかアップストリームのそれとは異なる独自の仕様を持っています)。
なお、--write-kubeconfig-mode 644
オプション付きで K3s を導入すると、ホストにログインできる誰でも管理権限で kubectl
を叩けるようになります。操作ユーザを限定したいのであればこのオプションは使わず、導入後に /etc/rancher/k3s/k3s.yaml
を ~/.kube/config
にコピーして KUBECONFIG
環境変数で指定するなど、何らかの工夫が必要です。
AWX Operator の導入
K3s の導入が終われば、すでにシングルノードの Kubernetes が利用できる状態になっているので、ここからは AWX の導入です。
AWX のインストール手順 に従い、AWX Operator を構成します。ここでは執筆時点の最新の 0.10.0
を利用しています。なお、AWX Operator のバージョンは AWX のバージョンにも紐づく(異なる組み合わせでの利用はサポートしていない)ので、リストア目的で環境を再構築する場合は、この段階からバージョンを気にする必要があります。AWX Operator の 0.10.0
は、AWX の 19.2.0
に対応しているようです(installer
ロールの変数ファイル から対応バージョンが読み取れます)。
kubectl apply -f https://raw.githubusercontent.com/ansible/awx-operator/0.10.0/deploy/awx-operator.yaml
これで、デフォルトのネームスペース(通常は default
)に awx-operator
がデプロイされます。
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
awx-operator 1/1 1 1 30s
追記(2021/10/06):
AWX Operator の 0.14.0
から、AWX Operator のデプロイに make
を使うようになりました。
# make のインストール
sudo dnf install -y git make
# リポジトリのクローンと特定のバージョンのチェックアウト
git clone https://github.com/ansible/awx-operator.git
cd awx-operator
git checkout 0.14.0
# AWX Operator が動作する名前空間の指定とデプロイ
export NAMESPACE=awx
make deploy
AWX のデプロイ
AWX Operator の導入でカスタムリソース AWX
も利用可能になるので、雑に言えば、あとは AWX
リソースのマニフェストを書いて kubectl apply
すれば完成です。ミニマムでは、マニフェストは AWX Operator のドキュメント に記載のある数行だけです。
が、今回は前述の要件の通り少しカスタマイズを入れたいので、ドキュメント を参照しながらマニフェストに手を入れていきます。いくつかマニフェストファイルを作ってから、Kustomize でまとめて流す作戦で考えます。
詳解しているファイル群はまとめて GitHub 上のリポジトリ でも公開しています。
AWX リソースの準備(awx.yaml
)
AWX リソースのマニフェストを用意します。中で参照させているシークレットや PV、PVC については後述します。
---
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
name: awx
spec:
admin_user: admin
admin_password_secret: awx-admin-password
ingress_type: ingress
ingress_tls_secret: awx-secret-tls
hostname: awx.example.com
postgres_configuration_secret: awx-postgres-configuration
postgres_storage_class: awx-postgres-volume
postgres_storage_requirements:
requests:
storage: 2Gi
projects_persistence: true
projects_existing_claim: awx-projects-claim
なお、このパラメータ名は AWX Operator の 0.10.0
準拠ですが、以前の 0.9.0
までは、パラメータ名にすべて tower_
が接頭辞としてついていました。古いバージョンを利用する場合は置き換えが必要です。
Namespace リソースの準備(namespace.yaml
)
作ったり消したりしやすくなるので、ネームスペースを用意します。
---
apiVersion: v1
kind: Namespace
metadata:
name: awx
PersistentVolume リソースとディレクトリの準備(pv.yaml
、pvc.yaml
)
前述の awx.yaml
で参照しているふたつの PV(PostgreSQL 用、プロジェクト用)と、そのうちプロジェクト用の PV のための PVC のマニフェストです。PostgreSQL 用の PVC は事前に定義できないようなので、クラス名で紐づけさせています。
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: awx-postgres-volume
spec:
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 2Gi
storageClassName: awx-postgres-volume
hostPath:
path: /data/postgres
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: awx-projects-volume
spec:
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 2Gi
storageClassName: awx-projects-volume
hostPath:
path: /data/projects
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: awx-projects-claim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 2Gi
storageClassName: awx-projects-volume
併せて、PV 中で hostPath
で指定しているディレクトリも作成します。プロジェクトディレクトリは UID が 1000
の awx
ユーザが触ることになるので、その UID で作成します。
sudo mkdir -p /data/postgres
sudo mkdir -p /data/projects
sudo chown 1000:0 /data/projects
なお、K3s では Local Path Provisioner がデフォルトで動作しており、PV を手で用意しなくても PVC に対して動的に PV をプロビジョニングできますが、
persistentVolumeReclaimPolicy
がDelete
になる(PV を消すと実データも消える)accessModes
がReadWriteMany
の PVC に対応できない- PV 名が予測できない(
/var/lib/rancher/k3s/storage
下の GUID ベースのディレクトリとして作成される)
ので、今回は使っていません。
サーバ証明書の準備(tls.crt
、tls.key
)
AWX のインタフェイスを Ingress で HTTPS 化するために、サーバ証明書を作ります。ここでは自己署名証明書を作っていますが、正規のものでももちろんよいです。
openssl
コマンドで作成します。
AWX_HOST="awx.example.com"
openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -out tls.crt -keyout tls.key -subj "/CN=${AWX_HOST}/O=${AWX_HOST}" -addext "subjectAltName = DNS:${AWX_HOST}"
Kustomize の準備(kustomization.yaml
)
ここまでで作った色々をまとめて放り込むために、kustomization.yaml
を作成します。冒頭で namespace
を指定して、そのネームスペース内に閉じ込めています。
また、awx.yaml
中で指定していたシークレットリソースもこの中で作成させます。PostgreSQL の認証情報と AWX の管理者の初期パスワードもここであらかじめ作成させます(ランダムでよければ当該ブロックは丸ごと削除できます)。
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: awx
generatorOptions:
disableNameSuffixHash: true
secretGenerator:
- name: awx-secret-tls
type: kubernetes.io/tls
files:
- tls.crt
- tls.key
- name: awx-postgres-configuration
type: Opaque
literals:
- host=awx-postgres
- port=5432
- database=awx
- username=awx
- password=Ansible123!
- type=managed
- name: awx-admin-password
type: Opaque
literals:
- password=Ansible123!
resources:
- namespace.yaml
- pv.yaml
- pvc.yaml
- awx.yaml
デプロイ
Kustomize を実行します。
$ kubectl apply -k .
namespace/awx created
secret/awx-admin-password created
secret/awx-postgres-configuration created
secret/awx-secret-tls created
awx.awx.ansible.com/awx created
persistentvolume/awx-postgres-volume created
persistentvolume/awx-projects-volume created
persistentvolumeclaim/awx-projects-claim created
うまくいけば AWX Operator の Pod のログに Ansible っぽいアレが出て完了します。
$ kubectl logs -f deployment/awx-operator
...
--------------------------- Ansible Task Status Event StdOut -----------------
PLAY RECAP *********************************************************************
localhost : ok=51 changed=2 unreachable=0 failed=0 skipped=32 rescued=0 ignored=0
-------------------------------------------------------------------------------
追記(2021/10/06):
AWX Operator 0.14.0
以降では、ログは次のコマンドで確認できます。
kubectl -n awx logs -f deployments/awx-operator-controller-manager -c manager
awx
ネームスペースにいろいろできあがります。
$ kubectl get all -n awx
NAME READY STATUS RESTARTS AGE
pod/awx-postgres-0 1/1 Running 0 4m30s
pod/awx-b47fd55cd-d8dqj 4/4 Running 0 4m22s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/awx-postgres ClusterIP None <none> 5432/TCP 4m30s
service/awx-service ClusterIP 10.43.159.187 <none> 80/TCP 4m24s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/awx 1/1 1 1 4m22s
NAME DESIRED CURRENT READY AGE
replicaset.apps/awx-b47fd55cd 1 1 1 4m22s
NAME READY AGE
statefulset.apps/awx-postgres 1/1 4m30s
DNS か hosts
ファイルでホスト名の名前解決をできるようにして、ブラウザで HTTPS でアクセスすると、ログイン画面が表示され、ユーザ名 admin
と指定したパスワードでログインできます。
楽しいですね。
管理用パスワードを事前に指定しなかった場合は、シークレットの値をデコードして取得できます。
$ kubectl get secret awx-admin-password -o jsonpath="{.data.password}" -n awx | base64 --decode
Mp1UtHgMqxRnDGzcz0fy3e4RBePgL96S
簡易バックアップと簡易リストア
AWX Operator の 0.10.0
からは、組み込みで バックアップ と リストア の機能が追加されています。必要なファイル一式を少しの操作でひとつのフォルダにまとめてくれるうえ、リストアも全自動なので、バックアップやリストアを行いたいときは基本的にはこれの利用がおすすめです。使い方は別エントリで紹介しています。
何らかの理由で AWX Operator の機能を使わずにすべてを手作業で行いたい場合は、
- デプロイに利用したファイル一式
- 証明書と秘密鍵を含む
- 二つの PV のまるごとの中身
/data/postgres
と/data/projects
- 自動生成されたシークレットキー
<インスタンス名>-secret-key
で自動作成されるシークレットkubectl -n awx get secret awx-secret-key -o yaml > secret_key.yaml
などで保存しておく
- AWX 内で
/etc/tower/SECRET_KEY
として利用され、DB 内の機微情報(Credential など)の暗号化や複合化に使われる
の保持を考えます。これらが維持できれば、極論、K3s をアンインストールしても、元のファイルを元のパスに置いて作り直せば同じ環境に戻せます。
# シークレットキーの保存
kubectl -n awx get secret awx-secret-key -o yaml > secret_key.yaml
# 環境全体のアンインストール
/usr/local/bin/k3s-uninstall.sh
# 環境全体の再インストール・再デプロイ
curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644
kubectl apply -f https://raw.githubusercontent.com/ansible/awx-operator/0.10.0/deploy/awx-operator.yaml
kubectl create namespace awx
kubectl apply -f secret_key.yaml
kubectl apply -k .
PostgreSQL の PV は、静止点が取りにくければ、素直に pg_dump
でもよいですね。
kubectl exec awx-postgres-0 -n awx -- sh -c 'pg_dump -c --if-exists -U $POSTGRES_USER' > dump.sql
リストアするには、awx
リソースの replicas
を 0
にして、PostgreSQL だけを残して AWX を止めてからがよさそうです。
kubectl patch awx awx -n awx -p '{"spec": {"replicas": 0}}' --type=merge
kubectl exec -i awx-postgres-0 -n awx -- sh -c 'psql -U $POSTGRES_USER' < dump.sql
kubectl patch awx awx -n awx -p '{"spec": {"replicas": 1}}' --type=merge
まとめ
軽量 Kubernetes ディストリビューションの K3s を使って AWX をホストする方法を紹介しました。パスワードを固定してしまうのは少し乱暴ではありますが、その分少しだけ取り回しはしやすくなっています。
前述の通り、0.10.0
から追加された AWX Operator 組み込みのバックアップとリストアは、別のエントリ で取り扱っています。手作業よりは圧倒的にラクなので、併せて使うと便利です。
Hi,
Thanks for this tutorial, I’d managed to have AWX ingress run perfectly – I have some clarifications on the volumes. I can see that the PV are both status “bound” using “k3s kubectl get pv” – however, I can’t see any PVCs using the “k3s kubectl get pvc” it only says “No resources found in default namespace”. Tried to run sample AWX playbook, whenever I tried to save files onto the “hosts: localhost” – it gives me a denied permission error on the file path: /data/projects.
Appreciate your response on this.
thanks.
Wow sry for the late reply. The PVC is the namespace-dependent resource, therefore you should specify correct namespace by “-n awx” or “–namespace=awx” for “kubectl” command, e.g. “k3s kubectl -n awx get pvc”.