Background
Ansible AWX provides an open-source, web-based user interface, REST API, and task engine built on top of Ansible. It is one of the upstream projects for Red Hat Ansible Automation Platform.
I have been using Ansible AWX for many years, I actually have an 8 year-old video showcasing how Ansible AWX can be used to run an Ansible playbook to automate the Refresh Multiple Oracle 18c databases using ORCA.
Minikube Environment
On my MacBook I have created a Minikube environment using the Podman Desktop to provide a single-node Kubernetes environment for educational purposes.
From the terminal interface
% minikube version
minikube version: v1.39.0
commit: 7a9f6a841470a207de8cf4bafcccee0969d8ba10
% minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
$ minikube kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:32791
CoreDNS is running at https://127.0.0.1:32791/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Kubernetes
Before we start, lets setup an alias for kubectl to avoid having to prefix every command with minikube, for example:
alias kubectl=”minikube kubectl –“
Test kubectl, for example kubectl get nodes
% kubectl get nodes -A
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 23h v1.37.0
% kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
standard (default) k8s.io/minikube-hostpath Delete Immediate false 23h
AWX Operator
The AWX Operator is designed to be deployed into a Kubernetes cluster(s) and can be used to install and manage the lifecycle of an AWX instance in the same namespace.
To get started create a kustomization.yml, the example is for Tag 2.19.1
# kustomization.ymlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: # Find the latest tag here: https://github.com/ansible/awx-operator/releases - github.com/ansible/awx-operator/config/default?ref=2.19.1# Set the namespace for the AWX operatornamespace: awx# Set the image tag for the operatorimages: - name: quay.io/ansible/awx-operator newTag: 2.19.1 - name: gcr.io/kubebuilder/kube-rbac-proxy newName: docker.io/kubebuilder/kube-rbac-proxy newTag: v0.15.0
Use kubectl apply -k . to create the awx namespace, and deploy the AWX Operator into the Kubernetes cluster.
% kubectl apply -k .
namespace/awx created
customresourcedefinition.apiextensions.k8s.io/awxbackups.awx.ansible.com created
customresourcedefinition.apiextensions.k8s.io/awxmeshingresses.awx.ansible.com created
customresourcedefinition.apiextensions.k8s.io/awxrestores.awx.ansible.com created
customresourcedefinition.apiextensions.k8s.io/awxs.awx.ansible.com created
serviceaccount/awx-operator-controller-manager created
role.rbac.authorization.k8s.io/awx-operator-awx-manager-role created
role.rbac.authorization.k8s.io/awx-operator-leader-election-role created
clusterrole.rbac.authorization.k8s.io/awx-operator-metrics-reader created
clusterrole.rbac.authorization.k8s.io/awx-operator-proxy-role created
rolebinding.rbac.authorization.k8s.io/awx-operator-awx-manager-rolebinding created
rolebinding.rbac.authorization.k8s.io/awx-operator-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/awx-operator-proxy-rolebinding created
configmap/awx-operator-awx-manager-config created
service/awx-operator-controller-manager-metrics-service created
deployment.apps/awx-operator-controller-manager created
Wait a few minutes, and check progress…
% kubectl get pods -n awx
NAME READY STATUS RESTARTS AGE
awx-operator-controller-manager-557bcb9b5-n6npz 2/2 Running 0 98s
Wait until the awx-operator pod shows a Running status.
% kubectl -n awx get deployment awx-operator-controller-manager
NAME READY UP-TO-DATE AVAILABLE AGE
awx-operator-controller-manager 1/1 1 1 2m48s
Use kubectl describe pod <pod name> to get more details.
% kubectl describe pod awx-operator-controller-manager-557bcb9b5-n6npz -n awx
And kubectl logs pod/pod name> to see the log.
% kubectl logs pod/awx-operator-controller-manager-557bcb9b5-n6npz -n awx
Note: Use kubectl config set-context –current –namespace=awx to set the default context to awx to avoid having to specify -n awx each time.
Create a new file called awx-instance.yml
# awx-instance.ymlapiVersion: awx.ansible.com/v1beta1kind: AWXmetadata: name: awx namespace: awxspec: service_type: NodePort
And add this to the kustomization.yml file in the resources section. for example:
resources: - github.com/ansible/awx-operator/config/default?ref=<tag> # Add this extra line: - awx-instance.yml
And apply using kubectl apply -k .
% kubectl apply -k .
namespace/awx unchanged
customresourcedefinition.apiextensions.k8s.io/awxbackups.awx.ansible.com unchanged
customresourcedefinition.apiextensions.k8s.io/awxmeshingresses.awx.ansible.com unchanged
customresourcedefinition.apiextensions.k8s.io/awxrestores.awx.ansible.com unchanged
customresourcedefinition.apiextensions.k8s.io/awxs.awx.ansible.com unchanged
serviceaccount/awx-operator-controller-manager unchanged
role.rbac.authorization.k8s.io/awx-operator-awx-manager-role configured
role.rbac.authorization.k8s.io/awx-operator-leader-election-role unchanged
clusterrole.rbac.authorization.k8s.io/awx-operator-metrics-reader unchanged
clusterrole.rbac.authorization.k8s.io/awx-operator-proxy-role unchanged
rolebinding.rbac.authorization.k8s.io/awx-operator-awx-manager-rolebinding unchanged
rolebinding.rbac.authorization.k8s.io/awx-operator-leader-election-rolebinding unchanged
clusterrolebinding.rbac.authorization.k8s.io/awx-operator-proxy-rolebinding unchanged
configmap/awx-operator-awx-manager-config unchanged
service/awx-operator-controller-manager-metrics-service unchanged
deployment.apps/awx-operator-controller-manager unchanged
awx.awx.ansible.com/awx created
After a few seconds, you should see the operator begining to create the new resources:
% kubectl get pods -n awx
NAME READY STATUS RESTARTS AGE
awx-migration-24.6.1-4jq5k 0/1 Completed 0 12m
awx-operator-controller-manager-557bcb9b5-n6npz 2/2 Running 0 4h54m
awx-postgres-15-0 1/1 Running 0 15m
awx-task-5c649c4b99-nrt9z 4/4 Running 0 14m
awx-web-74bf4766b-cgr4g 3/3 Running 0 14m
List Kubernetes services using kubectl get svc
% kubectl get svc -l "app.kubernetes.io/managed-by=awx-operator" -n awx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
awx-postgres-15 ClusterIP None <none> 5432/TCP 119s
awx-service NodePort 10.107.3.88 <none> 80:30619/TCP 72s
Use kubectl logs to check logs
% kubectl logs deployments/awx-operator-controller-manager -c awx-manager -n awx
By default, the awx admin user is admin, obtain the password from the kubernetes awx-admin-password secret, as below:
% kubectl get secret awx-admin-password -n awx -o jsonpath="{.data.password}" | base64 --decode ; echo
jRG41RNCJTCGqIdsVrtCn9UhmIL3tuQN
AWX WebUI Connectivity
We can now test the AWX WebUI using the using Kubernetes awx-service
% minikube service -n awx awx-service
┌───────────┬─────────────┬─────────────┬───────────────────────────┐
│ NAMESPACE │ NAME │ TARGET PORT │ URL │
├───────────┼─────────────┼─────────────┼───────────────────────────┤
│ awx │ awx-service │ http/80 │ http://192.168.49.2:30338 │
└───────────┴─────────────┴─────────────┴───────────────────────────┘
🔗 Starting tunnel for service awx-service.
┌───────────┬─────────────┬─────────────┬────────────────────────┐
│ NAMESPACE │ NAME │ TARGET PORT │ URL │
├───────────┼─────────────┼─────────────┼────────────────────────┤
│ awx │ awx-service │ │ http://127.0.0.1:61446 │
└───────────┴─────────────┴─────────────┴────────────────────────┘
🎉 Opening service awx/awx-service in default browser...
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
Minikube will automatically open a new AWX browser tab, enter a Username of ‘admin‘ and the Password obtained from the awx-admin-password.
And if all has gone well, you should be presented with the AWX Dashboard to start.
Summary
In this blog post I have shared how to install the Ansible AWX Operator on a Mac Laptop with Podman Desktop and Minikube.

