The GitOps Principle
GitOps positions Git as the single source of truth for the desired state of your infrastructure. Every change — deployment, configuration update, scaling — must go through a Pull Request in a Git repository. Operators never connect directly to clusters to make manual changes. ArgoCD continuously monitors the repository and reconciles the cluster's real state with the state declared in Git.
This model delivers considerable benefits: complete auditability (every change is a commit with author and timestamp), trivial rollback (Git revert), multi-environment consistency, and automatic recovery from configuration drift.
Recommended Architecture: Separate Repositories
Best practice separates the application code repository from the Kubernetes configuration repository. This allows independent CI/CD pipelines and avoids mixing deployment logic with business code.
Git Repositories:
├── app-source/ # Application code (CI → build → push image)
└── app-config/ # Kubernetes manifests (GitOps → ArgoCD)
├── base/ # Common configuration
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── dev/ # Dev overrides (replicas=1, small resources)
├── staging/ # Staging overrides
└── prod/ # Prod overrides (replicas=3, HPA, PDB)
ArgoCD Applications:
├── app-dev → app-config/overlays/dev (automated sync)
├── app-staging → app-config/overlays/staging (automated sync)
└── app-prod → app-config/overlays/prod (MANUAL sync — approval required)
ArgoCD Installation
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Access the UI
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Retrieve initial admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
Defining an ArgoCD Application (CRD)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-prod
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/org/app-config
targetRevision: HEAD
path: overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Removes resources deleted from Git
selfHeal: true # Reconciles manual changes not in Git
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
CI/CD Pipeline Integration with GitHub Actions
The complete GitOps workflow:
- Developer pushes to
mainofapp-sourcerepo - GitHub Actions builds, tests, and pushes a new Docker image
- GitHub Actions updates the image tag in
app-config - ArgoCD detects the commit in
app-configand synchronises the cluster
- name: Build and push image
run: |
docker build -t $REGISTRY/my-app:${{ github.sha }} .
docker push $REGISTRY/my-app:${{ github.sha }}
- name: Update image tag in config repo
run: |
git clone https://x-access-token:${{ secrets.CONFIG_REPO_TOKEN }}@github.com/org/app-config
cd app-config
yq e '.image.tag = "${{ github.sha }}"' -i overlays/prod/values.yaml
git commit -am "ci: update prod image to ${{ github.sha }}"
git push
Progressive Deployments with Argo Rollouts
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
strategy:
canary:
steps:
- setWeight: 10 # 10 % of traffic to new version
- pause: {duration: 5m}
- analysis: # Verify Prometheus metrics
templates: [{templateName: success-rate}]
- setWeight: 50
- pause: {duration: 10m}
- setWeight: 100
# Automatic rollback if error rate > 5 %
Conclusion
ArgoCD is the de-facto standard for implementing GitOps on Kubernetes. Its maturity, active community, and integration with the CNCF ecosystem (Argo Rollouts, Argo Workflows, Argo Events) make it a solid production choice. The real gain is not just technical — it is organisational: complete traceability of every deployment, one-command rollbacks, and the elimination of unaudited manual changes on production clusters.
