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.

Deploy to AKS with Azure Pipelines

By Kokil Thapa | Last reviewed: August 2026

If you need to deploy to AKS with Azure Pipelines reliably, the answer lies in treating your infrastructure as code and your release process as an immutable artifact pipeline. Many teams struggle because they conflate building Docker images with orchestrating Kubernetes manifests, leading to fragile scripts and inconsistent environments. A robust implementation separates these concerns into distinct build and release stages, authenticated via workload identity rather than static credentials.

While my daily work often involves deploying Laravel applications via GitLab CI and Deployer on traditional VPS infrastructure, the principles of atomic deployments and configuration management translate directly to Kubernetes. When moving to managed cloud-native platforms, the complexity shifts from server provisioning to manifest orchestration and identity federation. For teams evaluating whether this level of orchestration is necessary versus simpler platform options, understanding the trade-offs between managed cloud services and traditional hosting helps justify the operational overhead of AKS. The following guide assumes you have already decided on AKS and focuses strictly on the engineering mechanics of doing it correctly in 2026.

How do you securely connect Azure Pipelines to AKS without secrets?

The era of storing Kubernetes admin kubeconfig files or long-lived service principal passwords in Azure DevOps library variables is over. In 2026, the only acceptable method to deploy to AKS with Azure Pipelines is through Microsoft Entra ID Workload Identity Federation. This eliminates credential rotation headaches and reduces the blast radius if a pipeline account is compromised.

Azure DevOpsPipeline AgentOIDC Token RequestMicrosoft Entra IDToken ExchangeAKS ClusterRBAC + NamespaceDeploy Actionkubectl / helm
Secure token exchange enables deploying to AKS with Azure Pipelines without storing static kubeconfig or service principal secrets.

Configure the Service Connection

Navigate to Project Settings > Service Connections and create a new "Azure Resource Manager" connection. Select "Workload identity federation (automatic)" if your subscription permits, or manual if you need to pre-create the app registration. Crucially, scope this connection to the specific resource group containing your AKS cluster, not the entire subscription. This follows the principle of least privilege I apply whether configuring Linux servers or cloud IAM roles.

Grant RBAC Permissions on AKS

The federated identity needs explicit permissions inside the cluster. Avoid granting cluster-admin. Instead, create a RoleBinding scoped to your target namespace:

<!-- deploy-role-binding.yaml -->
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: azure-pipelines-deployer
  namespace: production-app
subjects:
- kind: User
  name: "system:serviceaccount:azdo:pipeline-sa" 
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: edit
  apiGroup: rbac.authorization.k8s.io

In production environments, replace the built-in edit ClusterRole with a custom role that only permits updates to Deployments, Services, ConfigMaps, and Secrets within that namespace. This prevents a compromised pipeline from modifying network policies or mutating other tenants.

What is the correct YAML structure for building and pushing to ACR?

A common mistake when engineers first deploy to AKS with Azure Pipelines is combining the image build and the cluster deployment into a single job. This creates tight coupling and makes rollbacks impossible without rebuilding. Always separate these into distinct stages. The build stage produces an immutable artifact (the tagged container image), while the deploy stage consumes it.

Multi-Stage Pipeline Skeleton

This structure mirrors the separation of concerns I use when architecting REST APIs where business logic is decoupled from transport layers. The build stage should never touch the cluster, and the deploy stage should never compile code.

# azure-pipelines.yml
trigger:
  branches:
    include: [main]
  paths:
    exclude: [docs/*, README.md]

variables:
  acrName: 'myregistry.azurecr.io'
  imageName: 'webapp'
  tag: '$(Build.BuildId)'

stages:
- stage: Build
  displayName: 'Build & Push Image'
  jobs:
  - job: BuildImage
    pool:
      vmImage: 'ubuntu-24.04'
    steps:
    - task: Docker@2
      inputs:
        command: 'buildAndPush'
        repository: $(imageName)
        dockerfile: '$(Build.SourcesDirectory)/Dockerfile'
        containerRegistry: 'ACR-Service-Connection'
        tags: |
          $(tag)
          latest

- stage: Deploy
  displayName: 'Deploy to AKS'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeployProd
    environment: 'aks-production'
    strategy:
      runOnce:
        deploy:
          steps:
          - checkout: self
          - task: KubernetesManifest@1
            inputs:
              action: 'deploy'
              kubernetesServiceConnection: 'AKS-Federated-Conn'
              namespace: 'production-app'
              manifests: '$(Pipeline.Workspace)/s/k8s/'
              imagePullSecrets: 'acr-auth'
              containers: '$(acrName)/$(imageName):$(tag)'

Optimizing Docker Builds for AKS

When targeting AKS, ensure your Dockerfile uses multi-stage builds to keep images lean. Large images increase pull times across nodes and inflate storage costs. For PHP/Laravel applications, this means separating composer install and npm build stages from the final runtime image. Also, enable ACR artifact cache to speed up subsequent pipeline runs, especially when working with teams distributed across regions where bandwidth can be variable.

Should you use Helm, Kustomize, or raw manifests for AKS deployments?

The choice of templating engine significantly impacts maintainability. Having maintained complex e-commerce systems where configuration drift causes real revenue loss, I prefer tools that enforce declarative consistency over flexible but error-prone templating.

CriteriaRaw ManifestsKustomizeHelm
ComplexityLowMediumHigh
Environment VariancePoor (copy-paste)Excellent (overlays)Good (values files)
Templating LogicNonePatch-based onlyFull Go templates
Native Azure SupportKubernetesManifest taskKubernetesManifest taskHelmDeploy task required
Best ForSimple apps, learningMicroservices, GitOpsPlatform charts, vendors

Why Kustomize Wins for Custom Applications

For bespoke applications like legal-tech portals or custom e-commerce platforms, Kustomize offers the best balance. It avoids the "template spaghetti" problem where Helm charts become unmaintainable due to excessive conditionals. Kustomize overlays let you maintain a clean base configuration and apply environment-specific patches (replica counts, resource limits, domain names) without duplicating entire manifest files. The KubernetesManifest@1 task natively supports Kustomize via the kustomizationPath input, eliminating extra tooling installation steps.

When Helm Is Unavoidable

Use Helm when deploying third-party infrastructure components (Ingress controllers, cert-manager, monitoring stacks) where upstream charts are the standard distribution format. Never write a custom Helm chart for your application unless you plan to distribute it to multiple unrelated organizations. The cognitive overhead of debugging Go template rendering errors during a production outage is rarely worth the abstraction benefit for internal apps.

Kustomize Structurebase/ (deployment.yaml, svc.yaml)overlays/staging/overlays/prod/kustomization.yamlkustomization.yamlHelm Structuretemplates/ (Go tpl logic)values-staging.yamlvalues-prod.yamlChart.yaml + helpers.tpl
Kustomize uses patch overlays while Helm relies on value injection; choose based on team familiarity and application complexity when deploying to AKS with Azure Pipelines.

How do you implement zero-downtime deployments and safe rollbacks?

Deploying to Kubernetes is not inherently zero-downtime. Without explicit strategy configuration, you risk service interruptions during pod replacement. This matters critically for transactional systems where even seconds of downtime affect user trust and revenue.

Configure Rolling Update Strategy

Always specify update strategy in your Deployment manifest. The default may be acceptable for stateless web apps, but tuning it prevents resource exhaustion on smaller AKS node pools:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1        # Create at most 1 extra pod during update
      maxUnavailable: 0  # Never drop below desired replica count
  minReadySeconds: 30    # Wait for readiness probe before proceeding

Setting maxUnavailable: 0 guarantees capacity is never reduced during deployment. Combined with proper readiness probes (not just liveness probes), this ensures traffic only shifts to new pods once they are fully initialized. For Laravel apps, this includes checking database connectivity and cache availability, not just HTTP 200 on /health.

Automated Rollback Triggers

Azure Pipelines does not automatically rollback failed Kubernetes deployments. You must implement this explicitly. Add a post-deployment validation step that checks pod health and reverts if unhealthy:

- script: |
    kubectl rollout status deployment/webapp -n production-app --timeout=300s
    if [ $? -ne 0 ]; then
      echo "##vso[task.logissue type=error]Deployment failed, initiating rollback"
      kubectl rollout undo deployment/webapp -n production-app
      exit 1
    fi
  displayName: 'Validate & Auto-Rollback'

This pattern catches issues that pass initial manifest validation but fail at runtime—misconfigured environment variables, missing secrets, or incompatible schema changes. In my experience maintaining high-traffic platforms, automated rollback reduces mean-time-to-recovery from minutes to seconds compared to manual intervention.

Managing Database Migrations Safely

Never run migrations as part of the container entrypoint during deployment. This causes race conditions when multiple pods start simultaneously. Instead, use an init container or a dedicated migration job that runs before the main deployment. For frameworks like Laravel or Symfony, this means running php artisan migrate --force in a controlled, single-execution context. If the migration fails, the pipeline stops before updating the Deployment, preventing new code from running against an old schema.

T=0 StartPod v1 (Ready)Pod v1 (Ready)T=1 SurgePod v1 (Ready)Pod v1 (Ready)Pod v2 (Starting)T=2 CutoverPod v1 (Ready)Pod v2 (Ready)Pod v2 (Ready)T=3 DonePod v2Pod v2
Rolling update sequence maintains full capacity during cutover when you deploy to AKS with Azure Pipelines using maxUnavailable zero strategy.

How do you handle secrets and configuration across environments?

Hardcoding configuration in manifests or pipeline variables is a security anti-pattern. For teams evaluating whether to adopt enterprise-grade practices, understanding fundamental security principles for web infrastructure provides context for why secret management matters beyond compliance checkboxes.

Integrate Azure Key Vault with AKS

Use the Azure Key Vault Provider for Secrets Store CSI Driver. This mounts secrets as volumes rather than environment variables, preventing leakage in logs and crash dumps. Configure it in your pipeline by ensuring the workload identity has Key Vault read permissions, then reference secrets in your pod spec:

volumes:
- name: app-secrets
  csi:
    driver: secrets-store.csi.k8s.io
    readOnly: true
    volumeAttributes:
      secretProviderClass: "app-kv-secrets"
containers:
- name: webapp
  volumeMounts:
  - name: app-secrets
    mountPath: "/mnt/secrets"
    readOnly: true

Environment-Specific Configuration Management

Separate structural configuration (ports, paths, feature flags) from sensitive data (API keys, DB passwords). Use ConfigMaps for the former, Key Vault for the latter. When using Kustomize, each overlay references its own ConfigMap generator, ensuring staging never accidentally loads production values. This discipline prevents the "it works on staging" syndrome that plagues teams who share configuration sources across environments.

Conclusion

To successfully deploy to AKS with Azure Pipelines in 2026, prioritize workload identity federation over static credentials, separate build and deploy stages immutably, choose Kustomize for application manifests, and enforce zero-downtime strategies with automated rollback safeguards. These patterns transform Kubernetes deployment from a fragile manual ritual into a reliable, auditable engineering process. If your team needs help implementing these practices or evaluating whether AKS is the right fit versus simpler alternatives, reach out to discuss your specific infrastructure requirements.

Frequently Asked Questions

You need an active Azure subscription, an existing AKS cluster, an Azure Container Registry, and a YAML pipeline definition. Service connections for both ACR and AKS must be configured in Azure DevOps project settings before the first deployment runs successfully.

Azure Pipelines offers one free Microsoft-hosted agent with 1,800 monthly minutes. AKS cluster management is free; you pay only for underlying VMs, storage, and networking. Expect Rs 15,000–40,000/month (~USD 110–300) for a small production cluster plus pipeline usage overages.

Yes. Self-hosted agents reduce costs and provide VNet access without exposing AKS API server publicly. Install the agent on an Ubuntu 22.04 VM within your Azure VNet, configure kubectl and helm binaries, and register it as a deployment group or agent pool in Azure DevOps.

Create a Kubernetes service connection using either a service principal or workload identity federation. Workload identity is preferred in 2026 as it eliminates long-lived secrets. Grant the identity Contributor role on the AKS resource and AcrPull on the container registry for least-privilege access.

Use rolling updates with maxSurge=1 and maxUnavailable=0 for zero-downtime deploys. For critical services, implement blue-green or canary via Flagger or Argo Rollouts integrated into your pipeline. Always include health checks and automatic rollback triggers based on HTTP error rates or pod restart counts.

Store manifests in Git but never commit secrets. Use Azure Key Vault with the AzureKeyVault@2 task to inject secrets at runtime, or integrate External Secrets Operator. Parameterize environment-specific values using Helm charts or Kustomize overlays rather than maintaining separate manifest copies per environment.

This usually means missing acr-pull role assignment or incorrect image tag. Verify the AKS cluster has Managed Identity enabled with AcrPull on your ACR. Confirm the image exists with az acr repository show-tags and that your pipeline pushes to the same registry and repository path referenced in manifests.

Run migrations as a Kubernetes Job before the main deployment using init containers or a pre-deploy pipeline stage. Never run migrations inside application pods during rollout. Use idempotent migration scripts and include a rollback job. On Laravel projects, I run php artisan migrate --force in a dedicated job with proper DB credentials injected via Key Vault.

Use Helm for applications with multiple environments or complex dependencies. Raw kubectl apply works for simple single-environment services but lacks templating and release tracking. In my experience, Helm reduces configuration drift across staging and production, especially when combined with azure-pipelines.yml template stages.

Add an Environment with approvals and checks in Azure Pipelines. Configure branch policies requiring PR reviews for manifest changes. Use runtime parameters to gate production stages behind manual validation. Combine this with automated quality gates like container scanning results or integration test pass thresholds before allowing promotion.

Integrate Azure Monitor Container Insights and enable Prometheus scraping. Add a post-deployment verification stage that queries Application Insights or Grafana for error rate spikes. Fail the pipeline if p95 latency exceeds baseline or 5xx errors surpass threshold within five minutes of rollout completion.

Enable verbose logging with system.debug=true and review kubectl describe output captured via script tasks. Check pod events, node resources, and quota limits. Common issues include insufficient CPU/memory requests, failed liveness probes, or ConfigMap version mismatches. Always retain pipeline artifacts including rendered manifests for post-mortem analysis.

Yes, using multi-stage YAML pipelines with parallel jobs per service. Share common build and push stages, then fan out to independent deploy stages. Use dependsOn and conditions to control ordering. Avoid monolithic pipelines; instead, create templates for reuse and isolate failure domains so one service failure doesn't block others.

Disable public API server access and use private clusters with VNet-integrated self-hosted agents. If public access is required, restrict API server IP ranges to your agent subnet. Never store kubeconfig files; always use service connections with workload identity. Rotate credentials quarterly and audit access logs via Azure Activity Log.

Forgetting to grant AcrPull to the AKS managed identity causes silent image pull failures. Hardcoding image tags breaks reproducibility; always use SHA digests. Missing resource requests leads to OOMKilled pods under load. Not setting pod disruption budgets causes downtime during node upgrades. Test your full pipeline against a non-production cluster first to catch these issues cheaply.

Share this article

Quick Contact Options
Choose how you want to connect me: