What GitOps actually means in practice
GitOps is not a tool — it's a principle: Git is the single source of truth for your infrastructure and application state. ArgoCD is the most mature implementation of this principle for Kubernetes. After running ArgoCD across production EKS clusters managing 30+ microservices, here's how to set it up properly and avoid the mistakes that bite you later.
Installation
# Install ArgoCD into its own namespace
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Wait for all pods to be ready
kubectl wait --for=condition=Ready pod -l app.kubernetes.io/name=argocd-server -n argocd --timeout=120s
# Get initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Port-forward to access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
argocd-initial-admin-secret. It contains the plain initial password and has no business existing after setup.
Repository structure that scales
How you structure your GitOps repo determines how painful your life will be at 50 apps vs 5. The pattern I use:
gitops-repo/
apps/ # ArgoCD Application manifests
api-service.yaml
worker-service.yaml
frontend.yaml
clusters/
production/
kustomization.yaml # points to apps/ with prod overlays
staging/
kustomization.yaml
base/ # shared Helm values or k8s manifests
api-service/
deployment.yaml
service.yaml
hpa.yaml
Your first Application manifest
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: api-service
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/gitops-repo
targetRevision: main
path: base/api-service
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # delete resources removed from Git
selfHeal: true # revert manual kubectl changes
syncOptions:
- CreateNamespace=true
The prune and selfHeal decision
prune: true means resources deleted from Git get deleted from the cluster. selfHeal: true means if someone runs kubectl edit directly on a resource, ArgoCD reverts it within minutes. These are powerful but need team agreement first.
selfHeal but keep prune manual initially — accidental resource deletion in prod is expensive.
Progressive delivery with Argo Rollouts
ArgoCD pairs with Argo Rollouts to give you canary and blue-green deployments as Kubernetes-native resources:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-service
spec:
strategy:
canary:
steps:
- setWeight: 10 # 10% traffic to new version
- pause: {{duration: 5m}}
- setWeight: 50
- pause: {{duration: 10m}}
- setWeight: 100 # full rollout if no issues
If error rates spike during the canary phase, you roll back with a single Git revert — ArgoCD picks it up within seconds.
Common mistakes to avoid
- Storing secrets in Git — use Sealed Secrets or External Secrets Operator. Never commit raw Kubernetes Secrets to your GitOps repo, even private ones.
- One repo for everything — separate your app config repo from your infra repo. Different change velocity, different access controls.
- Skipping RBAC — ArgoCD has its own RBAC system. Set it up before giving developers access. Default is admin for everyone.
- Not setting resource limits in synced manifests — ArgoCD will happily sync manifests without resource limits, and your cluster will hit OOM issues in production.