Ansible Kubernetes

In this section, you’ll learn the following:

  • How Ansible connects with Kubernetes

  • Deploying Applications to Kubernetes using Ansible

  • Using Ansible Templates as Kubernetes manifests

  • Deleting Kubernetes Resources

Ansible and Kubernetes

Ansible provides an Ansible Kubernetes Collection to interact with a Kubernetes cluster. With these collections, you get the same approach of maintaining more traditional workloads like virtual machines, but for Kubernetes.

The first thing you need to do is create a Kubernetes cluster. You can use any Kubernetes cluster you might have available (minikube, K3s, EKS, AKS, OpenShift, …​) but since there are many options we’ll focus on Red Hat Developers Sandbox a free cloud Kubernetes-OpenShift cluster ready to use, so no local installation is required.

Setup Red Hat Developer Sandbox

Developer Sandbox for Red Hat OpenShift is a free Kubernetes cloud environment in a shared, multi-tenant OpenShift cluster that is pre-configured with a set of developer tools. The Developer Sandbox is active for 30 days and renewable once it expires.

To create your account, register to Developer Sandbox for Red Hat OpenShift. From there, click on the red button that says Start your sandbox for free as shown in the following image.

Developer Sandbox Sign-up Page

Use your existing Red Hat account or create a new one, then follow the instructions on the screen. You should then be redirected to the Developer Sandbox page again, but this time, you should see a button labelled Start using your sandbox.

Developer Sandbox Start Page

Clicking on it opens up the OpenShift login screen where you can log in using the DevSandbox button, as seen below.

Log in the Developer Sandbox

Clicking this button opens up your new OpenShift cluster console.

Topology View
Quotas and Limits

Your private OpenShift environment on Developer Sandbox includes quotas and limits of:

  • 7 GB RAM

  • 15GB storage

which is enough to run this workshop.

There are one fixed project (namespace):

  • <your_username>-dev

Please work in the <your_username>-dev project.

After Kubernetes is up and running, we install the Kubernetes Collection.

Installing Ansible Kubernetes Collection

First of all, we install the Kubernetes Python dependency:

pip install kubernetes
You must use pip3 instead of pip depending on the environment and version.

Then let’s use Ansible Galaxy to install the collection:

ansible-galaxy collection install kubernetes.core
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://galaxy.ansible.com/download/kubernetes-core-2.4.0.tar.gz to /Users/alexsoto/.ansible/tmp/ansible-local-561757k19pm6z/tmpkia3z432/kubernetes-core-2.4.0-e57tp6bs
Installing 'kubernetes.core:2.4.0' to '/Users/alexsoto/.ansible/collections/ansible_collections/kubernetes/core'
kubernetes.core:2.4.0 was installed successfully
If you get a certificate verify failed exception, run the command with the --ignore-certs option.

Deploy Application to Kubernetes

To deploy the application, a login process is required. The collection supports username/password method, kubeconfig folder, and also the authentication token. For Red Hat Sandbox, we need to use the token approach to login into the cluster and interact with it.

Get the Server Address and the Auth Token

Go to Sandbox main screen, click on your username placed at top-right position, and select the Copy login command option from the drop-down menu.

sandbox initial topology

Then, copy the token and server properties in a temporal file, as we’ll need them later.

sandbox token

Current Namespace

Another important data to know is the working namespace Red Hat Sandbox has assigned to us. It’s in the form of <username>-dev, and you can easily found it in the upper-left corner.

sandbox initial topology ns

This namespace is important too, as it’s where we’ll deploy the application.

With this information, let’s make Ansible deploy the application.

Deploy to Kubernetes

Let’s start with a simple deployment of an already developed application.

In your working directory, create a new directory named kubernetes:

mkdir kubernetes
cd kubernetes

Create the first-kubernetes-playbook.yaml file containing the cluster information and the Kubernetes manifest information to deploy the application:

kubernetes/first-kubernetes-playbook.yaml
- name: Login
  hosts: localhost (1)
  connection: local
  gather_facts: false
  environment:
    K8S_AUTH_HOST: "https://api.sandbox-m2.ll9k.p1.openshiftapps.com:6443" (2)
    K8S_AUTH_API_KEY: "sha256~NRG7aBVOdaRonMJ172H16KrS0Chy--knwpefomLrcZA" (3)
  tasks:
    - name: Deploy The Application
      kubernetes.core.k8s: (4)
        state: present (5)
        definition: (6)
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            namespace: asotobue-dev (7)
            labels:
              app.kubernetes.io/name: hello-world
              app.kubernetes.io/version: 1.0.0-SNAPSHOT
            name: hello-world
          spec:
            replicas: 1
            selector:
              matchLabels:
                app.kubernetes.io/name: hello-world
                app.kubernetes.io/version: 1.0.0-SNAPSHOT
            template:
              metadata:
                labels:
                  app.kubernetes.io/name: hello-world
                  app.kubernetes.io/version: 1.0.0-SNAPSHOT
              spec:
                containers:
                  - env:
                      - name: KUBERNETES_NAMESPACE
                        valueFrom:
                          fieldRef:
                            fieldPath: metadata.namespace
                    image: quay.io/lordofthejars/hello-world:1.0.0-SNAPSHOT
                    imagePullPolicy: Always
                    name: hello-world
                    ports:
                      - containerPort: 8080
                        name: http
                        protocol: TCP
1 The playbook is executed in the local machine
2 Substitute the hostname with your server property
3 Substitute the token with your token property
4 Ansible Kubernetes Collection definition
5 Apply the manifest
6 Set the Kubernetes manifest content
7 Substitute the namespace with your current working namespace

After that, run the following command in the terminal to deploy the application to the Kubernetes cluster:

ansible-playbook first-kubernetes-playbook.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [Login] ***************************************************************************************************************************************************************************************************************

TASK [Deploy The Application] **********************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *****************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

To validate the deployment, access the Red Hat Sandbox Topology view, and check that the application is there up and running:

sandbox first deployment

Clean up the Namespace

To clean up the namespace, we need to undeploy the application.

Create a delete-kubernetes-playbook.yaml file selecting which resource is deleted and setting the state to Absent.

kubernetes/delete-kubernetes-playbook.yaml
- name: Login
  hosts: localhost
  connection: local
  gather_facts: false
  environment:
    K8S_AUTH_HOST: "https://api.sandbox-m2.ll9k.p1.openshiftapps.com:6443" (1)
    K8S_AUTH_API_KEY: "sha256~NRG7aBVOdaRonMJ172H16KrS0Chy--knwpefomLrcZA" # (2)
  tasks:
    - name: Delete The Application
      kubernetes.core.k8s:
        state: absent (3)
        api_version: v1
        kind: Deployment
        namespace: asotobue-dev (4)
        name: hello-world (5)
1 Substitute the hostname with your server property
2 Substitute the token with your token property
3 Delete the resource
4 Substitute the namespace with your current working namespace
5 Name of the deployment

After that, run the following command in the terminal to undeploy the application from the Kubernetes cluster:

ansible-playbook delete-kubernetes-playbook.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [Login] ***************************************************************************************************************************************************************************************************************

TASK [Delete The Application] **********************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *****************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Referencing Kubernetes manifest files

In the previous example, we defined the Kubernetes manifest within the playbook. Although this is possible and it has some advantages, most of the time, you’ll define the resources outside of the playbook. Ansible Kubernetes collection let you reference external Kubernetes files directly in the playbook.

Create a Kubernetes Deployment file named deployment.yaml in kubernetes directory with the following content:

kubernetes/deployment.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: asotobue-dev (1)
  labels:
    app.kubernetes.io/name: hello-world
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  name: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: hello-world
      app.kubernetes.io/version: 1.0.0-SNAPSHOT
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hello-world
        app.kubernetes.io/version: 1.0.0-SNAPSHOT
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: quay.io/lordofthejars/hello-world:1.0.0-SNAPSHOT
          imagePullPolicy: Always
          name: hello-world
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
  namespace: asotobue-dev (2)
  annotations:
    app.quarkus.io/commit-id: 277270f3f2a7b0e78c69b3be83be372c7e6ca693
    app.quarkus.io/build-timestamp: 2023-03-08 - 08:51:15 +0000
  labels:
    app.kubernetes.io/name: hello-world
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  name: hello-world
spec:
  ports:
    - name: http
      port: 80
      protocol: TCP
      targetPort: 8080
  selector:
    app.kubernetes.io/name: hello-world
    app.kubernetes.io/version: 1.0.0-SNAPSHOT
  type: ClusterIP
1 Substitute the namespace with your current working namespace
2 Substitute the namespace with your current working namespace

Then, create the file-kubernetes-playbook.yaml file referencing this manifest instead of defining it on the playbook.

kubernetes/file-kubernetes-playbook.yaml
- name: Login
  hosts: localhost
  connection: local
  gather_facts: false
  environment:
    K8S_AUTH_HOST: "https://api.sandbox-m2.ll9k.p1.openshiftapps.com:6443" (1)
    K8S_AUTH_API_KEY: "sha256~NRG7aBVOdaRonMJ172H16KrS0Chy--knwpefomLrcZA" (2)
  tasks:
    - name: Deploy The Application
      kubernetes.core.k8s:
        state: present
        src: deployment.yaml (3)
1 Substitute the hostname with your server property
2 Substitute the token with your token property
3 Set the location of the Kubernetes manifest to apply

After that, run the following command in the terminal to undeploy the application from the Kubernetes cluster:

ansible-playbook file-kubernetes-playbook.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [Login] ***************************************************************************************************************************************************************************************************************

TASK [Deploy The Application] **********************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *****************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Check the application is running in the Red Hat Sandbox Topology view:

sandbox file deployment

Clean up

To cleanup the namespace, create the delete-all-kubernetes-playbook.yaml:

kubernetes/delete-all-kubernetes-playbook.yaml
- name: Login
  hosts: localhost
  connection: local
  gather_facts: false
  environment:
    K8S_AUTH_HOST: "https://api.sandbox-m2.ll9k.p1.openshiftapps.com:6443" (1)
    K8S_AUTH_API_KEY: "sha256~NRG7aBVOdaRonMJ172H16KrS0Chy--knwpefomLrcZA" (2)
  tasks:
    - name: Delete The Application
      kubernetes.core.k8s:
        state: absent
        api_version: v1
        kind: Deployment
        namespace: asotobue-dev (3)
        name: hello-world
    - name: Delete The Service
      kubernetes.core.k8s:
        state: absent
        api_version: v1
        kind: Service
        namespace: asotobue-dev (4)
        name: hello-world
1 Substitute the hostname with your server property
2 Substitute the token with your token property
3 Substitute the namespace with your current working namespace
4 Substitute the namespace with your current working namespace

And run the playbook:

ansible-playbook delete-all-kubernetes-playbook.yaml

Ansible Templates as Kubernetes manifests

Ansible Kubernetes Collection also integrates with Ansible templates, so you can define Kubernetes manifests as templates.

Create a deployment.j2 file in the kubernetes folder:

kubernetes/deployment.j2
---
apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: asotobue-dev (1)
  labels:
    app.kubernetes.io/name: hello-world
    app.kubernetes.io/version: {{ version }} (2)
  name: hello-world
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: hello-world
      app.kubernetes.io/version: {{ version }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: hello-world
        app.kubernetes.io/version: {{ version }}
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: quay.io/lordofthejars/hello-world:{{ version }}
          imagePullPolicy: Always
          name: hello-world
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
1 Substitute the namespace with your current working namespace
2 Template placeholder

Then, create the template-kubernetes-playbook.yaml file:

kubernetes/template-kubernetes-playbook.yaml
- name: Login
  hosts: localhost
  connection: local
  gather_facts: false
  vars:
    - version: 1.0.0-SNAPSHOT (1)
  environment:
    K8S_AUTH_HOST: "https://api.sandbox-m2.ll9k.p1.openshiftapps.com:6443" (2)
    K8S_AUTH_API_KEY: "sha256~NRG7aBVOdaRonMJ172H16KrS0Chy--knwpefomLrcZA" (3)
  tasks:
    - name: Deploy The Application
      kubernetes.core.k8s:
        state: present
        template: deployment.j2 (4)
1 Set version for the placeholder
2 Substitute the hostname with your server property
3 Substitute the token with your token property
4 Set the template location

Run the playbook:

ansible-playbook template-kubernetes-playbook.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [Login] ***************************************************************************************************************************************************************************************************************

TASK [Deploy The Application] **********************************************************************************************************************************************************************************************
changed: [localhost]

PLAY RECAP *****************************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Check the application is running in the Red Hat Sandbox Topology view:

sandbox template result