DEV Community

iapilgrim
iapilgrim

Posted on

Phase 3 - Deploying a Custom App to Azure Kubernetes Service Using Azure Container Registry

πŸš€

In this lab, we will:

  • Create an Azure Container Registry (ACR)
  • Build a custom Docker image in the cloud
  • Deploy it to Azure Kubernetes Service (AKS)
  • Expose it publicly using a LoadBalancer

This is a production-style workflow used by modern cloud-native teams.


πŸ— Architecture Overview

Developer β†’ ACR β†’ AKS β†’ Service (LoadBalancer) β†’ Public IP
Enter fullscreen mode Exit fullscreen mode

We use:

  • Azure Kubernetes Service (AKS)
  • Azure Container Registry (ACR)
  • Managed Identity for secure image pulls

πŸ”§ Prerequisites

You already created AKS:

az aks create \
  --resource-group aks-east2-rg \
  --name aks-prod-east2 \
  --location eastus2 \
  --node-count 2 \
  --network-plugin azure \
  --enable-managed-identity \
  --enable-oidc-issuer \
  --enable-workload-identity \
  --enable-addons monitoring
Enter fullscreen mode Exit fullscreen mode

Set variables:

RG=aks-east2-rg
CLUSTER=aks-prod-east2
ACR_NAME=akseast2acr$RANDOM
LOCATION=eastus2
Enter fullscreen mode Exit fullscreen mode

1️⃣ Register Required Azure Providers (Important)

New subscriptions often need manual provider registration:

az provider register --namespace Microsoft.ContainerRegistry
az provider register --namespace Microsoft.ContainerService
az provider register --namespace Microsoft.Network
az provider register --namespace Microsoft.Compute
Enter fullscreen mode Exit fullscreen mode

Verify:

az provider list --query "[?registrationState!='Registered']"
Enter fullscreen mode Exit fullscreen mode

2️⃣ Create Azure Container Registry

az acr create \
  --resource-group $RG \
  --name $ACR_NAME \
  --sku Standard \
  --location $LOCATION
Enter fullscreen mode Exit fullscreen mode

Attach ACR to AKS (important for image pull permissions):

az aks update \
  --name $CLUSTER \
  --resource-group $RG \
  --attach-acr $ACR_NAME
Enter fullscreen mode Exit fullscreen mode

This configures managed identity-based access.


3️⃣ Create a Simple Hello App

Create project folder:

mkdir hello-aks && cd hello-aks
Enter fullscreen mode Exit fullscreen mode

app.js

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200);
  res.end("Hello from AKS + ACR πŸš€");
});

server.listen(3000);
Enter fullscreen mode Exit fullscreen mode

package.json

{
  "name": "hello-aks",
  "version": "1.0.0",
  "main": "app.js"
}
Enter fullscreen mode Exit fullscreen mode

Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

4️⃣ Build Image in ACR (Cloud Shell Compatible)

Since Azure Cloud Shell doesn’t support Docker daemon, use:

az acr build \
  --registry $ACR_NAME \
  --image hello-aks:v1 \
  .
Enter fullscreen mode Exit fullscreen mode

This:

  • Uploads source
  • Builds inside ACR
  • Stores image securely

Enterprise-friendly approach βœ…


5️⃣ Connect kubectl to AKS

az aks get-credentials \
  --resource-group $RG \
  --name $CLUSTER
Enter fullscreen mode Exit fullscreen mode

Verify:

kubectl get nodes
Enter fullscreen mode Exit fullscreen mode

6️⃣ Deploy the Application

Get ACR login server:

ACR_LOGIN_SERVER=$(az acr show \
  --name $ACR_NAME \
  --query loginServer \
  --output tsv)
Enter fullscreen mode Exit fullscreen mode

Create hello-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-aks
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-aks
  template:
    metadata:
      labels:
        app: hello-aks
    spec:
      containers:
      - name: hello-aks
        image: <ACR_LOGIN_SERVER>/hello-aks:v1
        ports:
        - containerPort: 3000
Enter fullscreen mode Exit fullscreen mode

Replace <ACR_LOGIN_SERVER> with actual value.

Deploy:

kubectl apply -f hello-deployment.yaml
Enter fullscreen mode Exit fullscreen mode

Verify:

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

7️⃣ Expose the Application

Create hello-service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: hello-aks-service
spec:
  type: LoadBalancer
  selector:
    app: hello-aks
  ports:
  - port: 80
    targetPort: 3000
Enter fullscreen mode Exit fullscreen mode

Apply:

kubectl apply -f hello-service.yaml
Enter fullscreen mode Exit fullscreen mode

Wait for public IP:

kubectl get svc hello-aks-service -w
Enter fullscreen mode Exit fullscreen mode

Test:

curl http://<EXTERNAL-IP>
Enter fullscreen mode Exit fullscreen mode

Expected output:

Hello from AKS + ACR πŸš€
Enter fullscreen mode Exit fullscreen mode

🎯 What You Learned

You now understand:

  • How AKS pulls images securely from ACR
  • How to build containers without local Docker
  • How Azure LoadBalancer exposes services
  • How managed identity simplifies authentication
  • How cloud-native deployments work end-to-end

🧠 Real-World Production Enhancements

Next steps for enterprise-grade setup:

  • Private ACR with Private Endpoint
  • NGINX Ingress Controller
  • TLS with cert-manager
  • Horizontal Pod Autoscaler
  • Azure Key Vault + Workload Identity
  • CI/CD with GitHub Actions
  • Blue/Green deployments

πŸš€ Final Architecture

ACR (Private Registry)
        ↓
AKS Deployment (2 replicas)
        ↓
Kubernetes Service (LoadBalancer)
        ↓
Public IP
Enter fullscreen mode Exit fullscreen mode

You just built a real production foundation used by SaaS companies and platform teams.

Top comments (0)