Skip to main content

Azure DevOps Pipeline: Deploy Container to AKS Kubernetes Cluster

821 words·
Azure Azure DevOps CI Pipeline AKS
Table of Contents
Azure-DevOps - This article is part of a series.
Part 3: This Article

Overview
#

The following tutorial is based on the previous post “Azure DevOps Pipeline: Build Container Image and push the Image to Azure Container Registry”.


AKS Prerequisites
#

Create AKS Cluster
#

I’m using the following AKS cluster, for more details, check out my post about AKS Kubernetes clusters.

# Create Kubernetes cluster
az aks create \
    --resource-group container-playground \
    --name aks-cluster-1 \
    --location northeurope \
    --kubernetes-version 1.30.0 \
    --node-count 1 \
    --node-vm-size Standard_DS2_v2 \
    --node-osdisk-size 30

Configure Kubectl
#

# Configure Kubectl to use the AKS cluster
az aks get-credentials \
    --resource-group container-playground \
    --name aks-cluster-1

Create a Namespace
#

Create a namespace for the deployment:

# Create namespace
kubectl create ns dev

Azure DevOps
#

Adopt the Repository
#

Overview
#

The repository file and folderstructure should look like this:

├── azure-pipelines.yml
├── Dockerfile
├── HTML
│   └── index.html
├── kube-manifests
│   └── 01-deployment-and-loadbalancer-service.yml
└── README.md

GitHub Repository: https://github.com/jueklu/azure-devops-aks


Deployment and LoadBalancer Manifest
#

Create a manifest for the deployment and loadbalancer service:

kube-manifests/01-deployment-and-loadbalancer-service.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: container-deployment
  labels:
    app: apache-container
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache-container
  template:
    metadata:
      labels:
        app: apache-container
    spec:
      containers:
        - name: apache-container
          image: jkwregistry.azurecr.io/azuredevopscontainerexample
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: container-loadbalancer
  labels:
    app: apache-container
spec:
  type: LoadBalancer
  selector:
    app: apache-container
  ports:
    - port: 80
      targetPort: 80

Adopt Deployment Pipeline
#

Add a task that publishes the build artifacts:

azure-pipelines.yml
# Docker
# Build and push an image to Azure Container Registry
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker

trigger:
- main

resources:
- repo: self

variables:
  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: '875a58dd-registry-service-connection'
  imageRepository: 'azuredevopscontainerexample'
  containerRegistry: 'jkwregistry.azurecr.io'
  dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
  tag: '$(Build.BuildId)'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

stages:
- stage: Build
  displayName: Build and push stage
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)
    steps:

    - task: Docker@2
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: $(imageRepository)
        dockerfile: $(dockerfilePath)
        containerRegistry: $(dockerRegistryServiceConnection)
        tags: |
                    $(tag)

# Add Publish Build Artifacts Task
    - task: PublishBuildArtifacts@1
      inputs:
        PathtoPublish: '$(System.DefaultWorkingDirectory)/kube-manifests'
        ArtifactName: 'kube-manifests'
        publishLocation: 'Container'

AKS Service Connection
#

Create a service connection for the AKS cluster:

  • Go to: Project Settings > (Pipelines) “Service connections”

  • Click “New service connection”

  • Select “Kubernetes” (login again)

  • Select “Authentication method” x “Azure Subscription”

  • Select your Azure Subscription

  • Select your AKS cluster

  • Select the previously created “dev” namespace

  • Define a service connection name, like aks-cluster-1 dev

  • Click “Save”


Organization Settings
#

Open the dashboard of your organization:
https://dev.azure.com/jueklu/

  • Go to: “Organization settings”
  • Select (Pipelines) “Settings”

  • Disable “Disable creation of classic release pipelines”


Release Pipeline
#

Create Release Pipeline
#

  • Go to: “Pipelines” > “Releases”

  • Click “New pipeline”

  • Select template type “Empty job”
  • Define a stage name like Dev

  • Click “Add an artifact”

  • Select source type “Build”

  • Select your project and repository

  • Click “Add”

  • Add a “Continuous deployment trigger”
  • Set continuois deployment trigger to “Enabled”
  • Select the “Tasks” tab

  • Click “Agent job”

  • Set “Agent pool” to “Azure Pipelines”

  • Set “Agent Specification” to “ubuntu-latest”

  • Click “+” to add a task

  • Select “Deploy to Kubernetes” > “Add”

  • Define a display name like image pull secret

  • Set action to “create secret”

  • Select service connection type “Kubernetes Service Connection”

  • Select your Kubernetes service connection aks-cluster-1 dev

  • Set “Type of secret” to “dockerRegistry”

  • Define a secret name like dev-secret

  • Select your “Docker registry service connection” jkwregistry

  • Click “+” to add a task

  • Select “Deploy to Kubernetes” > “Add”

  • Define a display name like deploy dev

  • Set action to “deploy”

  • Select service connection type “Kubernetes Service Connection”

  • Select your Kubernetes service connection aks-cluster-1 dev

  • Define namespace dev

  • Set “Manifests” to $(System.DefaultWorkingDirectory)/_azure-devops-container-example/kube-manifests/01-deployment-and-loadbalancer-service.yml

  • Set “Containers” to jkwregistry.azurecr.io/azuredevopscontainerexample:$(Build.BuildId)

  • Set “ImagePullSecrets” to dev-secret

  • Click “Save”

  • Click “OK”

Change & Push Repository
#

Adopt the index.html file and push it into the repository.


Verify the Release Pipeline
#


Verify the Deployment with Kubectl
#

# List pods in "dev" namespace
get pods -n dev

# Shell output:
NAME                                   READY   STATUS    RESTARTS   AGE
container-deployment-c85569b74-g4lqc   1/1     Running   0          31s
# List services in "dev" namespace
kubectl get svc -n dev

# Shell output:
NAME                     TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
container-loadbalancer   LoadBalancer   10.0.114.205   172.205.94.30   80:31470/TCP   2m29s

Test the deployment with curl:

# Curl the loadbalancer external IP
curl 172.205.94.30:80

# Shell output:
<!DOCTYPE html>
<html>

<head>
        <title>jklug.work</title>
</head>

<body>
        <h1>Azure DevOps Example</h1>
        <p>Build Container 2</p>
</body>

Delete Resources
#

Delete AKS Cluster
#

# Delete AKS cluster
az aks delete \
    --resource-group container-playground \
    --name aks-cluster-1 \
    --yes \
    --no-wait

Delete Azure Container Registry
#

# Delete the Azure container registry
az acr delete --name jkwregistry --resource-group container-playground --yes

Delete Resource Group
#

# Delete the Azure resource group
az group delete --name container-playground --yes --no-wait

Delete Azure DevOps Project
#

  • Open the project dashboard: https://dev.azure.com/jueklu/Project1

  • Select “Project settings”

  • Select (General) “Overview” and scroll down to “Delete project”

  • Click “Delete”


Delete Azure DevOps Organization
#

  • Open the organization dashboard: https://dev.azure.com/jueklu

  • Select “Organization settings”

  • Select (General) “Overview” and scroll down to “Delete organization”

  • Click “Delete”

Azure-DevOps - This article is part of a series.
Part 3: This Article