VOOZH about

URL: https://dev.to/sirisharaju_kamparaju_c9c/deploying-ansible-awx-on-kubernetes-using-helm-6i5

⇱ Deploying Ansible AWX on Kubernetes Using Helm - By Sireesha - DEV Community


In this blog, I'm going to walk you through how I deployed Ansible AWX on a Kubernetes cluster using Helm. This was one of the most hands-on projects I've worked on β€” it involves setting up the K8s cluster from scratch, installing the container runtime, deploying Helm, and finally getting AWX up and running. I also hit a few real errors along the way, so I'll share exactly how I fixed them.
It was one of those projects that looks simple on paper but turns into a chain of small problems once you actually start doing it.
Here's the overall flow I followed:
The goal was pretty straightforward:

  • Set up a Kubernetes cluster on Ubuntu 22.04
  • Install containerd
  • Get Helm working
  • Deploy AWX using the AWX Operator
  • Fix whatever broke along the way (this part took the longest πŸ˜…)

Setting Up the Kubernetes Cluster on Ubuntu 22.04
Before anything else, I want to quickly explain the two types of nodes in a K8s cluster since this matters for the setup:
Master Node β€” manages the control plane, API calls, pods, services, and everything else in the cluster.
Worker Node β€” runs the actual containers. Pods can spread across multiple worker nodes for better resource management.
Step 1 β€” Update and Upgrade (All Nodes)
I started by logging in as root and running updates on all nodes:

hostnamectl set-hostname siri-awx-01 # run on master node
hostnamectl set-hostname siri-awx-02 # run on worker node
exec bash


apt update
apt upgrade

Step 2 β€” Disable Swap


swapoff -a
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

Step 3 β€” Load Kernel Modules

tee /etc/modules-load.d/containerd.conf <<EOF
overlay
br_netfilter
EOF


modprobe overlay
modprobe br_netfilter

Step 4 β€” Configure Kernel Parameters
tee /etc/sysctl.d/kubernetes.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

sysctl --system

Installing Containerd Runtime (All Nodes)
apt install -y curl gnupg2 software-properties-common apt-transport-https ca-certificates

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/docker.gpg

add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

apt update
apt install -y containerd.io

containerd config default | sudo tee /etc/containerd/config.toml >/dev/null 2>&1
sed -i 's/SystemdCgroup \= false/SystemdCgroup \= true/g' /etc/containerd/config.toml

systemctl restart containerd
systemctl enable containerd

πŸ‘

Installing Kubernetes Components (All Nodes)
`sudo apt-get install -y apt-transport-https ca-certificates curl gpg

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg`

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

πŸ‘

πŸ‘

πŸ‘

Initialising the Cluster (Master Node β€” siri-awx-01 Only)

systemctl enable kubelet && systemctl start kubelet
kubeadm init

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

Tip: If you forget to save the kubeadm join output, regenerate it with:
bashkubeadm token create --print-join-command

$kubectl get nodes

πŸ‘

Join Worker Node (siri-awx-02)
Run this on siri-awx-02 (use your actual token from kubeadm init output):

kubeadm join 192.168.237.144:6443 --token uhkvxh.mjp6aiyhy18vaxh0 \
--discovery-token-ca-cert-hash sha256:c0200907cc68957eea6d9cc4ad314282fb58ac92bceef2416e8212040441f130

Install Calico Network Plugin (siri-awx-01 Only)

curl https://raw.githubusercontent.com/projectcalico/calico/v3.28.0/manifests/calico.yaml -O
kubectl apply -f calico.yaml
kubectl get nodes
kubectl get pods -n kube-system

πŸ‘

πŸ‘

πŸ‘

Installing Helm

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

πŸ‘

Deploying Ansible AWX Using Helm

helm install ansible-awx-operator awx-operator/awx-operator -n awx --create-namespace
kubectl get pods -n awx

πŸ‘

πŸ‘

Setting Up Storage β€” StorageClass, PV and PVC
local-storage-class.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
namespace: awx
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

πŸ‘

kubectl create -f local-storage-class.yaml
kubectl get sc -n awx

πŸ‘

pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
 name: postgres-pv
 namespace: awx
spec:
 capacity:
 storage: 2Gi
 volumeMode: Filesystem
 accessModes:
 - ReadWriteOnce
 persistentVolumeReclaimPolicy: Delete
 storageClassName: local-storage
 local:
 path: /mnt/storage # Mount point should available on worker node
 nodeAffinity:
 required:
 nodeSelectorTerms:
 - matchExpressions:
 - key: kubernetes.io/hostname
 operator: In
 values:
 - siri-awx-02 # worker node hostname

πŸ‘

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: postgres-13-ansible-awx-postgres-13-0
 namespace: awx
spec:
 storageClassName: local-storage
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 2Gi

πŸ‘

kubectl apply -f pv.yaml
kubectl create -f pvc.yaml
kubectl get pv,pvc -n awx

πŸ‘

Deploying AWX

`kubectl create -f ansible-awx.yaml

kubectl logs -f deployments/awx-operator-controller-manager -c awx-manager -n awx
`

πŸ‘

πŸ‘

Accessing the AWX Web Interface

kubectl expose deployment ansible-awx-web --name ansible-awx-web-svc --type NodePort -n awx
kubectl get svc ansible-awx-web-svc -n awx

Get admin password

kubectl get secret ansible-awx-admin-password -o jsonpath="{.data.password}" -n awx | base64 --decode ; echo

πŸ‘

AWX is now accessible at http://: β€” in my case port 32418. Log in with username admin and the decoded password.

πŸ‘

πŸ‘

πŸ‘

πŸ‘

πŸ‘

Errors I Hit and How I Fixed Them
Error 1 β€” Node Taint Issue (Pods Stuck in Pending)

Warning FailedScheduling 2m37s default-scheduler

0/1 nodes are available: 1 node(s) had untolerated taint
{node.kubernetes.io/not-ready: }

First, check the actual taint on your node:
kubectl describe node siri-awx-01 | grep Taints

Taints: node.kubernetes.io/not-ready:NoSchedule

Remove it

kubectl taint nodes siri-awx-01 node.kubernetes.io/not-ready:NoSchedule-

node/siri-awx-01 untainted

After removing the correct taint, pods started coming up properly.

Error 2 β€” ImagePullSecret Error
FailedToRetrieveImagePullSecret Unable to retrieve some image pull secrets
(redhat-operators-pull-secret); attempting to pull the image may not succeed.

Debug with:
kubectl logs awx-operator-controller-manager-6586fccbdd-xtdvj -n awx
kubectl get events -n awx

Fix β€” edit the deployment and comment out the imagePullSecrets section:

kubectl edit deployment awx-operator-controller-manager -n awx
Kubernetes automatically picks up the changes. No manual restart needed.
Accessing the AWX Web Interface

kubectl expose deployment ansible-awx-web --name ansible-awx-web-svc --type NodePort -n awx
kubectl get svc ansible-awx-web-svc -n awx

Get admin password

kubectl get secret ansible-awx-admin-password -o jsonpath="{.data.password}" -n awx | base64 --decode ; echo

Final Verification
Once logged in, I ran a demo playbook to make sure everything was wired up correctly. Seeing that first successful job run in the AWX UI after all of this setup was genuinely satisfying.

This wasn’t a smooth β€œfollow steps β†’ done” kind of project.

It was more like:

set up cluster β†’ something breaks
fix networking β†’ something else breaks
fix storage β†’ something else breaks again
finally get AWX running β†’ feels like victory

But I did learn a lot about how Kubernetes actually behaves when things aren’t ideal.

If you’re doing this yourself and hit weird issues, you’re probably not aloneβ€”most of the fixes I found were pieced together from random threads and trial-and-error.

Still worth it though.

  • happy to help! β€” Sireesha