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.
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.yamlfile 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.