Skip to main content
All posts
CI/CDAzure DevOpsArgoCDKubernetesGitOps

From Code to Cloud: CI/CD with Azure DevOps and ArgoCD

How to wire Azure DevOps pipelines for build, test, and image push — then hand off to ArgoCD for GitOps-based Kubernetes delivery.

January 20, 20266 min read

A clean CI/CD pipeline has two distinct jobs: build a verified artifact (CI), and deploy it to the right environment (CD). Mixing these in one pipeline creates fragility. This post shows how Azure DevOps handles CI and ArgoCD handles CD — each doing what it does best.

The split model

CI (Azure DevOps pipelines):

  • Compile and test on every push
  • Build and tag a Docker image
  • Push to Azure Container Registry (ACR)
  • Update a Helm values.yaml file in the GitOps repo with the new image tag

CD (ArgoCD):

  • Watch the GitOps repo for changes
  • Diff the cluster state against the repo
  • Apply changes on sync (manual or automated)

The coupling point is the image tag commit to the GitOps repo. CI produces it; ArgoCD consumes it.

Azure DevOps pipeline

trigger:
  branches:
    include: [main]

pool:
  vmImage: ubuntu-latest

variables:
  ACR_NAME: myregistry
  IMAGE_NAME: api-service

stages:
  - stage: CI
    jobs:
      - job: BuildAndPush
        steps:
          - task: Maven@4
            inputs:
              mavenPomFile: pom.xml
              goals: verify
              options: -DskipITs

          - task: Docker@2
            displayName: Build and push image
            inputs:
              command: buildAndPush
              repository: $(ACR_NAME).azurecr.io/$(IMAGE_NAME)
              dockerfile: Dockerfile
              containerRegistry: acr-service-connection
              tags: |
                $(Build.BuildId)
                latest

          - script: |
              TAG=$(Build.BuildId)
              sed -i "s|image.tag:.*|image.tag: \"$TAG\"|" gitops/helm/values.yaml
              git config user.email "ci@company.com"
              git config user.name "Azure DevOps CI"
              git add gitops/helm/values.yaml
              git commit -m "ci: update image tag to $TAG"
              git push
            displayName: Update GitOps repo image tag

The sed + git push step updates the values file. ArgoCD detects the diff and syncs.

ArgoCD Application manifest

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: api-service
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/gitops-repo
    targetRevision: main
    path: helm/api-service
    helm:
      valueFiles:
        - values.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true

selfHeal: true means ArgoCD will revert manual kubectl changes — good for production discipline. prune: true removes resources that were deleted from the repo.

Environment promotion

For multi-environment setups (dev → staging → prod), maintain separate values-dev.yaml, values-staging.yaml, values-prod.yaml files. CI auto-promotes to dev on every merge; staging and prod require a deliberate tag or pull request merge to the release branch.

This keeps the promotion audit trail in Git, not in Slack messages and tribal knowledge.


Want this pipeline pattern set up for your project? Book a call or send a brief.

Ready to fix this for your business?

Fixed scope, fixed price, written handover - websites, full-stack apps, and DevOps pipelines delivered in weeks, not months.