Ansible infrastructure-as-code to automate Nginx deployment in Google Kubernetes Cluster (GKE) on Google Cloud Platform (GCP).
Prerequisite
This tutorial is a continuation of my previous article called Automate your Kubernetes Cluster Setup Using Ansible. This article aimed to help you use Ansible¹ to create a Kubernetes Cluster in Google Cloud Platform (GCP)². Therefore, if you didn’t do it already, review the mentioned article before proceeding.
The code used to create this tutorial is available in this repository.
From this point on, I assume you already have an up and running GKE cluster.
Manage Kubernetes Objects with Ansible
We will use the kubernetes.core.k8s³ plugin to manage objects within our GKE cluster. As for our Nginx example, we will work with two Kubernetes objects: Namespace⁴ and Pod⁵.
Ansible Directory Layout
Follow is the directory structure we will be working with through this tutorial.
.
├── LICENSE # license file
├── README.md # main documentation file
└── ansible # top-level folder
├── ansible.cfg # config file
├── create-k8s.yml # playbook to provision env
├── deploy-app-k8s.yml # playbook to deploy Nginx
├── destroy-k8s.yml # playbook to destroy env
├── undeploy-app-k8s.yml # playbook to remove Nginx
├── inventory
│ └── gcp.yml # inventory file
└── roles
├── destroy_k8s # role to remove k8s cluster
│ └── tasks
│ └── main.yml
├── destroy_k8s_deployment # role to remove Nginx
│ └── tasks
│ └── main.yml
├── destroy_network # role to remove VPC
│ └── tasks
│ └── main.yml
├── k8s # role to create k8s cluster
│ └── tasks
│ └── main.yml
├── k8s-deployment # role to deploy Nginx
│ ├── tasks
│ │ └── main.yml
│ └── vars
│ └── main.yml
└── network # role to create VPC
└── tasks
└── main.yml
Ansible Inventory
In the Ansible inventory⁶ file add a variable named namespace.
...
# use the section below to enter k8s namespaces to manage
# this namespace is used in the Deploying an Application section
namespace: nginx
Ansible Roles
Create a new Ansible role⁷ on ansible/roles/k8s-deployment with the following main.yml file under tasks. This role will be responsible for creating the namespace and deploy the Pod with Nginx.
---
- name: Create a k8s namespace
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Namespace
metadata:
name: "{{ namespace }}"
- name: Create k8s pod for nginx
kubernetes.core.k8s:
state: present
definition:
apiVersion: v1
kind: Pod
metadata:
name: "{{ app }}"
namespace: "{{ namespace }}"
labels:
app: "{{ app }}"
spec:
containers:
- name: "{{ app }}"
image: "{{ image }}"
imagePullPolicy: Always
You can group several actions within the same task. In the task file above, it will first create the namespace and then it will create the Pod.
Notice that the kubernetes.core.k8s plugin uses the standard Kubernetes object yaml configuration to create the resources.
Investigating the role directory structure, we noticed that there is a vars folder. We set variables in roles to ensure a value is used in that role and is not overridden by inventory variables.
Refer to Ansible Using Variables documentation for more details.
Create a main.yml file under the vars folder to set the Nginx variables. We are using these values to replace {{ app }} and {{ image }} variables.
---
app: nginx
image: nginx:1.19.9-alpine
Ansible Playbook
The last step is to create an Ansible playbook⁸ to execute the k8s-deployment role. In the ansible folder, I created a file called deploy-app-k8s.yml:
---
- name: deploy application
hosts: localhost
gather_facts: false
environment:
GOOGLE_CREDENTIALS: "{{ credentials_file }}"
roles:
- k8s-deployment
Deploying an application
Execute the following command to deploy the Nginx web-server:
ansible-playbook ansible/deploy-app-k8s.yml -i ansible/inventory/<your-inventory-filename>
Output:
PLAY [deploy application] *****************************************************************
TASK [k8s-deployment : Create a k8s namespace] ******************
changed: [localhost]
TASK [k8s-deployment : Create a k8s service to expose nginx] ****
changed: [localhost]
PLAY RECAP *******************************************************
localhost: ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Accessing the Nginx
Execute the following commands and then access the Nginx using this URL.
export POD_NAME=$(kubectl get pods --namespace nginx -l "app=nginx" -o jsonpath="{.items[0].metadata.name}")
kubectl --namespace nginx port-forward $POD_NAME 8080:80
Cleaning up
To remove all resources created in this tutorial all we need is a role that removes the namespace object created initially.
The ansible/roles/destroy_k8s_deployment role has this configuration.
---
- name: Destroy a k8s namespace
kubernetes.core.k8s:
name: "{{ namespace }}"
api_version: v1
kind: Namespace
state: absent
Execute the following command to remove the Nginx resources created but, keep the Kubernetes cluster:
ansible-playbook ansible/undeploy-app-k8s.yml -i ansible/inventory/<your-inventory-filename>
Output:
PLAY [undeploy application] **************************************
TASK [destroy_k8s_deployment : Destroy a k8s namespace] *********
changed: [localhost]
PLAY RECAP *****************************************************************
localhost: ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Conclusion
This tutorial has demonstrated how to use Infrastructure as Code to deploy an Nginx web-server in a Kubernetes cluster on Google Cloud Platform. With the kubernetes.core.k8s plugin provided by Ansible, it’s possible to manage Kubernetes objects such as Namespaces and Pods using standard Kubernetes object yaml configuration.
Much more is possible with Ansible. Use this tutorial as the first step to manage your Kubernetes objects as code. Access the Ansible Documentation page for more information and to expand your Ansible knowledge and usage.
References
Comments