GitOps Core Principles
GitOps is a modern continuous delivery methodology introduced by Weaveworks in 2017. It uses Git as the Single Source of Truth for infrastructure and application configuration, achieving continuous deployment through declarative practices.
According to the ArgoCD documentation, GitOps follows four core principles:
1. Declarative System
Infrastructure and application configurations are stored in Git as declarative descriptions (YAML/Helm/Kustomize):
# Example Git repository structure
infra-repo/
├── apps/
│ ├── frontend/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── configmap.yaml
│ └── backend/
│ ├── deployment.yaml
│ └── service.yaml
├── helm/
│ └── values-production.yaml
└── kustomize/
├── base/
└── overlays/
├── staging/
└── production/
The core value of declarative descriptions: configuration as documentation, Git history as audit log. Every environment change is traceable and rollback-able.
2. Version Control
All changes are recorded through Git commits, providing:
- Change audit: Who changed what, when, and why
- Version rollback:
git revertto roll back to any historical version - Change review: Code Review for configuration changes via Pull Requests
3. Automatic Synchronization
Once code is merged into the target branch, deployment to the target environment is triggered automatically — no manual deployment commands needed:
Developer submits PR → Code Review → Merge to main → ArgoCD detects change → Auto-sync to cluster
4. Continuous Reconciliation
The control plane continuously monitors drift between the cluster’s actual state and Git’s desired state, automatically correcting any divergence:
Git (desired state) ←→ ArgoCD (reconciler) ←→ Cluster (actual state)
Continuous comparison ↑↓
Drift detected → Auto-sync
The fundamental difference from traditional CI/CD: traditional CI/CD uses a Push model (CI pushes to the cluster), while GitOps uses a Pull model (an in-cluster agent pulls from Git). The Pull model doesn’t require storing cluster credentials in the CI system, providing better security.
ArgoCD Architecture
ArgoCD is a CNCF graduated project and the most mature tool in the GitOps space. It runs as a Kubernetes Controller inside the cluster, continuously reconciling Git repository state with cluster state.
Core Components
┌─────────────────────────────────────────────────────────┐
│ ArgoCD Architecture │
│ │
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ API Server │ │ Repo Server │ │ Application │ │
│ │ (gRPC/REST) │ │ (Git render) │ │ Controller │ │
│ └──────┬──────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ Git Repository │ │ │
│ │ │ (Helm/Kustomize)│ │ │
│ │ └────────────────┘ │ │
│ │ │ │
│ ┌──────▼─────────────────────────────────────▼──────┐ │
│ │ Redis (cache + state) │ │
│ └───────────────────────────────────────────────────┘ │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ K8s API Server │ │
│ └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Component | Responsibility | Key Points |
|---|---|---|
| API Server | Exposes gRPC/REST API, manages Application CRDs | Auth, Web UI, CLI interaction |
| Repo Server | Clones Git repos, renders Helm/Kustomize | Stateless service, horizontally scalable |
| Application Controller | Reconciliation loop: compares Git vs cluster state | Core controller, triggers sync operations |
| Redis | Caches Git repos and render results | Reduces Repo Server load |
| ApplicationSet Controller | Batch-generates Applications | Multi-cluster/multi-environment scenarios |
Installation
# Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Get initial 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
# Install ArgoCD CLI
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && mv argocd /usr/local/bin/
# Login
argocd login localhost:8080 --username admin --password <password>
Application CRD Configuration
Application is ArgoCD’s core CRD, defining “what content from which Git repo to sync to which cluster”:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-prod
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io # Cascade cleanup on App deletion
spec:
project: production # Associated ArgoCD Project
source:
repoURL: https://github.com/xubaojin/k8s-manifests.git
targetRevision: main # Tracked branch/tag
path: apps/frontend/overlays/production # Kustomize path
destination:
server: https://kubernetes.default.svc # Target cluster
namespace: production
syncPolicy:
automated:
prune: true # Auto-delete resources removed from Git
selfHeal: true # Auto-revert manual changes (drift correction)
syncOptions:
- CreateNamespace=true # Auto-create namespace
- PrunePropagationPolicy=foreground
- ApplyOutOfSyncOnly=true
revisionHistoryLimit: 10 # Retain 10 historical versions for rollback
Sync Strategy Details
Auto Sync:
syncPolicy:
automated:
prune: true # Resources deleted in Git are also deleted in the cluster
selfHeal: true # If someone manually modifies cluster resources via kubectl, auto-revert
selfHeal is the core of GitOps — it ensures cluster state always matches Git. If someone manually kubectl edits a Deployment’s replica count, ArgoCD will automatically restore it to the value declared in Git.
Manual Sync:
syncPolicy:
# No automated config — requires manual sync trigger
syncOptions:
- CreateNamespace=true
Suitable for production environments where changes require manual confirmation before syncing.
Helm Chart Sync
spec:
source:
repoURL: https://github.com/xubaojin/helm-charts.git
targetRevision: main
path: charts/frontend
helm:
valueFiles:
- values-production.yaml
parameters:
- name: image.tag
value: v1.2.3
- name: replicaCount
value: "3"
skipCrds: false
Kustomize Sync
spec:
source:
repoURL: https://github.com/xubaojin/k8s-manifests.git
targetRevision: main
path: apps/frontend/overlays/production
kustomize:
images:
- ghcr.io/xubaojin/frontend:v1.2.3 # Override image version
commonAnnotations:
managed-by: argocd
Multi-Environment Management: App of Apps Pattern
When managing multiple microservices across multiple environments, the number of Applications grows exponentially. The App of Apps pattern manages multiple child Applications through a single parent Application:
root-app (Application)
├── staging-apps (Application)
│ ├── frontend-staging (Application)
│ ├── backend-staging (Application)
│ └── database-staging (Application)
└── production-apps (Application)
├── frontend-production (Application)
├── backend-production (Application)
└── database-production (Application)
Root Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/xubaojin/k8s-manifests.git
targetRevision: main
path: argocd/apps # This directory contains child Application definitions
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: true
Child Application Directory Structure
argocd/
├── apps/
│ ├── staging/
│ │ ├── frontend.yaml # Application CRD
│ │ ├── backend.yaml
│ │ └── database.yaml
│ ├── production/
│ │ ├── frontend.yaml
│ │ ├── backend.yaml
│ │ └── database.yaml
│ └── kustomization.yaml # Aggregate all child Applications
└── projects/
├── staging.yaml # ArgoCD Project
└── production.yaml
kustomization.yaml aggregates all child Applications:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- staging/
- production/
ArgoCD Project Isolation
Projects provide multi-tenant isolation, restricting which clusters and namespaces an Application can operate on:
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: production
namespace: argocd
spec:
description: Production environment project
sourceRepos:
- https://github.com/xubaojin/k8s-manifests.git
destinations:
- server: https://kubernetes.default.svc
namespace: production
- server: https://kubernetes.default.svc
namespace: production-*
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceWhitelist:
- group: '*'
kind: '*'
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota # Disallow modifying ResourceQuota
roles:
- name: developer
policies:
- p, proj:production:developer, applications, sync, production/*, allow
groups:
- github:dev-team
ArgoCD CD Workflow in Practice
A complete GitOps CD workflow from code commit to production deployment:
Developer Push → Git triggers CI → Build image → Update Manifest repo → ArgoCD detects → Sync to cluster
Complete Flow
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Git Push │───►│ CI Build │───►│ Push │───►│ Update │───►│ ArgoCD │
│ (app code)│ │(test/build)│ │ (Registry)│ │ Manifest │ │ Auto-sync│
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
CI Pipeline (GitHub Actions Example)
# .github/workflows/ci.yml
name: CI Build and Deploy
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout application code
uses: actions/checkout@v4
- name: Go tests
run: |
go test ./... -v -coverprofile=coverage.out
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ github.sha }}
ghcr.io/${{ github.repository }}:latest
- name: Update manifest repository
env:
GH_TOKEN: ${{ secrets.MANIFEST_REPO_TOKEN }}
run: |
# Clone manifest repo
git clone https://x-access-token:${GH_TOKEN}@github.com/xubaojin/k8s-manifests.git
cd k8s-manifests
# Update image version (using yq)
yq -i ".spec.template.spec.containers[0].image = \"ghcr.io/${{ github.repository }}:${{ github.sha }}\"" \
apps/frontend/overlays/production/deployment-patch.yaml
# Commit and push
git config user.name "CI Bot"
git config user.email "ci-bot@sre.wang"
git add .
git commit -m "chore: update frontend image to ${{ github.sha }}"
git push origin main
ArgoCD Detection and Sync
After CI pushes the manifest update, ArgoCD detects the change within the default 3-minute window and triggers a sync. The polling interval can be adjusted via the argocd-cm ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
# Set Git polling interval (seconds)
timeout.reconciliation: "180"
# Use Webhook instead of polling (recommended)
# Real-time trigger after configuring Git Webhook
The more recommended approach is to configure a Git Webhook, which triggers sync immediately upon push without waiting for polling:
# Configure Webhook in Git repository pointing to ArgoCD
# Payload URL: https://argocd.sre.wang/api/webhook
# Content type: application/json
# ArgoCD Webhook configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
webhook.github.secret: "your-webhook-secret"
Sync Status Monitoring
# View sync status of all Applications
argocd app list
# View details of a specific Application
argocd app get frontend-production
# Manually trigger sync
argocd app sync frontend-production
# View sync history
argocd app history frontend-production
# Rollback to a historical version
argocd app rollback frontend-production <revision-id>
Drift Detection Alerts
When someone manually modifies cluster resources causing drift, you should configure alert notifications:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: frontend-production
namespace: argocd
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: ops-alerts
notifications.argoproj.io/subscribe.on-health-degraded.slack: ops-alerts
notifications.argoproj.io/subscribe.on-sync-failed.slack: ops-alerts
spec:
# ... other configuration
ArgoCD Notifications supports Slack, Teams, email, and other notification channels. Key events include:
| Event | Description | Suggested Alert Level |
|---|---|---|
on-sync-succeeded | Sync succeeded | Info (optional) |
on-sync-failed | Sync failed | Critical |
on-health-degraded | Application health degraded | Critical |
on-deployed | Deployment completed | Info |
on-created | Application created | Warning |
Summary
GitOps is not just a tool choice — it’s a paradigm shift in operations. Its core values include:
- Security: Cluster credentials are not exposed in the CI system; Git permissions serve as deployment permissions
- Auditable: All changes are recorded through Git commits, providing natural compliance
- Rollback-able:
git revertto roll back — no additional rollback tools needed - Drift correction: The selfHeal mechanism ensures cluster state always matches the desired state
As the core component of GitOps, ArgoCD manages application lifecycles declaratively through Application CRDs, the App of Apps pattern enables multi-environment scale, and seamless integration with CI Pipelines forms a complete CD chain.
Production implementation recommendation: use Auto Sync + selfHeal for staging environments for rapid validation, and Manual Sync with manual confirmation + Webhook real-time notifications for production environments. Adopt a progressive approach — start with non-critical applications as pilots, then gradually expand coverage as you gain experience.
References & Acknowledgments
This article referenced the following materials during writing. We thank the original authors for their contributions:
- ArgoCD documentation — Argo Project, referenced for ArgoCD documentation