GitOps Best Practices¶
- GitOps is effective only when the repository structure, branching strategy, and promotion workflow are designed intentionally.
- Keeping Git as the single source of truth requires discipline: no
kubectl applyby hand, no out-of-band secrets. - A well-structured GitOps repository scales from one team to dozens without becoming a maintenance burden.
What will we learn?¶
- Mono-repo vs multi-repo strategies and when to use each
- Recommended folder structures for Kustomize and Helm GitOps repos
- Environment promotion workflows (image tag update, PR-based promotion)
- Secrets management options compatible with GitOps
- Common anti-patterns to avoid
Prerequisites¶
01. Mono-repo vs Multi-repo¶
| Strategy | Pros | Cons |
|---|---|---|
| Mono-repo | Atomic changes, single PR | RBAC harder, large repos slow |
| Multi-repo | Clear ownership, fine RBAC | Cross-service changes need multiple PRs |
| Hybrid | Config repo + app repos | Best of both worlds |
Recommended: Separate “config repo” (GitOps manifests) from “app repos” (source code).
02. Recommended Repository Structure¶
gitops-config-repo/
├── bootstrap/ # ArgoCD App-of-Apps root
│ └── root-app.yaml
├── infra/ # Cluster-wide infrastructure
│ ├── cert-manager/
│ ├── ingress-nginx/
│ └── monitoring/
├── apps/ # Application deployments
│ ├── frontend/
│ │ ├── base/
│ │ │ ├── deployment.yaml
│ │ │ └── kustomization.yaml
│ │ └── overlays/
│ │ ├── dev/
│ │ │ ├── kustomization.yaml ← image: frontend:dev-abc123
│ │ ├── staging/
│ │ └── prod/
│ └── backend/
│ └── ...
└── projects/ # AppProject CRs
├── team-alpha.yaml
└── team-beta.yaml
03. Image Tag Promotion Workflow¶
CI/CD writes back to the GitOps repo when a new image is built:
# In your CI pipeline (GitHub Actions example):
# 1. Build and push image
docker build -t registry.io/org/frontend:${GIT_SHA} .
docker push registry.io/org/frontend:${GIT_SHA}
# 2. Update the dev overlay image tag in the GitOps repo
git clone https://github.com/org/gitops-config-repo
cd gitops-config-repo
# Use kustomize edit to update the image
kustomize edit set image \
registry.io/org/frontend=registry.io/org/frontend:${GIT_SHA} \
--kustomizationfile apps/frontend/overlays/dev/kustomization.yaml
# 3. Commit and push - ArgoCD auto-syncs dev
git commit -am "promote frontend:${GIT_SHA} to dev"
git push
# 4. After dev validation, open PR to promote to staging/prod
04. Branch Strategy¶
# Recommended: environment branches map to ArgoCD targets
git branch --list
# main → production (protected, requires PR + approval)
# staging → staging environment
# dev → development (auto-merge from CI)
ArgoCD Application targets per environment:
# dev Application watches 'dev' branch
spec:
source:
targetRevision: dev
path: apps/frontend/overlays/dev
syncPolicy:
automated:
selfHeal: true
prune: true
# prod Application watches 'main' branch (manual sync recommended)
spec:
source:
targetRevision: main
path: apps/frontend/overlays/prod
syncPolicy: {} # No automated sync in prod
05. Secrets Management¶
Never commit plaintext secrets to Git. Choose one:
| Option | How it works | Complexity |
|---|---|---|
| Sealed Secrets | Encrypt with cluster public key, commit ciphertext | Low |
| External Secrets Operator | Reference AWS/GCP/Vault secrets by name | Medium |
| SOPS + age/GPG | Encrypt files before commit, decrypt at deploy time | Medium |
| Vault + ArgoCD Vault Plugin | Inject secrets from Vault at sync time | High |
# Sealed Secrets quick example
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
git add sealed-secret.yaml # Safe to commit
06. Anti-Patterns to Avoid¶
❌ kubectl apply by hand on production → Use ArgoCD sync only
❌ Storing plaintext secrets in Git → Use Sealed Secrets or ESO
❌ One giant repository with no structure → Use the folder hierarchy above
❌ Disabling selfHeal in production → Enable with caution + alerts
❌ Auto-sync + prune in prod without review → Use manual sync gates for prod
❌ Different app versions per env in one file → Use overlays / values files
Hands-on Tasks¶
- Create a Kustomize-based GitOps repo with
base/and three overlays (dev,staging,prod) - Write a shell script that updates the image tag in the dev overlay and commits the change
- Create ArgoCD Applications pointing to each overlay with appropriate sync policies
- Install Sealed Secrets and encrypt a Kubernetes Secret - commit the sealed version
- Document your team’s Git branching strategy and which ArgoCD sync policy maps to each branch
08. Summary¶
- Separate the GitOps config repo from application source repos - this gives clean RBAC and promotion boundaries
- Use Kustomize overlays or Helm values files per environment rather than duplicating full manifests
- CI writes image tags back to Git; ArgoCD detects the commit and deploys - no
kubectlin CI pipelines - Production sync should be manual (or require PR approval) to prevent accidental auto-deploys
- Never commit plaintext secrets - use Sealed Secrets, External Secrets Operator, or SOPS