GitOps with Argo CD on AKS

Wire your Helm chart into a GitOps pipeline using Argo CD on Azure AKS.

Introduction

30 Second Summary

Every team has experienced the "who deployed what?" problem. Someone runs a command from their laptop, something breaks, and nobody can trace what changed or roll it back quickly.

In this project, you will set up Argo CD on an Azure Kubernetes Service cluster to create a fully automated GitOps pipeline. Instead of deploying manually with Helm commands, you will push changes to Git and watch Argo CD automatically sync them to your cluster.

What You'll Build

Push a commit to GitHub, watch Argo CD pick up the change and deploy it to your AKS cluster within seconds, then break the cluster on purpose and see Argo CD automatically fix it.

By the end of this project, you'll have:

  • A GitOps pipeline where a Git commit is all it takes to deploy your Helm chart to your AKS cluster. No manual kubectl or helm install required.
  • Drift detection and self-healing that catches when someone makes a manual change to the cluster and automatically reverts it back to the Git-defined state within seconds.
  • Multi-environment promotion with separate dev and staging deployments managed through different Helm values files in the same repo. You will promote a change from dev to staging using only Git commits.
  • Secret Mission: an optional challenge to push your skills further.

Are there any prerequisites?

This project builds directly on Project 3 (Helm charts with environment-specific values). You need your GitHub repo containing the Helm chart from that project, an Azure Pay-As-You-Go subscription, and all CLI tools installed in previous projects (Azure CLI, Terraform, kubectl, Helm).

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

Rebuild Infrastructure and Install Argo CD

Your AKS cluster and ACR were torn down after the previous project. Before you can wire up a GitOps pipeline, you need the infrastructure running again.

This step rebuilds your Azure resources with Terraform, installs Argo CD v3.5.1 on the cluster, and gets you into the Argo CD dashboard. Think of Argo CD as the control plane that watches your Git repo and keeps your cluster in sync with it.

In this step, get ready to:
  • Rebuild your AKS cluster and ACR using your existing Terraform configs.
  • Install Argo CD v3.5.1 on the cluster and set up the Argo CD CLI.
  • Log into the Argo CD dashboard and confirm a clean starting state.
Rebuild AKS and ACR with Terraform

Your Terraform configs from the previous project are still on your machine. You just need to sign into Azure and run them again.

  • Sign into the Azure CLI by running this command:
az login

What happens when you run this?

This opens a browser window for Microsoft sign-in. Complete the authentication in the browser and return to your terminal. You should see your subscription details printed in the terminal output.

Can't sign in?

If the browser does not open automatically, look for a URL and code in your terminal output. Open the URL manually and enter the code to authenticate.

Help me troubleshoot my az login issue.

  • Navigate to your Terraform environment directory by running:
cd ~/azure-cloud-platform/terraform/environments/dev
  • Rebuild your AKS cluster and ACR by running:
terraform apply

What happens when you run this?

Terraform shows a plan listing every resource it will create. Review the plan, then type yes when prompted to confirm.

This can take 5-10 minutes while Azure provisions the cluster and container registry. Wait for the command to finish before moving on.

Terraform apply failed?

If you see an authentication error, run az login again and retry. Your session may have expired.

If Terraform reports a naming conflict, a resource from the previous project may not have been fully deleted. Check the Azure Portal for leftover resources in your resource group and remove them manually.

Help me fix my Terraform apply error.

  • Once Terraform finishes, reconnect kubectl to your cluster by running:
az aks get-credentials --resource-group [[RESOURCE_GROUP="your resource group name e.g. rg-cloudplatform-dev-eastus"]] --name [[AKS_CLUSTER="your AKS cluster name"]]

Where do I find these values?

Check the Terraform output that just printed in your terminal. It lists the resource group and cluster names. You can also find them by scrolling up to the plan output or checking the Azure Portal.

Before you run the next command, what do you expect to see if your cluster rebuilt successfully?

  • Verify your cluster nodes are ready by running:
kubectl get nodes

You should see your node(s) listed with a Ready status. This confirms your AKS cluster is running and kubectl is connected to it.

Nodes not showing Ready?

If the nodes show NotReady, wait 1-2 minutes and run kubectl get nodes again. The cluster may still be initializing.

If you see a connection error, double-check that you ran az aks get-credentials with the correct resource group and cluster name.

Help me fix my kubectl connection.

Install Argo CD on the cluster

Argo CD runs inside your Kubernetes cluster as a set of pods. Once installed, it watches your Git repository and continuously syncs the desired state to the cluster.

  • Create the argocd namespace and install Argo CD v3.5.1 by running these commands:
kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts -f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.1/manifests/install.yaml

What do these commands do?

  • The first command creates a dedicated namespace called argocd for all of Argo CD's components.
  • The second command downloads and applies the official Argo CD v3.5.1 manifests. This installs all the controllers, API server, and CRDs that Argo CD needs to run.

Why manifests instead of a Helm chart?

The official Argo CD documentation recommends manifest-based installation. The Helm chart for Argo CD itself is community-maintained, not official. Using manifests also avoids a chicken-and-egg problem: you would be using Helm to install the tool that will manage Helm for you.

Argo CD's pods need a moment to start. Wait about 60 seconds, then check their status.

  • Check that all Argo CD pods are running by executing:
kubectl get pods -n argocd

You should see several pods, all showing Running status. If some show ContainerCreating, wait another 30 seconds and run the command again.

Pods stuck in Pending or CrashLoopBackOff?

If pods stay in Pending, your cluster may not have enough resources. Confirm your AKS node pool has at least one node in Ready state with kubectl get nodes.

Help me troubleshoot my Argo CD pod issues.

  • Install the Argo CD CLI in WSL by running these commands:
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

What do these commands do?

  • The first command downloads the Argo CD CLI binary for Linux.
  • The second installs it to /usr/local/bin/argocd with execute permissions.
  • The third removes the downloaded file to clean up.
  • Confirm the CLI installed correctly by checking its version:
argocd version --client

You should see the Argo CD client version printed in the output.

Command not found?

If the argocd command is not found, the install step may have failed silently. Re-run the three install commands above and check that sudo did not prompt for a password you missed.

Help me fix my Argo CD CLI install.

Now retrieve the initial admin password so you have it ready for login.

  • Retrieve the Argo CD admin password by running:
argocd admin initial-password -n argocd
  • Copy the password that appears in the output. You will need it to log into the dashboard in the next substep.

Where does this password come from?

Argo CD stores the initial admin password in a Kubernetes secret called argocd-initial-admin-secret in the argocd namespace. This command reads that secret and prints the password for you.

The last piece is to access the Argo CD dashboard through your browser. The Argo CD server runs inside the cluster, so you need to forward a local port to reach it.

  • Start port-forwarding to the Argo CD server by running:
kubectl port-forward svc/argocd-server -n argocd 8080:443

What does this command do?

This forwards port 8080 on your local machine to port 443 on the Argo CD server inside the cluster. You can now reach the dashboard at https://localhost:8080.

This command takes over your terminal

Port-forwarding runs in the foreground. Your terminal will appear frozen with a Forwarding from... message. Leave it running and open a new terminal tab or window for any further commands.

Log into the Argo CD dashboard

With port-forwarding active, you can now open the Argo CD dashboard in your browser and log in with the admin credentials you retrieved.

  • Open your browser and navigate to https://localhost:8080.
  • Your browser will display a security warning about the connection. This is expected because the Argo CD server uses a self-signed certificate. Accept the warning to proceed to the login page.
  • Enter admin as the username.
  • Paste the password you copied earlier into the password field.
  • Click SIGN IN.

What do you expect to see on the dashboard right now? You have not created any Argo CD applications yet.

You should see an empty Applications page. No applications are listed because you have not wired up any Git repos yet. This empty dashboard is your starting point for GitOps delivery.

What are Applications, Projects, and Repositories in Argo CD?

An Application is the central concept. Each Application points to a source (a Git repo and path) and a destination (a cluster and namespace). It is the unit of deployment that Argo CD monitors and syncs.

A Project groups Applications together with access controls. The default project is available out of the box and is what you will use in this project.

A Repository is a Git repo that Argo CD connects to for pulling manifests. You will connect your GitHub repo when you create your first Application in the next step.

Can't reach the dashboard?

Check that the port-forwarding terminal is still running. If you see an error or the process stopped, re-run the port-forward command: kubectl port-forward svc/argocd-server -n argocd 8080:443.

Make sure you are using https:// (not http://) in the browser URL. Argo CD serves over HTTPS.

Help me access the Argo CD dashboard.

Your infrastructure is rebuilt and Argo CD is running on the cluster. Next up, you will deploy your Helm chart through Argo CD and see what Git-driven deployment looks like in action.

Deploy Your Helm Chart Through Argo CD

Your infrastructure is back online and Argo CD is running on the cluster. Right now, deploying your app means running helm install manually. That works, but it means deployments depend on whoever has cluster access and remembers the right command.

In this step, you will switch to a GitOps delivery model. Instead of running Helm commands by hand, you will create a declarative Application manifest that tells Argo CD where your chart lives in Git and where to deploy it. Then you will watch Argo CD pull the chart from your repo and deploy it to the cluster for you.

In this step, get ready to:
  • Move your values files into the chart directory so Argo CD can resolve them.
  • Create and apply an Argo CD Application manifest that points to your Helm chart in GitHub.
  • Trigger a sync and verify the application is healthy.
Reorganize your values files

Your values-dev.yaml and values-staging.yaml currently sit at the repo root. Argo CD resolves valueFiles paths relative to the chart directory, not the repo root. If you leave them where they are, Argo CD will not be able to find them.

  • In your terminal, navigate to the root of your repository by running:
cd ~/azure-cloud-platform
  • Move both values files into the cloud-app-chart/ directory by running these commands:
mv values-dev.yaml cloud-app-chart/
mv values-staging.yaml cloud-app-chart/
  • Confirm the files landed in the right place by running:
ls cloud-app-chart/

You should see values-dev.yaml and values-staging.yaml listed alongside the existing chart files like Chart.yaml and values.yaml.

Don't see the values files?

Make sure you ran the mv commands from the repo root (~/azure-cloud-platform), not from inside cloud-app-chart/. If you were inside the chart directory, the relative paths would not resolve.

help me find where my values files ended up after the mv command

  • Commit and push the reorganized files to GitHub by running:
git add .
git commit -m "Move values files into chart directory"
git push

You should see the push complete with a summary of changes. Your GitHub repo now has the values files inside cloud-app-chart/ instead of at the root.

Why move the files?

Argo CD resolves valueFiles paths relative to the spec.source.path directory defined in the Application manifest. Since your chart lives at cloud-app-chart/, a reference to values-dev.yaml means Argo CD looks for cloud-app-chart/values-dev.yaml.

Moving the files into the chart directory keeps everything in one place and avoids path-resolution issues.

Create an Argo CD Application manifest

An Argo CD Application is a Kubernetes custom resource that declaratively defines what to deploy, where the source lives, and where to put it on the cluster. Instead of typing helm install with flags, you write this once in a YAML file and apply it.

  • Create a new argocd/ directory to hold your Application manifests by running:
mkdir argocd
  • Create a file called application-dev.yaml inside the argocd/ directory and paste the following content:
# Argo CD Application for the dev environment
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nextwork-dev
  namespace: argocd
spec:
  # Use the default Argo CD project
  project: default
  # Point to the Helm chart in your GitHub repo
  source:
    repoURL: [[GITHUB_REPO_URL="https://github.com/your-username/azure-cloud-platform.git"]]
    targetRevision: HEAD
    path: cloud-app-chart
    helm:
      valueFiles:
        - values-dev.yaml
  # Deploy to the dev namespace on this cluster
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  # Create the namespace if it doesn't exist yet
  syncPolicy:
    syncOptions:
      - CreateNamespace=true

What does this manifest do?

  • source.repoURL tells Argo CD which Git repository to pull from. targetRevision: HEAD means it always tracks the latest commit.
  • source.path points to cloud-app-chart, the directory containing your Helm chart.
  • helm.valueFiles tells Argo CD to layer values-dev.yaml on top of the default values.yaml when rendering the chart.
  • destination.server points to the local cluster (the same one Argo CD runs on). destination.namespace puts the resources into dev.
  • CreateNamespace=true tells Argo CD to create the dev namespace automatically if it does not exist yet.

Helm template, not Helm install

Argo CD uses Helm only to inflate charts with helm template. The lifecycle of the application (sync, health checks, rollback) is managed entirely by Argo CD, not by Helm.

This means helm ls will not show Argo CD-managed releases. Argo CD is the source of truth for what is deployed, not Helm's release database.

  • Save the file, then apply the Application manifest to your cluster by running:
kubectl apply -f argocd/application-dev.yaml -n argocd

You should see output confirming the Application was created, such as application.argoproj.io/nextwork-dev created.

Seeing a validation error?

Check that the indentation in your YAML is correct. YAML uses spaces, not tabs. Each nested level is indented by two spaces.

Also confirm you replaced the repoURL placeholder with your actual GitHub repository URL.

help me fix my Argo CD Application manifest YAML

✔️ Awesome, I've got everything!

Great. Double check that argocd/application-dev.yaml is saved, then move on.

ⓧ I'd like to double check the full code

Here is the full argocd/application-dev.yaml for this step. Make sure your file matches this exactly (with your own repo URL):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nextwork-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: [[GITHUB_REPO_URL="https://github.com/your-username/azure-cloud-platform.git"]]
    targetRevision: HEAD
    path: cloud-app-chart
    helm:
      valueFiles:
        - values-dev.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
Trigger a sync and watch Argo CD deploy

The Application resource exists on the cluster now, but nothing has been deployed yet. Argo CD knows about your chart, but it has not synced it. You need to trigger the first sync manually.

  • Return to the Argo CD dashboard at https://localhost:8080 in your browser.
  • You should see a new application tile called nextwork-dev. Its sync status shows OutOfSync and its health shows Missing. This is expected. No resources have been deployed to the cluster yet.
  • Click on the nextwork-dev application tile to open its detail view.
  • Click the SYNC button in the application header.
  • A sync options dialog appears. Leave the defaults and click SYNCHRONIZE.

Watch the resource tree populate as Argo CD renders your Helm chart and creates each Kubernetes resource. After a few seconds, the application status should change to Synced and Healthy.

What do Synced and Healthy mean?

Synced means the live cluster state matches the desired state defined in Git. Every resource Argo CD expected to find is present and configured correctly.

Healthy means all deployed resources are actually working. For example, pods are running, services have endpoints, and deployments have the expected number of ready replicas.

An application can be Synced but not Healthy if the manifests were applied correctly but a pod keeps crashing. You will see this exact situation in the Secret Mission.

Before you run the next command, what sync status and health status do you expect to see for nextwork-dev?

  • Verify the application status from the CLI by running:
argocd app get nextwork-dev --port-forward-namespace argocd

You should see Sync Status: Synced and Health Status: Healthy in the output.

  • Confirm the application pods are running in the dev namespace by running:
kubectl get pods -n dev

You should see your application pods listed with a Running status. These pods were created entirely by Argo CD pulling your Helm chart from Git. You never ran helm install.

Application stuck on Progressing?

If the health status shows Progressing for more than a minute, your pods may be failing to start. Run kubectl describe pods -n dev to check for image pull errors. Make sure your ACR contains the container image referenced in your Helm chart's values.

If the sync status shows OutOfSync after you clicked SYNCHRONIZE, check that your GitHub repo URL in the Application manifest is correct and that the branch has your latest push with the moved values files.

help me troubleshoot my Argo CD application sync

Your Helm chart is now fully managed by Argo CD. Every resource in the dev namespace was deployed from Git, not from a manual command. But what happens when someone makes a change directly on the cluster, bypassing Git? In the next step, you will break the cluster on purpose and watch how Argo CD responds.

Break the Cluster and Watch Argo CD Detect Drift

Your Helm chart is now deployed through Argo CD. Git is the source of truth, and the dashboard confirms everything is synced and healthy.

In production, someone will inevitably make a manual kubectl change to "quick-fix" something on the cluster. Right now, Argo CD would detect that change but do nothing about it.

In this step, you will simulate that exact scenario. You will break your own cluster, watch Argo CD flag the drift, and then enable self-healing so the cluster always snaps back to the Git-defined state.

In this step, get ready to:
  • Make a manual kubectl change to the cluster, bypassing Git entirely.
  • Watch Argo CD detect the drift and report the application as OutOfSync.
  • Enable auto-sync with self-healing so Argo CD automatically corrects drift.
Make a manual change outside of Git

In a GitOps world, every change to the cluster should flow through a Git commit. But what happens when someone runs a quick kubectl command directly against the cluster instead?

The cluster's actual state drifts from the state defined in Git. Let's cause some drift on purpose by scaling your deployment replicas directly.

  • Find the name of your deployment in the dev namespace by running:
kubectl get deployments -n dev
  • Note the deployment name shown in the NAME column. You will use this name in the next command.
  • Scale that deployment to 5 replicas by running:
kubectl scale deployment [[DEPLOYMENT_NAME="your deployment name from the output above"]] --replicas=5 -n dev

You should see deployment.apps/<your-deployment> scaled confirming the change.

  • Confirm the scaling worked by running:
kubectl get pods -n dev

You should see 5 pods listed, up from whatever number your Helm chart originally defined.

What is drift?

You just changed the cluster's state directly, without updating Git. Your values-dev.yaml still defines the original replica count, but the cluster now has 5.

This mismatch between what Git says the cluster should look like and what the cluster actually looks like is called drift. It is one of the most common problems in Kubernetes operations.

Watch Argo CD detect the drift

Argo CD continuously compares what is running on the cluster with what is defined in Git. Let's see what it thinks about the change you just made.

Before you look at the dashboard, take a guess: what do you think happened to the nextwork-dev application's sync status?

  • Switch back to the Argo CD dashboard at https://localhost:8080 in your browser.

The application status has changed from Synced to OutOfSync. Argo CD detected that the cluster no longer matches what Git defines.

  • Click on the nextwork-dev application to open its detail view.
  • Click App Diff to see exactly what changed between Git and the cluster.

The diff view highlights the replica count difference between the Git-defined state and the cluster's actual state. This is the same view you would use on the job to investigate unexpected changes.

  • Confirm the OutOfSync status from the CLI by running:
argocd app get nextwork-dev --port-forward-namespace argocd

The output shows Sync Status: OutOfSync. Argo CD knows something is wrong, but it is not configured to fix it automatically.

Why doesn't Argo CD fix it automatically?

By default, Argo CD only detects drift. It does not auto-correct it. This is a safety feature. Some teams want to review and approve every change before Argo CD applies it.

In the next substep, you will enable auto-sync with self-healing so Argo CD corrects drift on its own.

Still seeing Synced instead of OutOfSync?

Argo CD polls Git on an interval. It may take a moment for the status to refresh. Click the Refresh button on the application in the Argo CD dashboard to force a re-check.

Also confirm your kubectl scale command targeted the correct namespace (-n dev) and used the right deployment name from the earlier output.

Help me figure out why Argo CD is not showing OutOfSync after my manual kubectl change.

Enable auto-sync with self-heal

Drift detection alone is not enough. You saw that Argo CD flagged the problem, but it left the cluster in the drifted state. On a real team, you would want Argo CD to automatically revert manual changes so the cluster always matches Git.

You will now update the Application manifest to enable auto-sync with self-healing. This turns Argo CD from a passive observer into an active enforcer.

  • Return to argocd/application-dev.yaml in VS Code.
  • Find the syncPolicy: section near the bottom of the file:
  syncPolicy:
    syncOptions:
      - CreateNamespace=true
  • Add the automated block between syncPolicy: and syncOptions: so the section now looks like this:
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - CreateNamespace=true

What do selfHeal and prune do?

  • selfHeal: true tells Argo CD to revert any manual changes made directly on the cluster. If someone runs a kubectl command that changes a resource, Argo CD overwrites it with the Git-defined state.
  • prune: true tells Argo CD to delete any Kubernetes resources that were removed from Git. If you delete a manifest from your repo, Argo CD removes the corresponding resource from the cluster.
  • Save argocd/application-dev.yaml.
  • Apply the updated manifest to the cluster by running:
kubectl apply -f argocd/application-dev.yaml -n argocd

You should see application.argoproj.io/nextwork-dev configured confirming the update.

Seeing a YAML syntax error?

YAML is indentation-sensitive. Make sure automated: is indented at the same level as syncOptions: (4 spaces in from the start of syncPolicy:). selfHeal: and prune: should each be 2 more spaces under automated:.

Help me fix a YAML indentation error in my Argo CD Application manifest.

✔️ Awesome, I've got everything!

Great. Double check that you have saved argocd/application-dev.yaml and that the kubectl apply command returned configured.

ⓧ I'd like to double check the full code

Here is the complete argocd/application-dev.yaml after adding auto-sync:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nextwork-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-username/azure-cloud-platform.git
    targetRevision: HEAD
    path: cloud-app-chart
    helm:
      valueFiles:
        - values-dev.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - CreateNamespace=true

Now let's prove that self-healing actually works. You are going to make the same kind of manual change again. Before you run the next command, ask yourself: do you think the replica count will stay at 5, or will Argo CD revert it?

  • Scale your deployment to 5 replicas again by running:
kubectl scale deployment [[DEPLOYMENT_NAME="your deployment name from earlier"]] --replicas=5 -n dev
  • Wait about 10-15 seconds, then check the pod count by running:
kubectl get pods -n dev

The replica count has reverted to the Git-defined value automatically. Argo CD detected the manual change and overwrote it with the state from your Helm chart's values-dev.yaml.

  • Confirm the application is synced again by running:
argocd app get nextwork-dev --port-forward-namespace argocd

The output now shows Sync Status: Synced and Health Status: Healthy. Self-healing brought the cluster back in line with Git.

Why does this matter on the job?

With self-healing enabled, Git is the only way to change your cluster's state permanently. Any manual kubectl change gets automatically reverted within seconds.

This gives your team a complete audit trail of every change (through Git commits) and prevents "shadow" changes that nobody knows about.

Replicas not reverting?

Self-healing can take up to 15 seconds to kick in. Wait a moment and run kubectl get pods -n dev again.

If the count still does not revert, make sure your kubectl apply command returned configured (not unchanged). If it said unchanged, the automated block was not applied. Re-check your YAML indentation and re-apply.

Help me figure out why Argo CD self-heal is not reverting my manual kubectl change.

Your cluster now self-heals. Any manual change gets automatically corrected back to the Git-defined state. Next up, you will add a second environment so you can manage dev and staging side by side through separate Argo CD Applications.

Multi-Environment Promotion Through Git

In the last step, you saw Argo CD catch a manual cluster change and revert it automatically. Your dev environment is now self-healing.

Real teams don't manage just one environment. They run dev, staging, and production from the same Helm chart with different configuration values. In this step, you'll add a staging environment to Argo CD and practice the promotion workflow: change dev through Git, verify it, then promote the same change to staging.

In this step, get ready to:
  • Create a staging Argo CD Application alongside the existing dev Application.
  • Push a Git change and watch dev auto-sync while staging stays unchanged.
  • Promote the change to staging through a separate Git commit.
Create a staging Application manifest

Your nextwork-dev Application points to values-dev.yaml. Staging needs its own Application that reads from values-staging.yaml and deploys to a separate staging namespace.

  • In VS Code's Explorer sidebar, right-click the argocd/ folder and select New File.
  • Name the file application-staging.yaml.
  • Paste the following manifest into the new file:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nextwork-staging
  namespace: argocd
spec:
  project: default
  source:
    # Same repo and chart as dev
    repoURL: https://github.com/[[YOUR_GITHUB_USERNAME="your GitHub username"]]/azure-cloud-platform.git
    targetRevision: HEAD
    path: cloud-app-chart
    helm:
      valueFiles:
        - values-staging.yaml  # Different values file for staging config
  destination:
    server: https://kubernetes.default.svc
    namespace: staging  # Deploys to the staging namespace instead of dev
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - CreateNamespace=true

What does this manifest do?

This Application resource is nearly identical to your dev Application. Three things differ:

  • valueFiles points to values-staging.yaml so staging gets its own configuration (different replica counts, resource limits, or environment variables).
  • destination.namespace is staging instead of dev, keeping the two environments fully isolated on the cluster.
  • metadata.name is nextwork-staging so Argo CD tracks it as a separate Application.
  • Save application-staging.yaml.
  • Make sure you replaced the repoURL with your actual GitHub username (the same URL you used in application-dev.yaml).

✔️ Awesome, I've got everything!

Great. Make sure you saved the file before applying it to the cluster.

ⓧ I'd like to double check the full code

Your argocd/application-staging.yaml should look exactly like this (with your real GitHub username in the repoURL):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nextwork-staging
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/[[YOUR_GITHUB_USERNAME="your GitHub username"]]/azure-cloud-platform.git
    targetRevision: HEAD
    path: cloud-app-chart
    helm:
      valueFiles:
        - values-staging.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: staging
  syncPolicy:
    automated:
      selfHeal: true
      prune: true
    syncOptions:
      - CreateNamespace=true
  • Apply the staging Application to your cluster by running this command:
kubectl apply -f argocd/application-staging.yaml -n argocd
  • Return to the Argo CD dashboard at https://localhost:8080.

You should now see two applications side by side: nextwork-dev and nextwork-staging.

Why two apps on one dashboard?

This is how teams visualize their environments at a glance. Each Application tile shows its own sync status and health status independently. You can tell immediately if dev is healthy but staging has drifted.

Don't see the staging app?

  • Make sure you ran the kubectl apply command from the root of your azure-cloud-platform repository so the file path resolves correctly.
  • Check that namespace: argocd appears under metadata in your manifest. Argo CD only watches for Application resources in its own namespace.
  • Help me troubleshoot my missing staging Application.

If you see a yellow Progressing status instead of green Healthy, wait about 30 seconds. Argo CD is creating the staging namespace and deploying your pods.

Push a change to dev and watch it sync

Both environments are now live. The real power of this setup is that each environment syncs independently from its own values file. To see this in action, you'll change the dev configuration and confirm staging stays untouched.

  • Open cloud-app-chart/values-dev.yaml in VS Code.
  • Find the replicaCount line and change its value to 3.
  • Save the file.
  • Commit and push the change by running these commands:
git add cloud-app-chart/values-dev.yaml
git commit -m "Increase dev replica count to 3"
git push
  • Return to the Argo CD dashboard.
  • Click Refresh on the nextwork-dev tile to trigger an immediate repo check.

Watch the dev Application's status cycle through OutOfSync to Synced as Argo CD applies the new replica count.

  • Verify the change reached your cluster by running:
kubectl get pods -n dev

You should see 3 pods running in the dev namespace.

  • Now check the staging namespace by running:
kubectl get pods -n staging

Staging still has its original pod count. Your Git change only touched values-dev.yaml, so Argo CD had no reason to update the staging Application.

Why does this isolation matter?

In a production environment, you never want a dev change to accidentally roll out to staging or production. Because each Argo CD Application watches a different values file, changes are isolated by default.

A commit that bumps replicas in dev cannot affect staging until someone explicitly updates values-staging.yaml too.

Still seeing the old pod count in dev?

  • Make sure you pushed your commit. Run git log --oneline -1 and confirm your latest commit message appears, then run git status to check nothing is uncommitted.
  • Confirm the repoURL in argocd/application-dev.yaml matches your GitHub repository URL exactly.
  • Click Refresh on the nextwork-dev tile in the Argo CD dashboard to force a repo poll.
  • Help me troubleshoot my dev sync issue.
Promote the change to staging

Dev is running with the updated replicas and you've confirmed it works. The promotion workflow is straightforward: apply the same change to the staging values file, commit, and push.

  • Open cloud-app-chart/values-staging.yaml in VS Code.
  • Change the replicaCount to 3 (the same value you used for dev).
  • Save the file.
  • Commit and push the staging change by running these commands:
git add cloud-app-chart/values-staging.yaml
git commit -m "Promote replica count to staging"
git push
  • Return to the Argo CD dashboard and click Refresh on the nextwork-staging tile.

Watch the staging Application sync with the new configuration.

Before you run the final check, think about what you expect to see. How many applications should appear, and what sync and health status should each one show?

  • Verify both applications by running:
argocd app list --port-forward-namespace argocd

Both nextwork-dev and nextwork-staging show Sync Status: Synced and Health Status: Healthy. Each application deployed from its own Git commit, using its own values file.

This is the promotion model

Changes flow dev-first, then staging, then production. Each promotion is a separate Git commit that updates a single values file. This gives your team a clear audit trail: you can see exactly when each environment was updated, by whom, and what changed.

This is the GitOps delivery model. Git is the single source of truth for every environment. Nobody runs helm install or kubectl apply by hand. Every cluster change traces back to a commit.

One app is Synced but the other is OutOfSync?

  • Click on the OutOfSync application in the dashboard to open its detail view. Check the diff to see what Argo CD thinks has changed.
  • Confirm you pushed both commits. Run git log --oneline -3 to see your recent commit history.
  • Click Refresh on the affected application tile to force a repo poll, then wait for auto-sync.
  • Help me troubleshoot my OutOfSync application.

Secret mission

Diagnose a Degraded Application

On day one of a real job, you will get paged because an Argo CD application has gone Degraded. In this mission, you will break your own deployment on purpose, investigate the failure using Argo CD's reporting tools, and fix it the GitOps way through a Git commit.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses an AKS cluster and ACR on Azure Pay-As-You-Go, so leaving resources running will incur ongoing charges.

Cost warning

Your AKS cluster incurs charges for the control plane and node VMs as long as it is running. ACR Basic tier also incurs a small ongoing cost. If you are not continuing to the next project immediately, choose Pause or Delete to avoid unnecessary charges.

Resources you used:

  • AKS cluster (control plane and node VMs on Pay-As-You-Go).
  • ACR (Basic tier).
  • Argo CD pods running inside the AKS cluster (no additional cost beyond cluster compute).
  • Argo CD CLI installed in WSL at /usr/local/bin/argocd.
  • Argo CD Application manifests in the argocd/ directory of your local repo.

Keep everything running

No action needed. Choose this if you are continuing to the next project immediately.

  • Your AKS cluster, ACR, and Argo CD pods will continue running.
  • The Argo CD CLI will remain installed in WSL at /usr/local/bin/argocd.
  • Your Application manifests in the argocd/ directory and values files in cloud-app-chart/ remain in your local repo and on GitHub.
  • Port-forwarding will stop when you close your terminal. Restart it with kubectl port-forward svc/argocd-server -n argocd 8080:443 next time you need the Argo CD UI.

Pause - I'll come back to this later

Stop the AKS cluster to reduce costs while preserving your cluster state. Argo CD state persists because it is stored in the cluster's etcd.

  • Stop the port-forwarding process by pressing Ctrl+C in the terminal running it.
  • Stop the AKS cluster by running:
az aks stop --name [[AKS_CLUSTER_NAME="your AKS cluster name"]] --resource-group [[RESOURCE_GROUP="your resource group name"]]

What does stopping the cluster do?

Stopping the AKS cluster deallocates the node VMs so you are not charged for compute. The cluster's etcd data (including Argo CD's state) is preserved. When you are ready to resume, start the cluster again by running:

az aks start --name [[AKS_CLUSTER_NAME="your AKS cluster name"]] --resource-group [[RESOURCE_GROUP="your resource group name"]]

Delete - I don't want to use this again

Remove all Azure resources and local tools to stop all charges and clean up your machine.

  • Stop the port-forwarding process by pressing Ctrl+C in the terminal running it.
  • Navigate to your Terraform environment directory by running:
cd ~/azure-cloud-platform/terraform/environments/dev
  • Destroy all Azure resources (AKS cluster, ACR, and associated infrastructure) by running:
terraform destroy
  • When prompted, type yes and press Enter to confirm.
  • Remove the Argo CD CLI binary by running:
sudo rm /usr/local/bin/argocd
  • Remove the Argo CD CLI configuration directory by running:
rm -rf ~/.config/argocd

What about my local repo files?

Your argocd/ directory and values files inside cloud-app-chart/ remain in your local Git repo and on GitHub. These are just YAML files with no ongoing cost. Keep them as a reference for future projects.

Nice Work!

Nice Work!

Nice work! You just built a fully automated GitOps pipeline using Argo CD on AKS. Every change to your cluster now flows through Git, and Argo CD ensures reality always matches your declared state.

You've learned how to:

  • Deployed your Helm chart through a declarative Argo CD Application manifest, replacing manual helm install with Git as the single source of truth.
  • Experienced drift detection and self-healing firsthand by making a manual kubectl change, watching Argo CD flag it as OutOfSync, and enabling auto-sync to automatically revert cluster drift.
  • Built a multi-environment promotion workflow with separate dev and staging Application manifests, each deploying from different Helm values files in the same repo.
  • Completed an optional Secret Mission to push your troubleshooting skills further.

Ready to quiz yourself?