Full CI/CD with Terraform & Kubernetes on Azure

Below is a detailed, step‐by‐step guide for a "Full CI/CD with Terraform & Kubernetes on Azure" project. This project demonstrates how to provision an Azure Kubernetes Service (AKS) cluster using Terraform, deploy a containerized application onto the cluster using Kubernetes manifests, and automate the deployment process with a CI/CD pipeline using GitHub Actions.


Project Overview

Objectives:

  • Use Terraform to provision an AKS cluster on Azure.

  • Deploy a containerized application (e.g., a simple Nginx deployment) on the AKS cluster.

  • Set up a CI/CD pipeline using GitHub Actions to automate build and deployment.

Tools & Technologies:

  • Terraform (Infrastructure as Code)

  • Azure Kubernetes Service (AKS)

  • Docker & Kubernetes (Containerization & Orchestration)

  • GitHub Actions (CI/CD Automation)

  • Azure CLI


Step 1: Provision an AKS Cluster with Terraform

1.1. Create a Project Directory

Open your terminal and run:

mkdir terraform-aks-ci-cd
cd terraform-aks-ci-cd

1.2. Create Your Terraform Configuration File

Create a file named main.tf and paste the following code. This configuration will:

  • Create a resource group.

  • Provision an AKS cluster with a default node pool.

  • Output the Kubernetes configuration for later use.

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.23.0"
    }
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.0"
    }
  }
}

provider "azurerm" {
  features {}
}

# Create a Resource Group
resource "azurerm_resource_group" "aks_rg" {
  name     = "aks-resource-group"
  location = "East US"
}

# Create an AKS Cluster
resource "azurerm_kubernetes_cluster" "aks_cluster" {
  name                = "myAKSCluster"
  location            = azurerm_resource_group.aks_rg.location
  resource_group_name = azurerm_resource_group.aks_rg.name
  dns_prefix          = "myaks"

  default_node_pool {
    name       = "default"
    node_count = 2
    vm_size    = "Standard_DS2_v2"
  }

  identity {
    type = "SystemAssigned"
  }
}

# Output the Kubernetes configuration
output "kube_config" {
  value     = azurerm_kubernetes_cluster.aks_cluster.kube_config_raw
  sensitive = true
}

1.3. Initialize and Apply Terraform

Run these commands in your terminal:

terraform init
terraform plan
terraform apply -auto-approve

Step 2: Deploy a Containerized Application on AKS

2.1. Create Kubernetes Deployment and Service Files

Create a folder called k8s in your project directory. Inside the folder, create two files: deployment.yaml and service.yaml.

Deployment File: k8s/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app
        image: nginx:latest
        ports:
        - containerPort: 80

Service File: k8s/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: my-app

2.2. Deploy to AKS

Before deploying, ensure your local kubectl is configured to talk to your new AKS cluster. Run:

az aks get-credentials --resource-group aks-resource-group --name myAKSCluster --overwrite-existing

Then, deploy your app:

kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

Check if Pods Are Running

kubectl get pods

Check if Services Are Running

kubectl get services


Step 3: Set Up a CI/CD Pipeline with GitHub Actions

3.1. Create a GitHub Actions Workflow

In your repository, create a folder .github/workflows and a file named ci-cd-pipeline.yml with the following content:

name: CI/CD Pipeline

on:
  push:
    branches:
      - main

jobs:
  build-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v2

      - name: Login to Azure
        uses: azure/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}

      - name: Set up Kubectl
        uses: azure/setup-kubectl@v1
        with:
          version: 'latest'

      - name: Update kubeconfig for AKS
        run: |
          az aks get-credentials --resource-group aks-resource-group --name myAKSCluster --overwrite-existing

      - name: Deploy to Kubernetes
        run: |
          kubectl apply -f k8s/deployment.yaml
          kubectl apply -f k8s/service.yaml


Step 4: Verify and Monitor

  1. Check Kubernetes Status:
    Run:

     kubectl get pods
     kubectl get services
    
  2. Monitor Pipeline Execution:
    Check the status in GitHub Actions (or Jenkins if you use that) to ensure all steps complete successfully.


To destroy your Terraform-managed resources on Azure, follow these steps:

Open Your Terminal

Ensure you're in the directory where your Terraform files (main.tf, variables.tf, etc.) are located.

Run Terraform Destroy Command

Execute the following command to remove all resources:

terraform destroy

This will show a list of resources that will be deleted and ask for confirmation.


Confirm the Destruction

Type yes when prompted:

Do you really want to destroy all resources?
Enter a value: yes

Terraform will then proceed to delete all the resources.


(Optional) Force Destroy Without Confirmation

If you want to destroy everything without being asked for confirmation, use:

terraform destroy -auto-approve

Verify Resources Are Deleted

After the process completes, confirm everything is removed by running:

az resource list --resource-group aks-resource-group --output table

If no resources are listed, the destruction was successful.

Conclusion

This project demonstrates an end-to-end CI/CD pipeline on Azure using Terraform for infrastructure provisioning and Kubernetes for container orchestration. With this project, I automated the deployment of a containerised application, integrated continuous delivery using GitHub Actions, and built a scalable, resilient cloud-native infrastructure. This hands-on experience not only reduces deployment times significantly but also optimizes resource usage and reliability.

0
Subscribe to my newsletter

Read articles from Chigozie Ozoemena directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Chigozie Ozoemena
Chigozie Ozoemena

Hi there! 👋 I'm Daniel Ozoemena, a passionate Cloud Solution Architect and DevOps Engineer dedicated to building scalable, secure, and innovative cloud solutions. With hands-on experience in Azure, AWS, and Google Cloud Platform, I specialize in deploying infrastructure as code, automating workflows, and optimizing system reliability. Driven by a love for problem-solving, I constantly explore new technologies and best practices to deliver impactful results. Beyond the cloud, I enjoy mentoring, blogging about tech insights, and contributing to open-source projects. When I'm not automating deployments or creating secure virtual networks, you can find me playing chess, learning about AI, or brainstorming solutions to real-world challenges. Let’s connect and grow together on this tech journey! 🚀