AWX on Kubernetes/OpenShift

    Ansible AWX provides a RESTful API, web interface and a task engine that is built on top of Ansible. It is the upstream project for Red Hat Ansible Automation Platform.

    Persistent Volume

    We need storage to persist AWX data. There is no limitation on the type of storage that has already been integrated with the OpenShift or K8 cluster.

    Storage class

    A K8 StorageClass describes and classifies storage that can be requested, as well as provides a means for passing parameters for dynamically provisioned storage on demand – it abstract the details of underlying storage in a simple fashion.

    Query the current storage classes from your cluster:

    oc get sc
    NAME                                  PROVISIONER                                 RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
    cephfs                                                   Delete          Immediate              false                  712d
    nfs                                   cluster.local/wso2-nfs-server-provisioner   Delete          Immediate              true                   49d
    ocs-storagecluster-cephfs (default)       Delete          Immediate              true                   299d


    In our case, we shall use ocs-storagecluster-cephfs (default) StorageClass.


    Make Tools and Git

    Ensure that you have installed Git and Make Tools on your bastion host that you’re using to interact with your OpenShift/K8 cluster.

    RHEL based systems

    #RHEL based systems #
    sudo yum install curl jq
      git.x86_64 0:                                                                                                                                      
    Dependency Updated:
      perl-Git.noarch 0:                                                                                                                                 

    Dev Tools

    sudo yum group install "Development Tools"
    Installing for group install "Development Tools":
     bison                                         x86_64                          3.0.4-2.el7                                    base                             674 k
     byacc                                         x86_64                          1.9.20130304-3.el7                             base                              65 k
     cscope                                        x86_64                          15.8-10.el7                                    base                             203 k
     ctags                                         x86_64                          5.8-13.el7                                     base                             155 k
     diffstat                                      x86_64                          1.57-4.el7                                     base                              35 k
     doxygen                                       x86_64                          1:1.8.5-4.el7                                  base                             3.6 M
      bison.x86_64 0:3.0.4-2.el7            byacc.x86_64 0:1.9.20130304-3.el7                 cscope.x86_64 0:15.8-10.el7           ctags.x86_64 0:5.8-13.el7           
      diffstat.x86_64 0:1.57-4.el7          doxygen.x86_64 1:1.8.5-4.el7                      elfutils.x86_64 0:0.176-5.el7         flex.x86_64 0:2.5.37-6.el7          
      gcc-gfortran.x86_64 0:4.8.5-44.el7    indent.x86_64 0:2.2.11-13.el7                     intltool.noarch 0:0.50.2-7.el7        patchutils.x86_64 0:0.3.3-5.el7_9   
      rcs.x86_64 0:5.9.0-7.el7              redhat-rpm-config.noarch 0:9.1.0-88.el7.centos    rpm-build.x86_64 0:4.11.3-48.el7_9    rpm-sign.x86_64 0:4.11.3-48.el7_9   
      subversion.x86_64 0:1.7.14-16.el7     swig.x86_64 0:2.0.10-5.el7                        systemtap.x86_64 0:4.0-13.el7        
    Dependency Installed:
      boost-date-time.x86_64 0:1.53.0-28.el7                    bzip2.x86_64 0:1.0.6-13.el7                           dwz.x86_64 0:0.11-3.el7                           
      dyninst.x86_64 0:9.3.1-3.el7                              efivar-libs.x86_64 0:36-12.el7                        emacs-filesystem.noarch 1:24.3-23.el7_9.1         
      gdb.x86_64 0:7.6.1-120.el7                                gettext-common-devel.noarch 0:          gettext-devel.x86_64 0:             
      kernel-debug-devel.x86_64 0:3.10.0-1160.95.1.el7          libdwarf.x86_64 0:20130207-4.el7                      libgfortran.x86_64 0:4.8.5-44.el7                 
      libmodman.x86_64 0:2.0.1-8.el7                            libproxy.x86_64 0:0.4.11-11.el7                       libquadmath.x86_64 0:4.8.5-44.el7                 
      libquadmath-devel.x86_64 0:4.8.5-44.el7                   mokutil.x86_64 0:15-8.el7                             neon.x86_64 0:0.30.0-4.el7                        
      pakchois.x86_64 0:0.4-10.el7                              perl-XML-Parser.x86_64 0:2.41-10.el7                  perl-srpm-macros.noarch 0:1-8.el7                 
      python-srpm-macros.noarch 0:3-34.el7                      subversion-libs.x86_64 0:1.7.14-16.el7                systemtap-client.x86_64 0:4.0-13.el7              
      systemtap-devel.x86_64 0:4.0-13.el7                       systemtap-runtime.x86_64 0:4.0-13.el7                



    ### Debian / Ubuntu ###
    sudo apt update
    sudo apt install git build-essential curl jq  -y


    AWX Installation on OpenShift/K8

    Download the AWX Operator

    git clone to download the operator to your host.

    [root@svdt8bastion ~]# git clone
    Cloning into 'awx-operator'...
    remote: Enumerating objects: 9223, done.
    remote: Counting objects: 100% (1938/1938), done.
    remote: Compressing objects: 100% (287/287), done.
    remote: Total 9223 (delta 1745), reused 1702 (delta 1647), pack-reused 7285
    Receiving objects: 100% (9223/9223), 2.47 MiB | 0 bytes/s, done.
    Resolving deltas: 100% (5331/5331), done.


    Create AWX namespace


    export NAMESPACE=ansible-awx
    oc create ns ${NAMESPACE}



    export NAMESPACE=ansible-awx
    kubectl create ns ${NAMESPACE}


    Switch to the created namespace

    # oc project ${NAMESPACE}
    Now using project "ansible-awx" on server "".


    Release tag

    AWX_RELEASE_TAG=curl -s | grep tag_name | cut -d '"' -f 4 ;
    git checkout $AWX_RELEASE_TAG


    Expected output

    # git checkout $AWX_RELEASE_TAG
    Note: checking out '2.5.2'.
    You are in 'detached HEAD' state. You can look around, make experimental
    changes and commit them, and you can discard any commits you make in this
    state without impacting any branches by performing another checkout.
    If you want to create a new branch to retain commits you create, you may
    do so (now or later) by using -b with the checkout command again. Example:
      git checkout -b new_branch_name
    HEAD is now at 7012a6a... Modify how pg password is set in postgres pod (#1540)


    Deploy AWS operator to the OpenShift/K8s cluster

    export NAMESPACE=ansible-awx
    make deploy


    Expected output

    usage: git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]
                         [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]
    Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
    namespace/ansible-awx configured configured configured configured
    serviceaccount/awx-operator-controller-manager created created created unchanged unchanged created created configured
    configmap/awx-operator-awx-manager-config created
    service/awx-operator-controller-manager-metrics-service created
    deployment.apps/awx-operator-controller-manager created


    After successful deployment of the operator, check the running pods

    oc get po
    NAME                                               READY   STATUS                   RESTARTS   AGE
    awx-operator-controller-manager-6544864fcd-rdpzr   2/2     Running                  0          2m12s
    awx-operator-controller-manager-6544864fcd-sb6sm   0/2     ContainerStatusUnknown   2          3m48s


    Install AWX on OpenShift


    cat <<EOF | kubectl create -f -
    apiVersion: v1
    kind: PersistentVolumeClaim
      name: awx-data-pvc
      namespace: ansible-awx
        - ReadWriteMany
      storageClassName: ocs-storagecluster-cephfs
          storage: 10Gi


    Expected output

    persistentvolumeclaim/awx-data-pvc created


    PVC created successfully

    oc get pvc
    NAME           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS                AGE
    awx-data-pvc   Bound    pvc-8ea4b8c1-535e-4bcc-b129-95e6b6e2268e   10Gi       RWX            ocs-storagecluster-cephfs   94s


    Create AWX deployment File

    Lets deploy AWX instance by creating an ansible-awx.yaml file with following content.

    vim ansible-awx-deployment.yaml

    kind: AWX
      name: ansible-awx
      service_type: ClusterIP
      projects_persistence: true
      projects_storage_access_mode: ReadWriteMany
      web_extra_volume_mounts: |
        - name: static-data
          mountPath: /var/lib/projects
      extra_volumes: |
        - name: static-data
            claimName:  awx-data-pvc



    #  oc apply -f ansible-awx-deployment.yaml created


    Check pods

    oc get po
    NAME                                               READY   STATUS    RESTARTS   AGE
    ansible-awx-postgres-13-0                          1/1     Running   0          14h
    ansible-awx-task-675bb6846d-7lhgj                  4/4     Running   0          13h
    ansible-awx-web-66d967d896-7h7tk                   3/3     Running   0          12h
    awx-operator-controller-manager-6544864fcd-rdpzr   2/2     Running   0          21h



    Access AWX Container Shell

    Get the deployment

    oc get deployment
    NAME                              READY   UP-TO-DATE   AVAILABLE   AGE
    ansible-awx-task                  1/1     1            1           16h
    ansible-awx-web                   1/1     1            1           16h
    awx-operator-controller-manager   1/1     1            1           21h


    Access container shell


    oc exec -ti deploy/ansible-awx-task -c  ansible-awx-task -- /bin/bash
    oc exec -ti deploy/ansible-awx-web -c  ansible-awx-web -- /bin/bash


    Expose the AWX service

    A K8 service is an abstraction layer that defines a logical set of pods and enables external traffic exposure, service discovery and load balancing for those pods.

    Check the services in the ansible-awx namespace. Take a keen interest in the ansible-awx-service through the ClusterIP.

    oc get svc
    NAME                                              TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
    ansible-awx-postgres-13                           ClusterIP   None             <none>        5432/TCP   2d18h
    ansible-awx-service                               ClusterIP    <none>        80/TCP     2d18h
    awx-operator-controller-manager-metrics-service   ClusterIP   <none>        8443/TCP   2d22h


    At this stage, the assumption is that you already have an OpenShift/K8 cluster with an ingress controller. We can epose the servie through a route using the ingress .

    Check the DNS records for the OpenShift ingress.

    # nslookup *
    Server:		xx.xx.xx.xx
    Address:	xx.xx.xx.xx#53
    Name:	*


    To display your default OpenShift ingress domain, run the following command:

    # oc get ingresses.config/cluster -o jsonpath={.spec.domain}


    Create route configuration manifest for AWX. A route allows us to host our application(AWX) at a public URL.

    Please note the following elements in the manifest:

        kind: Service
        name: ansible-awx-service
        weight: 100
        targetPort: http


    YAML AWX Route Manifest Definition:

    kind: Route
      name: ansible-awx
        - manager: OpenAPI-Generator
          operation: Update
          fieldsType: FieldsV1
        - manager: openshift-router
          operation: Update
      namespace: ansible-awx
      labels: awx awx-operator 2.2.1 ansible-awx
        kind: Service
        name: ansible-awx-service
        weight: 100
        targetPort: http
        termination: edge
        insecureEdgeTerminationPolicy: Redirect
      wildcardPolicy: None
        - host:
          routerName: default
          wildcardPolicy: None


    Deploy the route yaml file

    oc apply -f awx-route.yaml created


    Validate the created route

    oc get routes
    NAME                  HOST/PORT                                                   PATH   SERVICES              PORT   TERMINATION     WILDCARD
    ansible-awx                               ansible-awx-service   http   edge/Redirect   None
    ansible-awx-service          ansible-awx-service   http                   None


    Access the AWX Web console

    Access the web console from the URL above: .

    AWX Dashboard
    AWX Dashboard

    Extract the admin password

    From your namespace, lets extract the admin password

    # oc get secrets | grep -i admin-password
    ansible-awx-admin-password                        Opaque                                1      18h


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

    Use the password displayed to login to the Dashboard

    Username : admin

    Password : <password>

    Recent Articles

    Related Articles

    Leave A Reply

    Please enter your comment!
    Please enter your name here