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”