Modern cloud-native applications rely heavily on automated Continuous Integration and Continuous Deployment (CI/CD) pipelines. When deploying containerized workloads to Azure Kubernetes Service (AKS), a robust pipeline requires a secure, frictionless bridge between your source control, your container registry, and your orchestration cluster.

This end-to-end guide walks through provisioning an Azure Container Registry (ACR), linking it to an existing AKS cluster, generating Service Principal credentials securely, and automating the entire build-to-deploy lifecycle using GitHub Actions.

Prerequisites

Before diving into the configuration, ensure you have the following in place:

  • An active Azure Subscription.

  • Azure CLI installed and authenticated (az login).

  • An existing Azure resource group (e.g., linux-admin-course).

  • An existing Azure Kubernetes Service cluster (e.g., mudassar-kubi-course).

Phase 1: Provisioning the Azure Container Registry (ACR)

The Azure Container Registry is a managed, private Docker registry used to securely store and manage your container images.

1.1 Overcoming the Registration Error

A common pitfall when creating an ACR for the first time in a new subscription is encountering a MissingSubscriptionRegistration error. Azure requires explicit registration of the Microsoft.ContainerRegistry namespace before provisioning.

Register the provider using the Azure CLI:

Bash

Code
az provider register --namespace Microsoft.ContainerRegistry

Verify the registration status. Wait until the output returns "Registered" before proceeding:

Bash

Code
az provider show -n Microsoft.ContainerRegistry --query "registrationState"

1.2 Creating the Registry

Once registered, you can provision the registry. Note that ACR names must be globally unique across all of Azure and consist solely of lowercase alphanumeric characters.

Bash

Code
az acr create --resource-group linux-admin-course --name mudassaracr99 --sku Basic

The Basic SKU is highly cost-effective and provides the necessary throughput and storage for development and standard CI/CD workflows.

Phase 2: Integrating ACR with AKS

Kubernetes needs permission to pull private images from your registry. Instead of manually creating and managing Kubernetes Image Pull Secrets, Azure provides a streamlined command to establish a secure, role-based assignment (acrpull) between the AKS cluster's managed identity and the ACR.

Execute the following command to attach the registry to your cluster:

Bash

Code
az aks update -n mudassar-kubi-course -g linux-admin-course --attach-acr mudassaracr99

Once this process completes, any Pod deployed to your AKS cluster can seamlessly authenticate and pull images from mudassaracr99.azurecr.io.

Phase 3: Provisioning an Identity for GitHub Actions

To allow GitHub Actions to build Docker images, push them to your ACR, and apply manifests to your AKS cluster, it requires an Azure identity. We achieve this by creating an Azure Active Directory Service Principal assigned the Contributor role, tightly scoped to your specific resource group.

The Shell Syntax Trap

When referencing documentation, subscription IDs are often wrapped in angle brackets (e.g., <your-subscription-id>). If executed verbatim in Bash, the < and > symbols are interpreted as file redirection operators, leading to frustrating "No such file or directory" errors.

First, retrieve your exact Azure Subscription ID:

Bash

Code
az account show --query id --output tsv

Next, construct the Service Principal command by injecting the ID directly, stripping away any brackets:

Bash

Code
az ad sp create-for-rbac --name "GitHub-Actions-AKS" --role contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID_HERE/resourceGroups/linux-admin-course --json-auth

Securing the Credentials

The output of this command is a JSON object containing sensitive keys (clientId, clientSecret, subscriptionId, and tenantId).

Immediately copy this JSON payload. Navigate to your GitHub repository, go to Settings > Secrets and variables > Actions, and create a new repository secret named AZURE_CREDENTIALS. Paste the entire JSON block as the value.

Phase 4: Automating with GitHub Actions

With the infrastructure provisioned and authorized, the final step is defining the CI/CD pipeline. This workflow will trigger on code pushes, build a new container image, push it to ACR, and update the AKS cluster.

Create a file in your repository at .github/workflows/deploy.yml with the following configuration:

YAML

Bash
name: Build and Deploy to AKS

on:
  push:
    branches:
      - main

env:
  ACR_NAME: mudassaracr99
  CLUSTER_NAME: mudassar-kubi-course
  RESOURCE_GROUP: linux-admin-course
  IMAGE_NAME: my-aks-app 

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

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

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

      - name: Login to ACR
        run: az acr login --name ${{ env.ACR_NAME }}

      - name: Build and Push Docker Image
        run: |
          docker build -t ${{ env.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }} .
          docker push ${{ env.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}

      - name: Set AKS Context
        uses: azure/aks-set-context@v3
        with:
          resource-group: ${{ env.RESOURCE_GROUP }}
          cluster-name: ${{ env.CLUSTER_NAME }}

      - name: Deploy to AKS
        uses: Azure/k8s-deploy@v5
        with:
          manifests: |
            manifests/deployment.yaml
            manifests/service.yaml
          images: |
            ${{ env.ACR_NAME }}.azurecr.io/${{ env.IMAGE_NAME }}:${{ github.sha }}

Architecture of the Pipeline

This pipeline relies on Git commit hashes (${{ github.sha }}) to tag Docker images. This practice guarantees immutability and traceability. During the final deployment step, the Azure/k8s-deploy action intelligently parses your deployment.yaml manifest, finds the base image reference, and injects the specific commit hash tag. This ensures Kubernetes recognizes a change in the manifest and gracefully rolls out the new pods with zero downtime.