Install AWX on Kubernetes Rocky Linux 9: The Ultimate Step-by-Step Guide
Running Ansible at scale is far smoother with AWX, the open-source upstream of Red Hat’s Ansible Automation Platform. In this guide, you’ll install AWX on Kubernetes Rocky Linux 9 using the AWX Operator for a clean, declarative setup. By the end, you’ll have a secure, reproducible deployment you can upgrade in place.
Why Install AWX on Kubernetes Rocky Linux 9
If you already run Kubernetes on Rocky Linux, consolidating automation there is natural. We’ll install AWX on Kubernetes Rocky Linux 9 so you get containerized orchestration, persistent storage, and easy upgrades managed by the AWX Operator.
Prerequisites
- Rocky Linux 9 host(s) with a running Kubernetes cluster (e.g., v1.29).
kubectl
(kustomize is built intokubectl
).- A default StorageClass (for Postgres and project PVCs).
- Optional but recommended: an Ingress Controller (e.g., NGINX Ingress) and DNS pointing to your Load Balancer/Ingress.
- (If your environment uses a proxy) HTTP/HTTPS proxy variables ready.
Quick Architecture Overview
- AWX Operator (runs in a namespace, reconciles CRDs and manages AWX lifecycles).
- AWX control plane pods:
web
,task
,redis
, plus a managed PostgreSQL (unless you bring an external one). - PVCs for database and
/var/lib/projects
(optional but recommended).
Install the AWX Operator (kustomize)
Create a working directory and the namespace:
kubectl create namespace awx
mkdir -p ~/awx-operator-deploy && cd ~/awx-operator-deploy
Create kustomization.yaml
— this is the correct, working version:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: awx
resources:
- github.com/ansible/awx-operator/config/default?ref=<TAG>
- awx.yaml
images:
- name: quay.io/ansible/awx-operator
newTag: <TAG>
Note: Change <TAG> to match actual version.
Deploy an AWX instance
Create your AWX manifest awx.yaml
. Pick one of the following options.
Option A — NodePort (quick for labs)
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
name: awx
spec:
service_type: NodePort
nodeport_port: 30080
projects_persistence: true
projects_storage_size: 20Gi
Apply:
kubectl apply -k .
kubectl -n awx get pods -w
Access via: http://<any-node-ip>:30080/
Option B — Ingress + TLS (recommended)
Create secrets (admin and secret key). If you’re not using cert-manager, create a TLS secret too.
# Admin password (optional; otherwise operator generates one)
kubectl -n awx create secret generic awx-admin-password \
--from-literal=password='<a-very-strong-password>'
# Symmetric secret key for DB encryption (persist between upgrades)
kubectl -n awx create secret generic awx-secret-key \
--from-literal=secret_key="$(openssl rand -hex 32)"
# If you do NOT use cert-manager, bring your own TLS certs:
# kubectl -n awx create secret tls awx-tls --key privkey.pem --cert fullchain.pem
Now awx.yaml
:
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
name: awx
spec:
service_type: ClusterIP
ingress_type: ingress
ingress_class_name: nginx
ingress_hosts:
- hostname: awx.example.com
# tls_secret: awx-tls # uncomment if you're NOT using cert-manager
admin_user: admin
admin_password_secret: awx-admin-password
secret_key_secret: awx-secret-key
# Persist project data (recommended)
projects_persistence: true
projects_storage_size: 20Gi
# projects_storage_class: <your-sc> # omit to use cluster default
Apply:
kubectl apply -k .
kubectl -n awx get pods,svc,ingress
Access via: https://awx.example.com/
First Login (admin credentials)
If you didn’t set awx-admin-password
, retrieve the auto-generated one:
kubectl -n awx get secret awx-admin-password -o jsonpath="{.data.password}" | base64 -d; echo
- Username:
admin
- Password: (the value from the secret above or the one you set)
Upgrades & backups
- Upgrade: bump the AWX Operator tag in
kustomization.yaml
(it maps to a compatible AWX version), thenkubectl apply -k .
. - Backups: the operator ships
AWXBackup
/AWXRestore
CRDs. Before major changes (e.g., Postgres jumps), take anAWXBackup
.
Troubleshooting cheatsheet
- Watch rollout:
kubectl -n awx get awx awx -o yaml | sed -n '/status:/,$p' kubectl -n awx get events --sort-by=.lastTimestamp | tail -n 50 kubectl -n awx get pods -w
- PVC stuck in
Pending
:kubectl -n awx get pvc kubectl get storageclass kubectl annotate storageclass <your-sc> storageclass.kubernetes.io/is-default-class="true" --overwrite
- ImagePullBackOff: check registry connectivity and, if needed, proxy settings above.
- Ingress 404: confirm
ingress_class_name
, DNS, and that your Ingress Controller is running.
Useful external references:
- AWX Operator releases: https://github.com/ansible/awx-operator/releases
- Kubernetes StorageClass: https://kubernetes.io/docs/concepts/storage/storage-classes/
- NGINX Ingress Controller: https://kubernetes.github.io/ingress-nginx/