Running ansible-playbook from a laptop works for a single operator. The moment
you have a team of 10, or compliance needs an audit trail, or junior engineers need
to launch a deploy without SSH access to production — the CLI hits its limits.
AWX (open source) and Ansible Automation Platform (Red Hat's
commercial version) wrap Ansible with the multi-user infrastructure most teams need.
| AWX (open source) | AAP (commercial) | |
|---|---|---|
| License | Free, Apache 2.0 | Red Hat subscription |
| Support | Community (GitHub issues) | 24×7 Red Hat support |
| Installer | Operator on Kubernetes only | RPM installer · Kubernetes · OpenShift |
| UI / API | Identical | Identical (same codebase) |
| Certified collections | No | Yes — vendor-tested + supported |
| Insights / Analytics | No | Yes — automation analytics dashboard |
| Best for | Internal tooling, labs, learning | Regulated industries, large enterprises |
| Concept | Equivalent on the CLI |
|---|---|
| Project | A git repo containing playbooks/roles |
| Inventory | The same hosts.ini / dynamic inventory |
| Credentials | Vaulted SSH keys, vault passwords, cloud creds — managed centrally |
| Job Template | A pre-configured ansible-playbook invocation |
| Survey | A form attached to a job template — collect input from non-Ansible users |
| Schedule | Cron entries managed in the UI |
| Workflow Template | DAG of job templates with success/failure branches |
| Notification | Slack / email / webhook on job events |
AWX runs natively on Kubernetes via the AWX Operator. Once the operator is
installed, you create a single AWX Custom Resource and the operator does the rest —
deploys PostgreSQL, Redis, the web UI, and the execution pods.
# 1. Clone the operator repo
git clone https://github.com/ansible/awx-operator.git
cd awx-operator
# 2. Pin to a stable release
git checkout 2.19.1
# 3. Install the operator into the awx namespace
export NAMESPACE=awx
make deploy
# 4. Watch the operator pod come up
kubectl -n awx get pods
# NAME READY STATUS RESTARTS
# awx-operator-controller-manager-xxx 2/2 Running 0
---
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
name: awx
namespace: awx
spec:
service_type: NodePort
nodeport_port: 30080
# PostgreSQL — operator deploys & manages
postgres_storage_class: longhorn
postgres_storage_requirements:
requests:
storage: 20Gi
# Web replica count
web_replicas: 2
# Persistent project storage (your git checkouts)
projects_persistence: true
projects_storage_class: longhorn
projects_storage_size: 10Gi
# Default admin password — pulled from a Secret
admin_user: admin
admin_password_secret: awx-admin-password
# Create the admin password secret BEFORE applying the AWX CR
kubectl -n awx create secret generic awx-admin-password \
--from-literal=password="$(openssl rand -base64 24)"
# Apply the AWX CR (operator creates DB, redis, web, task pods)
kubectl apply -f awx.yml
# Wait ~5 minutes — watch progress
kubectl -n awx get pods -w
# Pull the admin password back out
kubectl -n awx get secret awx-admin-password \
-o jsonpath="{.data.password}" | base64 -d
# Browse to: http://<node-ip>:30080
Click-ops in AWX is a trap — within a year the UI state drifts from what's in git.
The awx.awx collection lets you declare every project, inventory, credential,
and job template in YAML and apply it via Ansible. The UI then becomes read-only and
audit-friendly.
---
- name: Configure AWX from code
hosts: localhost
gather_facts: false
collections:
- awx.awx
tasks:
- name: Create the organisation
organization:
name: Vriddh-DBA
description: Database team
state: present
- name: Register the playbook git repo as a Project
project:
name: db-automation
organization: Vriddh-DBA
scm_type: git
scm_url: git@github.com:vriddh/db-automation.git
scm_branch: main
scm_credential: github-deploy-key
scm_update_on_launch: true # always pull latest before each job
- name: Define the production inventory (sourced from project)
inventory:
name: production
organization: Vriddh-DBA
- name: Add SSH credential
credential:
name: ssh-deploy
organization: Vriddh-DBA
credential_type: Machine
inputs:
username: deploy
ssh_key_data: "{{{{ lookup('file', 'deploy_key') }}}}"
- name: Add Vault credential
credential:
name: vault-prod
organization: Vriddh-DBA
credential_type: Vault
inputs:
vault_password: "{{{{ vault_prod_password }}}}"
vault_id: prod
- name: Create the rolling-restart job template
job_template:
name: rolling_mysql_restart
project: db-automation
playbook: playbooks/rolling_restart_mysql.yml
inventory: production
credentials:
- ssh-deploy
- vault-prod
ask_variables_on_launch: true
- name: Schedule a nightly backup
schedule:
name: nightly_backups
unified_job_template: nightly_db_backup
rrule: "DTSTART:20260101T020000Z RRULE:FREQ=DAILY"
A junior on-call doesn't need to know Ansible vars. They click "Run rolling restart",
fill out a 2-question form (which environment? which database?), hit submit. AWX runs
the playbook with their answers as extra_vars:
---
- name: Add a survey to the rolling-restart job template
awx.awx.job_template:
name: rolling_mysql_restart
survey_enabled: true
survey_spec:
name: Rolling MySQL Restart
description: Drains, restarts, and verifies one host at a time.
spec:
- question_name: Target environment
variable: target_env
type: multiplechoice
choices:
- dev
- staging
- production
required: true
- question_name: Restart all replicas or just one?
variable: serial_count
type: multiplechoice
choices: ["1", "all"]
default: "1"
required: true
- question_name: Reason for restart (audit log)
variable: change_reason
type: text
required: true
For multi-step changes (deploy app, run migrations, restart services, run smoke tests), a workflow template chains job templates with success / failure branches:
---
- name: Define release workflow
awx.awx.workflow_job_template:
name: full_release
organization: Vriddh-DBA
workflow_nodes:
- identifier: deploy_code
unified_job_template:
name: deploy_app
type: job_template
- identifier: run_migrations
unified_job_template:
name: run_db_migrations
type: job_template
related:
success_nodes: []
failure_nodes: []
parents:
- identifier: deploy_code # only after deploy_code succeeds
- identifier: rolling_restart
unified_job_template:
name: rolling_mysql_restart
type: job_template
related:
parents:
- identifier: run_migrations
- identifier: smoke_tests
unified_job_template:
name: app_smoke_tests
type: job_template
related:
parents:
- identifier: rolling_restart
- identifier: rollback
unified_job_template:
name: emergency_rollback
type: job_template
related:
parents:
- identifier: smoke_tests
run: failure # fires only on failure
| Role | What they can do |
|---|---|
| System Administrator | Everything · global |
| Organisation Admin | All resources within an org |
| Project Admin | Edit a specific project's job templates |
| Inventory Admin | Manage one inventory |
| Job Template Executor | Launch (but not edit) a specific job template |
| Auditor | Read-only access to logs and configs |