Home/Infrastructure/Fully Automating Kubernetes Deployments with GitOps and Argo CD
InfrastructureGitOpsArgoCD

Fully Automating Kubernetes Deployments with GitOps and Argo CD

GitOps treats Git as the single source of truth so every commit becomes a deployment. This guide walks through Argo CD install, Kustomize overlays, CI wiring, secrets, drift, and the day-2 pitfalls that actually break GitOps in production.

Fully Automating Kubernetes Deployments with GitOps and Argo CD
Contents
  1. What Is GitOps
  2. Installing Argo CD
  3. Repository Structure
  4. Defining an Argo CD Application
  5. Per-Environment Kustomize Config
  6. Wiring Up the CI/CD Pipeline
  7. Secret Management — GitOps's Hardest Problem
  8. When You Scale — App of Apps & Multi-Cluster
  9. Drift Detection and Rollback
  10. Diagnostic Decision Table by Symptom
  11. When an Application Is Stuck OutOfSync or Degraded
  12. FAQ
  13. Editor's Note — From the Field
  14. References

What Is GitOps

GitOps is a methodology that uses a Git repository as the "single source of truth" to manage infrastructure and application deployments. The core idea is Git commit = automated deployment.

Installing Argo CD

Bash
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# check
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

Repository Structure

CODE
gitops-repo/
├── apps/
│   └── my-app/
│       ├── base/
│       │   ├── deployment.yaml
│       │   └── kustomization.yaml
│       └── overlays/
│           ├── staging/
│           └── prod/
└── argocd/
    └── applications/

Defining an Argo CD Application

YAML
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app-prod
  namespace: argocd
spec:
  source:
    repoURL: https://github.com/my-org/gitops-repo
    targetRevision: main
    path: apps/my-app/overlays/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
 prune: true # Git
 selfHeal: true # when

Per-Environment Kustomize Config

YAML
# overlays/prod/kustomization.yaml
resources:
- ../../base

images:
- name: my-app
  newTag: v1.2.3

patches:
- path: patch-replicas.yaml

Wiring Up the CI/CD Pipeline

YAML
- name: Update GitOps Repo
  run: |
    git clone https://github.com/my-org/gitops-repo
    cd gitops-repo/apps/my-app/overlays/prod
    kustomize edit set image my-app=my-registry/my-app:${{ github.sha }}
    git add -A
    git commit -m "chore: update to ${{ github.sha }}"
    git push

GitOps is more than deployment automation — it is a paradigm shift in how you operate. You can fully reconstruct everything happening in the cluster from Git history alone.

Secret Management — GitOps's Hardest Problem

"Put everything in Git" is the principle, but you must not commit passwords and keys in plaintext. Common approaches:

ApproachCharacteristics
Sealed SecretsEncrypt with a public key, store in Git, decrypt only in the cluster
External Secrets OperatorReference an external store such as Vault or AWS Secrets Manager
SOPS + age/KMSFile-level encryption, still reviewable in PRs

When You Scale — App of Apps & Multi-Cluster

Once you have dozens of applications, you manage Argo CD Applications with another Application using the App of Apps pattern, or templatize declarations with ApplicationSet. Multiple clusters (staging/prod/per-region) can also be managed as targets from a single Argo CD instance.

Drift Detection and Rollback

selfHeal: true automatically restores Git state even if someone changes the cluster directly with kubectl edit. Rollback during an incident is simply a Git revert — revert to a previous commit and Argo CD syncs. Deployment history = Git history is GitOps's biggest advantage.

Diagnostic Decision Table by Symptom

Practical diagnostic paths for situations you actually hit when running Argo CD.

SymptomCheck firstResponse
OutOfSync stuckCheck the actual diff with argocd app diffIf another actor (HPA, webhook, operator) is mutating fields rather than the controller, register ignoreDifferences
Sync succeeds but pods never come upPod events (kubectl describe pod), not Application statusArgo CD is only responsible through applying manifests — image pull failures and resource shortages are Kubernetes-layer problems
Drift repeatedly detectedAudit logs for who is making manual kubectl changesBlock the manual-change habit before enabling selfHeal (without removing the cause, selfHeal only leaves you fighting the cluster)
Slow to apply after a Git pushPolling interval (default 3 minutes) vs webhook configRegister a webhook for immediate sync; keep polling as a fallback
Secret changes not appliedExternal Secrets / SealedSecrets controller logsSecret tools are separate controllers outside Argo CD — check each one's sync interval

When an Application Is Stuck OutOfSync or Degraded

Common Argo CD states in operation: it stays OutOfSync even after syncing, or it syncs but Health shows Degraded.

Causes

  • Controllers or webhooks fill in fields automatically (e.g., replicas changed by an HPA, annotations injected by a webhook), so it always differs from Git
  • A custom resource is applied before its CRD exists and fails
  • New Pods never pass readiness, so the rollout never completes

Diagnosis

Bash
argocd app get myapp --refresh
argocd app diff myapp              # actual difference between Git and cluster
kubectl -n myapp get events --sort-by=.lastTimestamp | tail -20
kubectl -n myapp rollout status deploy/api

Fix

  • Register controller-managed fields in the Application's ignoreDifferences (e.g., the Deployment's /spec/replicas when using an HPA).
  • Order CRDs and custom resources with the sync-wave annotation (argocd.argoproj.io/sync-wave).
  • Degraded is a workload problem, not an Argo CD problem: find the cause in events and Pod logs, then fix it in Git (direct cluster edits are reverted on the next sync).

FAQ

Q. Argo CD or Flux? Argo CD is strong on UI, multi-tenancy, and App of Apps; Flux is strong as a lightweight GitOps toolkit combination. If dashboards and RBAC matter, Argo CD has a lower barrier to entry.

Q. Isn't enabling selfHeal dangerous? Emergency manual patches can be reverted immediately, so ops policy must already enforce "changes always go through Git." That discipline is also the core of GitOps.

Editor's Note — From the Field

What breaks most often in early GitOps adoption is not Argo CD but people's habits. When things get urgent, someone kubectl edits directly, and at that moment Git and the cluster drift apart. Turn on selfHeal and those changes auto-rollback — then complaints flood in: "why did my fix disappear?" In the end GitOps is not a tool; it only works once the discipline "every change goes through a PR" is established. The tool is just the mechanism that enforces that discipline.

References

✦ ✦ ✦
Sources and verification

Sources and checks vary by article. Only articles with a recorded check date, scope and sources below were checked, and only within that scope. For other articles, verify against the current docs for your version before applying anything, and email us about errors. Editorial policy · email us

This article has no recorded human check (date and scope) yet.

Published ·
Topic-related official docs (auto-linked · not per-claim sources)Kubernetes documentation ↗Git documentation ↗

Comments

Be the first to comment.