AWX (Ansible Tower)
Kubernetes YAML
apiVersion: v1
kind: Pod
metadata:
name: awx
labels:
app: awx
spec:
restartPolicy: Always
containers:
- name: awx-web
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
ports:
- containerPort: 8052
hostPort: 8052
env:
- name: DATABASE_USER
value: awx
- name: DATABASE_PASSWORD
value: IdXf8mOflAcfp_POzik4OA
- name: DATABASE_NAME
value: awx
- name: DATABASE_HOST
value: 127.0.0.1
- name: DATABASE_PORT
value: '5432'
- name: REDIS_HOST
value: 127.0.0.1
- name: REDIS_PORT
value: '6379'
- name: SECRET_KEY
value: ocABFzu5DW8SVQJkTrdRbA
- name: AWX_ADMIN_USER
value: admin
- name: AWX_ADMIN_PASSWORD
value: IdXf8mOflAcfp_POzik4OA
volumeMounts:
- name: vol-0
mountPath: /etc/tower
- name: vol-1
mountPath: /etc/nginx
- name: vol-2
mountPath: /var/lib/awx/projects
command:
- /bin/sh
args:
- -c
- until python3 -c "import socket;s=socket.create_connection(('${DATABASE_HOST:-127.0.0.1}',${DATABASE_PORT:-5432}),1);s.close()"
2>/dev/null; do echo 'Waiting for postgres...'; sleep 3; done && awx-manage
migrate && DJANGO_SUPERUSER_PASSWORD=${AWX_ADMIN_PASSWORD:-IdXf8mOflAcfp_POzik4OA}
awx-manage createsuperuser --noinput --username ${AWX_ADMIN_USER:-admin} --email
admin@localhost 2>/dev/null || true && exec /usr/bin/launch_awx_web.sh
- name: awx-task
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
env:
- name: DATABASE_USER
value: awx
- name: DATABASE_PASSWORD
value: IdXf8mOflAcfp_POzik4OA
- name: DATABASE_NAME
value: awx
- name: DATABASE_HOST
value: 127.0.0.1
- name: DATABASE_PORT
value: '5432'
- name: REDIS_HOST
value: 127.0.0.1
- name: REDIS_PORT
value: '6379'
- name: SECRET_KEY
value: ocABFzu5DW8SVQJkTrdRbA
- name: AWX_ADMIN_USER
value: admin
- name: AWX_ADMIN_PASSWORD
value: IdXf8mOflAcfp_POzik4OA
volumeMounts:
- name: vol-0
mountPath: /etc/tower
- name: vol-2
mountPath: /var/lib/awx/projects
command:
- /usr/bin/launch_awx_task.sh
- name: postgres
image: docker.io/postgres:15
env:
- name: POSTGRES_USER
value: awx
- name: POSTGRES_PASSWORD
value: IdXf8mOflAcfp_POzik4OA
- name: POSTGRES_DB
value: awx
volumeMounts:
- name: vol-3
mountPath: /var/lib/postgresql/data
securityContext:
runAsUser: 999
runAsGroup: 999
- name: redis
image: docker.io/redis:7-alpine
volumeMounts:
- name: vol-4
mountPath: /data
args:
- redis-server
- --appendonly
- 'yes'
initContainers:
# Auto-generated init container — do not edit manually.
# settings.py: required by AWX to read DB/Redis credentials from environment variables above.
# nginx.conf: reverse proxy config for the AWX web UI (port 8052 -> uWSGI on 8050).
# uwsgi.ini: copied directly from the AWX image — updates automatically with new image versions.
- name: awx-init
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
volumeMounts:
- name: vol-0
mountPath: /init-tower
- name: vol-1
mountPath: /init-nginx
command:
- sh
args:
- -c
- cp -r /etc/nginx/. /init-nginx/ && echo aW1wb3J0IG9zCgpEQVRBQkFTRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQVRPTUlDX1JFUVVFU1RTJzogVHJ1ZSwKICAgICAgICAnRU5HSU5FJzogJ2F3eC5tYWluLmRiLnByb2ZpbGVkX3BnJywKICAgICAgICAnTkFNRSc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9OQU1FJywgJ2F3eCcpLAogICAgICAgICdVU0VSJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1VTRVInLCAnYXd4JyksCiAgICAgICAgJ1BBU1NXT1JEJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1BBU1NXT1JEJywgJ2NoYW5nZW1lJyksCiAgICAgICAgJ0hPU1QnOiBvcy5lbnZpcm9uLmdldCgnREFUQUJBU0VfSE9TVCcsICcxMjcuMC4wLjEnKSwKICAgICAgICAnUE9SVCc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9QT1JUJywgJzU0MzInKSwKICAgIH0KfQpBTExPV0VEX0hPU1RTID0gWycqJ10KU0VDUkVUX0tFWSA9IG9zLmVudmlyb24uZ2V0KCdTRUNSRVRfS0VZJywgJ2NoYW5nZW1lJykKREpBTkdPX1JFRElTX0lHTk9SRV9FWENFUFRJT05TID0gVHJ1ZQoKX3JlZGlzX2hvc3QgPSBvcy5lbnZpcm9uLmdldCgnUkVESVNfSE9TVCcsICcxMjcuMC4wLjEnKQpfcmVkaXNfcG9ydCA9IG9zLmVudmlyb24uZ2V0KCdSRURJU19QT1JUJywgJzYzNzknKQpfcmVkaXNfdXJsID0gJ3JlZGlzOi8ve306e30nLmZvcm1hdChfcmVkaXNfaG9zdCwgX3JlZGlzX3BvcnQpCgpDQUNIRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQkFDS0VORCc6ICdhd3gubWFpbi5jYWNoZS5BV1hSZWRpc0NhY2hlJywKICAgICAgICAnTE9DQVRJT04nOiAne30vMScuZm9ybWF0KF9yZWRpc191cmwpLAogICAgfQp9CkNIQU5ORUxfTEFZRVJTID0gewogICAgJ2RlZmF1bHQnOiB7CiAgICAgICAgJ0JBQ0tFTkQnOiAnY2hhbm5lbHNfcmVkaXMuY29yZS5SZWRpc0NoYW5uZWxMYXllcicsCiAgICAgICAgJ0NPTkZJRyc6IHsKICAgICAgICAgICAgJ2hvc3RzJzogWyhfcmVkaXNfaG9zdCwgaW50KF9yZWRpc19wb3J0KSldLAogICAgICAgICAgICAnY2FwYWNpdHknOiAxMDAwMCwKICAgICAgICAgICAgJ2dyb3VwX2V4cGlyeSc6IDE1Nzc4NDc2MCwKICAgICAgICB9CiAgICB9Cn0KQlJPS0VSX1VSTCA9IF9yZWRpc191cmwK
| base64 -d > /init-tower/settings.py && cp /etc/tower/uwsgi.ini /init-tower/uwsgi.ini
&& echo d29ya2VyX3Byb2Nlc3NlcyBhdXRvOwplcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsKcGlkIC90bXAvbmdpbngucGlkOwoKaW5jbHVkZSAvdXNyL3NoYXJlL25naW54L21vZHVsZXMvKi5jb25mOwoKZXZlbnRzIHsKICAgIHdvcmtlcl9jb25uZWN0aW9ucyAxMDI0Owp9CgpodHRwIHsKICAgIGNsaWVudF9ib2R5X3RlbXBfcGF0aCAvdG1wL25naW54LWNsaWVudC1ib2R5OwogICAgcHJveHlfdGVtcF9wYXRoIC90bXAvbmdpbngtcHJveHk7CiAgICBmYXN0Y2dpX3RlbXBfcGF0aCAvdG1wL25naW54LWZhc3RjZ2k7CiAgICB1d3NnaV90ZW1wX3BhdGggL3RtcC9uZ2lueC11d3NnaTsKICAgIHNjZ2lfdGVtcF9wYXRoIC90bXAvbmdpbngtc2NnaTsKICAgIGluY2x1ZGUgL2V0Yy9uZ2lueC9taW1lLnR5cGVzOwogICAgZGVmYXVsdF90eXBlIGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsKICAgIGFjY2Vzc19sb2cgL2Rldi9zdGRvdXQ7CiAgICBzZW5kZmlsZSBvbjsKICAgIGtlZXBhbGl2ZV90aW1lb3V0IDY1OwoKICAgIHNlcnZlciB7CiAgICAgICAgbGlzdGVuIDgwNTIgZGVmYXVsdF9zZXJ2ZXI7CiAgICAgICAgc2VydmVyX25hbWUgXzsKICAgICAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAwOwoKICAgICAgICBsb2NhdGlvbiB+IF4vd2Vic29ja2V0IHsKICAgICAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOjgwNTE7CiAgICAgICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSAkaHR0cF91cGdyYWRlOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gIlVwZ3JhZGUiOwogICAgICAgICAgICBwcm94eV9jb25uZWN0X3RpbWVvdXQgNzVzOwogICAgICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMTIwczsKICAgICAgICB9CgogICAgICAgIGxvY2F0aW9uIC9zdGF0aWMvIHsKICAgICAgICAgICAgYWxpYXMgL3Zhci9saWIvYXd4L3B1YmxpYy9zdGF0aWMvOwogICAgICAgIH0KCiAgICAgICAgbG9jYXRpb24gLyB7CiAgICAgICAgICAgIHV3c2dpX3JlYWRfdGltZW91dCAxMjBzOwogICAgICAgICAgICB1d3NnaV9wYXNzIDEyNy4wLjAuMTo4MDUwOwogICAgICAgICAgICBpbmNsdWRlIC9ldGMvbmdpbngvdXdzZ2lfcGFyYW1zOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLUZvciAkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICAgICAgdXdzZ2lfcGFyYW0gSFRUUF9YX0ZPUldBUkRFRF9GT1IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7CiAgICAgICAgfQogICAgfQp9Cg==
| base64 -d > /init-nginx/nginx.conf
volumes:
- name: vol-0
persistentVolumeClaim:
claimName: awx-tower
- name: vol-1
persistentVolumeClaim:
claimName: awx-nginx
- name: vol-2
persistentVolumeClaim:
claimName: awx-projects
- name: vol-3
persistentVolumeClaim:
claimName: awx-db
- name: vol-4
persistentVolumeClaim:
claimName: awx-redis
Deployment Guide rootless
Prerequisites once as root
0. Install Podman
apt update && apt install -y podman
1. Create user (if not existing)
useradd -m -s /bin/bash passwd
2. Enable linger (service runs after reboot without login)
loginctl enable-linger
Switch to deployment user
su -
Use su - with the dash — this creates a proper login shell as . Without the dash, root environment variables carry over and rootless Podman will not work correctly.
As deployment user
Fix environment for rootless systemd (new users only — skip if already set)
Required once so systemctl --user works in non-login sessions.
cat << 'EOF' >> ~/.bashrc # Fix for systemd user services (rootless Podman/systemctl) export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus EOF source ~/.bashrc
Save the YAML file
mkdir -p ~/.config/containers/ nano ~/.config/containers/awx.yaml
Test the pod (without autostart)
podman play kube ~/.config/containers/awx.yaml # Check status: podman pod ps && podman ps # Stop: podman play kube --down ~/.config/containers/awx.yaml
Create Quadlet .kube file
%h is a systemd home-directory specifier — do not replace it with ~/.
Save to ~/.config/containers/systemd/:
mkdir -p ~/.config/containers/systemd/ nano ~/.config/containers/systemd/awx.kube
Start systemd service
systemctl --user daemon-reload systemctl --user start awx.service
Status & Logs
systemctl --user status awx.service journalctl --user -u awx.service -f podman pod ps podman ps
Enable automatic image updates optional
Requires AutoUpdate=registry in the .kube file. Podman then checks for new images and restarts the pod automatically:
systemctl --user enable --now podman.socket systemctl --user daemon-reload systemctl --user enable --now podman-auto-update.timer # Check status: systemctl --user status podman-auto-update.timer # Trigger manually: podman auto-update
Ports < 1024 (e.g. 80, 443)
Rootless cannot open privileged ports. Solution:
sysctl net.ipv4.ip_unprivileged_port_start=80
Make persistent in /etc/sysctl.d/99-podman.conf.
Containers communicate via localhost
All containers in the pod share the same network namespace. Always use localhost, not container names.
# Correct (e.g. app → db): localhost:5432 # Wrong (doesn't work in a pod): db-container:5432
List open ports
Which ports is the running pod listening on?
podman port awx-pod
Custom DNS for the pod
Set a custom DNS server (e.g. local Pi-hole):
# In YAML under spec.dnsConfig:
spec:
dnsConfig:
nameservers:
- 192.168.1.x
Set volume ownership
Fix permission errors by adjusting UID/GID in the user namespace:
podman unshare chown 1000:1000 /path/to/volume
SELinux volume labels
On SELinux systems (RHEL, Fedora) set the volume suffix:
/host/path:/container/path:Z # private /host/path:/container/path:z # shared
List all volumes
podman volume ls podman volume inspect <volume-name>
Volume backup
Back up data from a named volume:
podman run --rm \ -v <volume-name>:/data:ro \ -v $(pwd):/backup \ busybox tar czf /backup/backup.tar.gz /data
Cleanup
Remove unused images, containers and volumes:
podman system prune -f # containers + images podman image prune -f # untagged images only podman volume prune -f # unused volumes
Manual update
Pull a new image version and restart the pod:
podman pull <image>:<tag> podman play kube --replace \ ~/.config/containers/awx.yaml
Check for outdated images
List local images and test auto-update without applying:
podman images podman auto-update --dry-run
Shell into a running container
podman exec -it awx-<container> /bin/sh # or bash: podman exec -it awx-<container> /bin/bash
Follow live logs
# All containers in the pod: podman pod logs -f awx-pod # Single container: podman logs -f awx-<container>
Pod info & resource usage
podman pod inspect awx-pod podman stats awx-pod
Restart pod without data loss
podman pod restart awx-pod # or via systemd: systemctl --user restart awx.service
Stop & remove pod
podman pod stop awx-pod podman pod rm awx-pod
All in one
podman pod stop awx-pod && podman pod rm awx-pod