Active Nerds
Module #6 · advanced Article

GitOps Workflow: Declarative Infrastructure Management with ArgoCD and Flux

GitOps treats Git as the single source of truth for cluster state — changes happen via Git commits (not kubectl), and a controller continuously reconciles cl...

5 min read+20 XPPublished 2026-06-01

Quick Answer: GitOps treats Git as the single source of truth for cluster state — changes happen via Git commits (not kubectl), and a controller continuously reconciles cluster state to match Git, giving you audit trails, rollbacks, and drift detection for free.

Detailed Answer:

| Dimension | Traditional CI/CD | GitOps | |---|---|---| | Deployment trigger | CI pipeline runs kubectl | Git commit detected by controller | | Direction | Push (CI pushes to cluster) | Pull (controller pulls from Git) | | Cluster credentials | CI server holds kubeconfig | Controller runs inside cluster | | Audit trail | CI logs (ephemeral) | Git history (permanent) | | Rollback | Re-run old pipeline | git revert → auto-synced | | Drift detection | None by default | Continuous — alerts on drift | | Security | Wide blast radius (kubeconfig in CI) | Narrow (controller has scoped RBAC) |

GitOps Principles (OpenGitOps):

1. Declarative  — Entire system described declaratively in Git
2. Versioned    — Git is the single source of truth, versioned and immutable
3. Pulled       — Approved changes auto-applied by software agents (not pushed)
4. Continuous   — Software agents continuously reconcile desired vs actual state

ArgoCD vs Flux Comparison:

| Feature | ArgoCD | Flux | |---|---|---| | UI | Rich built-in web UI | CLI-first (Weave GitOps UI separate) | | Multi-tenancy | AppProjects for strong isolation | Tenancy via namespace + RBAC | | Architecture | Centralized server + agents | Distributed controllers per cluster | | Helm support | First-class | First-class | | Kustomize support | First-class | First-class | | Notifications | Plugin-based | Notification controller built-in | | Best for | Teams wanting visibility + UI | GitOps-native, modular approach |

Implementing GitOps Workflow:

# Developer workflow with GitOps:

# 1. Create feature branch
git checkout -b feature/update-config

# 2. Make changes to K8s manifests
vim overlays/production/kustomization.yaml
# Change: newTag: v1.2.3 → newTag: v1.3.0

# 3. Open Merge Request — triggers CI validation
# CI runs: kubectl diff, kube-score, trivy manifest scan, conftest policy check

# 4. Team reviews and approves MR
# 5. Merge to main
# 6. ArgoCD detects change within 3 minutes (or via webhook instantly)
# 7. ArgoCD syncs cluster to new state
# 8. ArgoCD reports sync status (healthy/degraded) back to GitLab commit status

# Rollback is just a git revert:
git revert HEAD
git push origin main
# ArgoCD detects revert → re-applies previous state automatically

Drift Detection and Self-Healing:

# ArgoCD self-heal — reverts manual kubectl changes automatically
syncPolicy:
  automated:
    selfHeal: true          # Revert any kubectl edit/patch in the cluster
    prune: true             # Delete resources removed from Git

# What happens when someone runs kubectl edit deployment in production:
# 1. Change applied immediately to cluster
# 2. ArgoCD detects drift within 3 minutes
# 3. ArgoCD reverts to Git state (if selfHeal: true)
# 4. Slack/PagerDuty notification: "Out of sync detected on production"
# 5. Engineer must make change via Git MR instead

Notification Setup:

# ArgoCD Notifications — alert on sync failures
apiVersion: v1
kind: ConfigMap
metadata:
  name: argocd-notifications-cm
  namespace: argocd
data:
  trigger.on-sync-failed: |
    - when: app.status.operationState.phase in ['Error', 'Failed']
      send: [slack-notification]
  template.slack-notification: |
    message: |
      Application {{.app.metadata.name}} sync {{.app.status.operationState.phase}}
      Cluster: {{.app.spec.destination.server}}
      Revision: {{.app.status.sync.revision}}
      {{if .app.status.operationState.syncResult.resources}}
      Failed resources:
      {{range .app.status.operationState.syncResult.resources}}
        - {{.kind}}/{{.name}}: {{.message}}
      {{end}}{{end}}
  service.slack: |
    token: $slack-token
    channel: "#deployments"

Key Takeaway: GitOps eliminates the "who deployed what and when?" question permanently — every production change is a Git commit with an author, timestamp, and diff, making auditing, rollbacks, and compliance effortless.


Finished reading?

Mark as complete to claim your +20 XP and track progress.