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 revert to 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                         │ │
│  └───────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
ComponentResponsibilityKey Points
API ServerExposes gRPC/REST API, manages Application CRDsAuth, Web UI, CLI interaction
Repo ServerClones Git repos, renders Helm/KustomizeStateless service, horizontally scalable
Application ControllerReconciliation loop: compares Git vs cluster stateCore controller, triggers sync operations
RedisCaches Git repos and render resultsReduces Repo Server load
ApplicationSet ControllerBatch-generates ApplicationsMulti-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:

EventDescriptionSuggested Alert Level
on-sync-succeededSync succeededInfo (optional)
on-sync-failedSync failedCritical
on-health-degradedApplication health degradedCritical
on-deployedDeployment completedInfo
on-createdApplication createdWarning

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 revert to 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:

  1. ArgoCD documentation — Argo Project, referenced for ArgoCD documentation