Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Azure AKS: A Practical Guide

By Kokil Thapa | Last reviewed: September 2026

Azure AKS: A Practical Guide starts where most tutorials stop — after the cluster exists but before production traffic hits it. You have a working Laravel app on a single Ubuntu box with Deployer and PHP-FPM. That setup is fine until you need horizontal scaling, zero-downtime rollouts across multiple replicas, or isolated staging namespaces. Azure Kubernetes Service (AKS) gives you a managed control plane so you focus on workloads, not etcd backups. This guide walks through cluster creation, your first deploy, CI/CD wiring, cost discipline, and the failures I see on real migration projects.

What is Azure Kubernetes Service and when should you use it?

Kubernetes orchestrates containers across a pool of virtual machines. AKS is Microsoft's managed offering. Azure runs the control plane. You pay for worker nodes, load balancers, and storage.

For many PHP and Laravel projects I maintain, a Linux VPS with Apache and PHP-FPM remains the right call. Costs stay predictable. Ops stay simple. AKS earns its place when you need multiple replicas, rolling updates without symlink tricks, or sidecar patterns for logging and metrics.

On a booking platform like Adventure Third Pole Trek, peak season traffic spikes are easier to absorb when the scheduler adds pods automatically. The trade-off is operational complexity. You now own YAML manifests, ingress controllers, and cluster upgrades.

Azure AKS Architecture OverviewAKS Control PlaneManaged by AzureNode Pool 1System workloadsNode Pool 2App workloadsNode Pool 3Spot instancesAzure Load Balancer + Ingress ControllerApp PodsRedis CacheMySQL Flex
Azure AKS: A Practical Guide — managed control plane with separate node pools for system, application, and cost-optimized spot workloads

Signals that AKS is the right move

  • You run three or more microservices that share release cadences but need independent scaling.
  • Your team already uses containers locally with Docker Compose and wants parity in staging.
  • You need blue-green or canary deploys without custom nginx scripting.
  • Compliance requires network segmentation between frontend, API, and worker tiers.

Signals to stay on App Service or a VPS

  • Single monolithic Laravel or WordPress site with modest traffic.
  • No dedicated DevOps time — cluster upgrades and ingress TLS will land on the same developer who writes features.
  • Budget under Rs 15,000/month (~USD 110) for compute — a basic App Service plan or VPS is cheaper.

How do you create your first AKS cluster with Azure CLI?

Install the Azure CLI and authenticate. Create a resource group, then provision the cluster. Start small. Two nodes in a single pool is enough for learning.

Prerequisites

  1. Azure subscription with Contributor role on the target resource group.
  2. Azure CLI 2.x installed locally or in Azure DevOps.
  3. kubectl matching your cluster version — install via az aks install-cli.
  4. Docker Desktop or Podman for building images locally.

Create the cluster

# Login and set subscription
az login
az account set --subscription "Your-Subscription-Name"

# Resource group in a nearby region
az group create --name rg-aks-practical --location eastasia

# Create cluster — start with 2 nodes, Standard_B2s for dev
az aks create \
  --resource-group rg-aks-practical \
  --name aks-practical-dev \
  --node-count 2 \
  --node-vm-size Standard_B2s \
  --enable-managed-identity \
  --generate-ssh-keys \
  --network-plugin azure \
  --enable-addons monitoring

# Fetch credentials
az aks get-credentials \
  --resource-group rg-aks-practical \
  --name aks-practical-dev

# Verify
kubectl get nodes
kubectl get namespaces

The command takes ten to fifteen minutes. Do not interrupt it. If it fails midway, delete the partial resource group and retry. Partial clusters leave orphaned NICs that confuse billing.

For production, enable the Azure CNI plugin with a dedicated subnet. Calico network policies become available. That matters when you segment a public API from internal queue workers.

Enable Azure Monitor from day one

The --enable-addons monitoring flag wires Log Analytics. Skip this and you will debug blind. Container restarts, OOM kills, and failed liveness probes show up here before users complain. Pair it with Grafana dashboards if your team already runs that stack.

How do you deploy a containerized application to AKS?

Containerize your app first. Push the image to Azure Container Registry (ACR). Apply Kubernetes manifests. Expose the service through an ingress controller.

Step 1: Build and push the image

# Create ACR
az acr create \
  --resource-group rg-aks-practical \
  --name acrpracticaldev \
  --sku Basic

# Attach ACR to AKS (pull permissions)
az aks update \
  --resource-group rg-aks-practical \
  --name aks-practical-dev \
  --attach-acr acrpracticaldev

# Build and push — example Laravel Dockerfile
az acr build \
  --registry acrpracticaldev \
  --image laravel-api:v1 \
  --file Dockerfile \
  .

A typical Laravel Dockerfile runs composer install --no-dev, copies the app, and starts PHP-FPM behind nginx. Build frontend assets in CI with Node.js 26 LTS before the Docker build. Commit compiled assets if your server has no Node — same pattern I use with Deployer releases.

Step 2: Write the Kubernetes manifests

Keep manifests in Git. Use Kustomize overlays for dev, staging, and prod. Validate YAML with the JSON formatter when converting between formats, or run kubectl apply --dry-run=client before every push.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: laravel-api
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: laravel-api
  template:
    metadata:
      labels:
        app: laravel-api
    spec:
      containers:
      - name: app
        image: acrpracticaldev.azurecr.io/laravel-api:v1
        ports:
        - containerPort: 80
        envFrom:
        - secretRef:
            name: laravel-env
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: 80
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5

Always set resource requests and limits. Without them, the scheduler packs too many pods onto one node. One memory spike takes down every container on that VM.

Step 3: Expose with ingress and TLS

# Install NGINX ingress controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

# Ingress with cert-manager for Let's Encrypt
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: laravel-api-ingress
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - api.example.com
    secretName: api-tls
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: laravel-api
            port:
              number: 80
AKS Deployment FlowGit Pushmain branchCI BuildTests + DockerPush ACRTagged imagekubectlApply manifestsRolling UpdateNew pods replace oldLive Pods3 replicasProduction Checks After DeployHealth probes pass | Logs clean | Ingress returns 200Database migrations run as Job, not in container start
Deploy to AKS: Git push triggers CI, image lands in ACR, kubectl applies manifests, and rolling updates replace pods safely

Wire Azure Pipelines for CI/CD

Manual kubectl apply works for learning. Production needs a pipeline. Follow the pattern in deploy to AKS with Azure Pipelines. Store kubeconfig as a secure file or use workload identity federation — never commit credentials.

# azure-pipelines.yml excerpt
trigger:
  branches:
    include:
      - main

stages:
- stage: Build
  jobs:
  - job: DockerBuild
    steps:
    - task: Docker@2
      inputs:
        containerRegistry: 'acr-practical-connection'
        repository: 'laravel-api'
        command: 'buildAndPush'
        Dockerfile: 'Dockerfile'
        tags: '$(Build.BuildId)'

- stage: Deploy
  dependsOn: Build
  jobs:
  - deployment: DeployAKS
    environment: 'production-aks'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: KubernetesManifest@1
            inputs:
              action: 'deploy'
              namespace: 'production'
              manifests: 'k8s/deployment.yaml'
              containers: 'laravel-api=acrpracticaldev.azurecr.io/laravel-api:$(Build.BuildId)'

Run database migrations as a Kubernetes Job, not inside the container entrypoint. Two pods starting simultaneously will race on migrations. A Job with backoffLimit: 1 runs once and exits.

How does AKS compare to App Service, GKE, and EKS?

Platform choice depends on team skills, existing cloud spend, and workload shape. I evaluate four options for every migration proposal.

CriteriaAzure AKSAzure App ServiceGoogle GKEAWS EKS
Control plane costFree (pay nodes only)Included in plan priceFree tier + cluster fee$0.10/hr per cluster
Ops overheadHigh — you own K8sLow — PaaS managedHighHighBest forMicroservices on Azure, DevOps shopsSingle web apps, quick deploysGCP-native ML/data stacksAWS-native SaaS products
PHP/Laravel fitGood with custom DockerfileExcellent native supportGoodGood
Learning curveSteepShallowSteepSteep

For PHP-heavy workloads, read GCP vs AWS vs Azure for PHP workloads before committing. AKS shines when you already pay for Azure DevOps, Key Vault, and Monitor in the same tenant. Jumping to GKE or EKS makes sense only when the rest of your stack lives there.

Nepal-based startups should model costs in NPR early. A two-node Standard_D2s_v5 pool runs roughly Rs 12,000–18,000/month (~USD 90–135) before load balancers and storage. See budgeting AWS and Azure in NPR for a fuller worksheet.

AKS vs App Service Decision TreeNew project?Single appMulti-serviceApp ServiceNeed K8s features?Scaling, mesh, jobsNoYesApp ServiceChoose AKSManaged K8sVPS + Deployer still wins for budget Laravel sitesRs 3,000–8,000/month with full control
Azure AKS decision tree — choose App Service or VPS for monoliths; choose AKS when multi-service orchestration justifies the ops cost

How do you manage costs, secrets, and security on AKS?

Uncontrolled AKS spend is the most common post-migration surprise. A dev cluster left running over Dashain can burn a month's VPS budget in a week.

Cost controls that actually work

  • Use spot node pools for non-critical workloads — batch imports, queue workers, staging.
  • Enable the cluster autoscaler with sensible min/max bounds.
  • Right-size VM SKUs — Standard_B2s for dev, Standard_D2s_v5 for production API tiers.
  • Set Azure budget alerts at 50%, 80%, and 100% thresholds.
  • Delete unused LoadBalancer services — each one provisions a public IP that bills hourly.

Apply the broader patterns from Azure cost management. Tag every resource with environment, project, and owner from creation time.

Secrets with Azure Key Vault

Never bake database passwords into Docker images. Mount secrets from Azure Key Vault using the Secrets Store CSI driver. Rotate credentials without rebuilding images.

# SecretProviderClass example
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: laravel-kv-secrets
spec:
  provider: azure
  parameters:
    usePodIdentity: "false"
    useVMManagedIdentity: "true"
    userAssignedIdentityID: "YOUR-MANAGED-IDENTITY-ID"
    keyvaultName: "kv-practical-prod"
    objects: |
      array:
        - |
          objectName: db-password
          objectType: secret
    tenantId: "YOUR-TENANT-ID"

Enable Azure Policy add-on on the cluster. Block containers running as root. Enforce label standards. Require resource limits on every pod spec.

Network segmentation

Default AKS networking allows any pod to reach any pod. That is a problem when your API and admin panel share a cluster. Apply NetworkPolicy resources to restrict east-west traffic. Expose only the ingress controller to the public internet.

How do you troubleshoot common AKS production issues?

These failures appear on every AKS project I have reviewed. Save the commands now.

Pod stuck in CrashLoopBackOff

kubectl describe pod POD_NAME -n production
kubectl logs POD_NAME -n production --previous
kubectl get events -n production --sort-by='.lastTimestamp'

Common causes: missing environment variables, failed database connection, migration running in entrypoint script, or wrong image tag. The --previous flag shows logs from the crashed container instance.

ImagePullBackOff

ACR authentication failed. Verify the managed identity attachment with az aks check-acr. Confirm the image tag exists in the registry. Typos in image names account for half of these errors.

502 from ingress after deploy

Readiness probe is failing. The pod is running but not receiving traffic. Check that your /ready endpoint actually verifies database connectivity. A probe that always returns 200 hides broken dependencies.

Cluster upgrade broke workloads

AKS supports N-2 Kubernetes versions. Plan upgrades quarterly. Test in a staging cluster first. Deprecated API versions in your manifests will break silently until apply time. Run kubectl deprecations or use the Kubernetes deprecation guide before each upgrade.

AKS Troubleshooting WorkflowSymptom502, crash, timeoutkubectldescribe + logsIdentifyRoot causeConfig fixImage fixResource fixNetwork fixVerify: kubectl rollout statusConfirm probes pass before closing incidentDocument fix in runbook — same bug returns after next deploy
Azure AKS troubleshooting — symptom to kubectl diagnosis to targeted fix, then rollout verification before closing the incident

Define infrastructure as code from the start. Hand-clicked clusters drift. Use Terraform or Azure Bicep to reproduce environments. Pair with Terraform in Azure DevOps pipelines for a full GitOps loop.

For ongoing support after launch, treat AKS like any production system. Schedule upgrades, monitor disk usage on nodes, and review support and maintenance contracts before the first outage — not after.

Key Takeaways

  • Start with a two-node dev cluster, enable monitoring, and attach ACR before writing application manifests.
  • Set resource requests, limits, liveness probes, and readiness probes on every deployment — skipping them causes production outages.
  • Run database migrations as Kubernetes Jobs, not container entrypoints, to prevent race conditions across replicas.
  • Use spot node pools and budget alerts to control AKS costs; delete unused LoadBalancer services immediately.
  • Store secrets in Azure Key Vault via the CSI driver — never embed credentials in Docker images or Git.
  • Choose AKS only when multi-service orchestration justifies the ops overhead; App Service or VPS remains better for single Laravel apps.

People Also Ask

Is Azure AKS free to use?

The AKS control plane has no charge. You pay for worker node VMs, storage, load balancers, and outbound bandwidth. A minimal two-node dev cluster costs roughly Rs 8,000–12,000/month (~USD 60–90). Production clusters with three or more larger nodes, plus Redis and managed MySQL, typically run Rs 25,000–50,000/month (~USD 185–370) depending on region and SKU choices.

Do I need Kubernetes experience before using AKS?

Basic kubectl fluency is essential before production. You should understand pods, deployments, services, and ingress at minimum. AKS removes control plane management but not Kubernetes concepts. Teams new to containers should containerize locally first, deploy to a dev cluster, and complete at least one staged rollout before touching production traffic.

Can I run PHP and Laravel on Azure AKS?

Yes. Build a Docker image with PHP 8.3 or 8.5, nginx, and PHP-FPM. Run queue workers as separate deployments or Horizon pods. Connect to Azure Database for MySQL or an external managed instance. The pattern works well for API-heavy Laravel apps that outgrow single-server Deployer workflows, especially when paired with horizontal pod autoscaling.

How does AKS integrate with Azure DevOps?

Azure DevOps connects to AKS through service connections using managed identity or a service principal. Pipeline tasks like KubernetesManifest@1 deploy updated images after CI builds. Environment approvals gate production deploys. Workload identity federation removes long-lived credentials from pipeline variables entirely — the recommended approach for 2026 pipelines.

Ship AKS with a plan, not a hope

Azure AKS: A Practical Guide is really a decision framework plus a deploy checklist. Provision a small cluster, wire CI/CD through Azure Pipelines, lock down secrets in Key Vault, and set cost alerts before you migrate production traffic. Keep your monolith on a VPS until scaling requirements force the move — premature Kubernetes adoption burns budget and morale.

If you are evaluating AKS for a Laravel API, eCommerce backend, or enterprise application, map your current Deployer workflow to containers first. Prove the image locally. Then schedule a cluster build. For multi-cloud context, see multi-cloud architecture and AWS vs Azure vs Google Cloud in 2026.

Need help containerizing an existing app or designing your first AKS pipeline? Contact us to walk through your stack, cost model, and rollout plan before you provision a single node.

Frequently Asked Questions

AKS is Microsoft’s managed Kubernetes offering. Azure runs the control plane; you pay for worker nodes, load balancers, and storage while deploying containerized workloads with kubectl or Helm.

AKS earns its place when you need multiple replicas, rolling updates without Deployer symlink tricks, independent scaling across microservices, or network segmentation between tiers. On a booking platform like Adventure Third Pole Trek, peak-season traffic spikes are easier to absorb when the scheduler adds pods automatically. Stay on a Linux VPS with Apache and PHP-FPM, or Azure App Service, for a single monolithic Laravel or WordPress site with modest traffic, no dedicated DevOps time, or a compute budget under Rs 15,000/month (~USD 110). The trade-off is operational complexity: you now own YAML manifests, ingress controllers, and cluster upgrades.

Install Azure CLI 2.x, run az login, set your subscription with az account set, create a resource group such as rg-aks-practical in a nearby region, then provision the cluster with az aks create. Start with two nodes on Standard_B2s for dev, enable managed identity, Azure CNI network plugin, and the monitoring addon for Log Analytics. Fetch credentials via az aks get-credentials and verify with kubectl get nodes. The command takes ten to fifteen minutes; do not interrupt it. If it fails midway, delete the partial resource group and retry, because partial clusters leave orphaned NICs that confuse billing.

The AKS control plane has no charge; you pay for worker node VMs, storage, load balancers, and outbound bandwidth. A minimal two-node dev cluster on Standard_B2s runs roughly Rs 8,000–12,000/month (~USD 60–90). A production two-node Standard_D2s_v5 pool costs roughly Rs 12,000–18,000/month (~USD 90–135) before load balancers and storage. Clusters with three or more larger nodes plus managed MySQL and Redis typically reach Rs 25,000–50,000/month (~USD 185–370). Model costs in NPR early, set budget alerts at 50%, 80%, and 100%, and delete unused LoadBalancer services that bill hourly.

Yes. Azure charges only for worker nodes, storage, load balancers, and bandwidth—not the managed Kubernetes control plane itself.

Containerize the app, push the image to Azure Container Registry, attach ACR to the cluster, then apply Kubernetes manifests kept in Git with Kustomize overlays for each environment. A typical Laravel Dockerfile runs composer install --no-dev and serves PHP-FPM behind nginx. Build frontend assets in CI with Node.js 26 LTS before the Docker build, or commit compiled assets if the server has no Node—the same pattern used with Deployer releases. Set resource requests and limits, liveness probes on /health, and readiness probes on /ready. Expose the service through the NGINX ingress controller with cert-manager for Let’s Encrypt TLS.

Running migrations inside a container entrypoint causes race conditions when multiple replicas start simultaneously—two pods will fight over the same schema changes. A Kubernetes Job with backoffLimit: 1 runs migrations once and exits cleanly before or alongside the rolling deployment. This is one of the first production failures I see on AKS migration projects where teams copied VPS deploy habits directly into manifests without adjusting for horizontal scaling.

Manual kubectl apply works for learning, but production needs a pipeline. Store kubeconfig as a secure file or use workload identity federation—never commit credentials. A typical azure-pipelines.yml triggers on main, builds and pushes the Docker image to ACR via Docker@2, then deploys with KubernetesManifest@1 using the Build.BuildId as the image tag. Run database migrations as a separate Job stage before or after the deployment stage. Pair this with the official deploy-to-AKS-with-Azure-Pipelines pattern and validate manifests with kubectl apply --dry-run=client before every push.

AKS control plane is free; you pay nodes only. App Service includes the control plane in plan pricing with low ops overhead—excellent for single web apps. GKE and EKS both carry high operational overhead similar to AKS. AKS shines when you already pay for Azure DevOps, Key Vault, and Monitor in the same tenant. Jumping to GKE or EKS makes sense only when the rest of your stack lives on GCP or AWS. For PHP-heavy workloads, evaluate team skills and existing cloud spend before committing; a custom Dockerfile on AKS works well, but App Service offers excellent native PHP support with a shallower learning curve.

Never bake database passwords into Docker images or commit them to Git. Mount secrets from Azure Key Vault using the Secrets Store CSI driver with a SecretProviderClass that references your keyvaultName, managed identity, and tenant ID. Rotate credentials in Key Vault without rebuilding images. Enable the Azure Policy add-on on the cluster to block containers running as root, enforce label standards, and require resource limits on every pod spec. Default AKS networking allows any pod to reach any pod, so apply NetworkPolicy resources to restrict east-west traffic and expose only the ingress controller publicly.

Uncontrolled AKS spend is the most common post-migration surprise—a dev cluster left running over Dashain can burn a month’s VPS budget in a week. Use spot node pools for non-critical workloads like batch imports, queue workers, and staging. Enable the cluster autoscaler with sensible min and max bounds. Right-size VM SKUs: Standard_B2s for dev, Standard_D2s_v5 for production API tiers. Set Azure budget alerts, delete unused LoadBalancer services, and tag every resource with environment, project, and owner from creation time. Apply broader Azure cost management patterns alongside these cluster-specific controls.

Run kubectl describe pod, kubectl logs with the --previous flag to see logs from the crashed container instance, and kubectl get events sorted by timestamp. Common causes include missing environment variables, failed database connections, migrations running in the entrypoint script instead of a Job, or a wrong image tag. The --previous flag is critical because the current container may not have useful logs yet. Fix the root cause, verify with a dry-run apply, then watch the rollout complete before closing the incident.

ACR authentication failed or the image tag does not exist. Verify managed identity attachment with az aks check-acr and confirm the exact image name and tag in Azure Container Registry. Typos in image names account for roughly half of these errors on projects I review. After fixing the tag or ACR attachment via az aks update --attach-acr, delete the failing pod so the scheduler pulls a fresh copy with corrected credentials.

The readiness probe is failing. The pod is running but not receiving traffic because Kubernetes considers it not ready. Check that your /ready endpoint actually verifies database connectivity—a probe that always returns 200 hides broken dependencies and sends traffic to pods that cannot serve requests. Compare liveness probe settings on /health separately; a pod can pass liveness while failing readiness. Fix the dependency, confirm the probe returns accurate status, then verify the rollout before closing the ticket.

AKS supports N-2 Kubernetes versions, so plan upgrades quarterly and test in a staging cluster first. Deprecated API versions in your manifests break silently until apply time. Run kubectl deprecations or consult the Kubernetes deprecation guide before each upgrade. After upgrading, verify all deployments roll out cleanly and check Azure Monitor for container restarts or failed probes. Define infrastructure as code from the start with Terraform or Azure Bicep paired with Azure DevOps pipelines—hand-clicked clusters drift and make upgrade testing unreliable across environments.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: