An ArgoCD "Application" connects a Git path to a K8s namespace. Sync policies control WHETHER and HOW changes are applied. This lesson teaches you to configure both — the core of GitOps operations.

What Is an ArgoCD Application?

SOURCE Repo: github.com/.../gitops Path: environments/staging Branch: main Application + Sync Policy DESTINATION Cluster: in-cluster (default) Namespace: staging
An Application = Source (Git path) + Destination (K8s namespace) + Sync Policy (how to deploy).

🏋️ Step 1: Populate the GitOps Repo

In your cicd-mastery-gitops repo, create Kustomize-based manifests:

base/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: cicd-mastery-api
spec:
  replicas: 2
  selector:
    matchLabels: { app: cicd-mastery-api }
  template:
    metadata:
      labels: { app: cicd-mastery-api }
    spec:
      containers:
        - name: api
          image: acrcicdmastery.azurecr.io/cicd-mastery-api:latest
          ports: [{ containerPort: 3000 }]
          readinessProbe:
            httpGet: { path: /health, port: 3000 }
            initialDelaySeconds: 5
          resources:
            requests: { cpu: 100m, memory: 128Mi }
            limits:   { cpu: 500m, memory: 256Mi }
---
apiVersion: v1
kind: Service
metadata:
  name: cicd-mastery-api
spec:
  selector: { app: cicd-mastery-api }
  ports: [{ port: 80, targetPort: 3000 }]

base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml

environments/staging/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: staging
resources:
  - ../../base
patches:
  - patch: |-
      - op: replace
        path: /spec/replicas
        value: 1
    target:
      kind: Deployment
      name: cicd-mastery-api
images:
  - name: acrcicdmastery.azurecr.io/cicd-mastery-api
    newTag: sha-abc1234   # CI will update this

Commit and push everything.

🏋️ Step 2: Create the ArgoCD Application

Create apps/staging.yaml in the GitOps repo:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cicd-mastery-staging
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default

  # WHERE to get manifests
  source:
    repoURL: https://github.com/YOUR_USER/cicd-mastery-gitops.git
    targetRevision: main
    path: environments/staging

  # WHERE to deploy
  destination:
    server: https://kubernetes.default.svc
    namespace: staging

  # HOW to sync
  syncPolicy:
    automated:
      prune: true       # Delete resources removed from Git
      selfHeal: true    # Revert manual kubectl changes
    syncOptions:
      - CreateNamespace=true
    retry:
      limit: 3
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Apply it:

kubectl apply -f apps/staging.yaml

# Or via CLI:
argocd app get cicd-mastery-staging

Open the ArgoCD UI — you should see your app appear and start syncing! 🎉

Sync Policies: The Decision Matrix

automated: true (Auto-sync) Git changes → ArgoCD immediately applies Use for: staging, dev, preview environments automated: false (Manual sync) Git changes → shows "OutOfSync" → human clicks Sync Use for: production (human approval) selfHeal: true Someone kubectl edits → ArgoCD reverts to Git Use for: ALL environments (prevent drift) prune: true Resource removed from Git → deleted from cluster Use for: staging ✓ | production: carefully ⚠️

Recommended Policies Per Environment

EnvironmentautomatedselfHealpruneWhy
Dev / PreviewFast iteration, auto-cleanup
StagingMirror prod behavior, auto-deploy
Production⚠️Human approval required, but prevent drift
Architect pattern: Staging auto-syncs (see changes immediately). Production shows "OutOfSync" and waits for manual sync — OR you use a PR-based promotion flow where merging a PR IS the approval (covered in a later lesson).

🏋️ Step 3: Test the GitOps Loop

  1. In the GitOps repo, change the image tag in environments/staging/kustomization.yaml
  2. Commit and push
  3. Watch ArgoCD UI — within 3 minutes (or instantly with webhook) it detects "OutOfSync"
  4. With automated: true, it auto-syncs. Watch pods update!

Test self-heal:

# Manually scale down (simulating someone "fixing" something)
kubectl scale deployment/cicd-mastery-api --replicas=0 -n staging

# Watch ArgoCD UI — it detects "OutOfSync" immediately
# Within seconds, self-heal kicks in and restores replicas=1

kubectl get pods -n staging -w  # Watch pods come back!

🎉 Git always wins. That's GitOps in action.

🧠 Recall Check

  1. What three things does an ArgoCD Application define?
  2. What's the difference between automated: true and manual sync for production?
  3. What does selfHeal: true do when someone runs kubectl delete pod?
  4. What does prune: true do?
Reveal answers
  1. Source (Git repo + path + branch), Destination (cluster + namespace), Sync Policy (auto/manual, selfHeal, prune).
  2. automated deploys immediately when Git changes. Manual shows "OutOfSync" and waits for someone to click Sync or run argocd app sync — giving humans a checkpoint before production changes.
  3. Kubernetes will restart the pod (that's K8s self-healing). ArgoCD won't intervene because the Deployment spec hasn't changed. But if someone kubectl edit deployment to change replicas, ArgoCD reverts it.
  4. If you delete a resource from Git (e.g., remove a Service YAML), prune: true means ArgoCD will also delete it from the cluster. Without prune, orphaned resources remain.
You now have a working GitOps loop: change Git → ArgoCD syncs → cluster updates. Manual cluster changes are self-healed. Next lesson: the complete CI→GitOps flow — how your CI pipeline triggers this loop by updating the image tag.