ESC
Type to search guides, tutorials, and reference documentation.
Verified by Garnet Grid

GitOps Workflow Patterns

Implement GitOps to manage infrastructure and application deployments through Git as the single source of truth. Covers pull-based deployment, ArgoCD, Flux, drift detection, multi-environment promotion, and the patterns that make GitOps reliable at scale.

GitOps uses Git repositories as the single source of truth for declarative infrastructure and application deployment. Instead of running kubectl apply or clicking buttons in a cloud console, you commit a change to Git and an operator automatically reconciles the live state to match. If someone manually changes production, the GitOps operator reverts it.


Push vs Pull Deployment

Push (Traditional CI/CD):
  Code commit → CI builds → CI pushes to production
  CI has production credentials
  Production state unknown between pushes
  
Pull (GitOps):
  Code commit → Git repo updated → Operator PULLS changes
  Only operator has production credentials
  Operator continuously reconciles (drift detection)
  Git history = deployment audit trail

ArgoCD Setup

# ArgoCD Application definition
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: order-service
  namespace: argocd
spec:
  project: default
  
  source:
    repoURL: https://github.com/company/gitops-config
    targetRevision: main
    path: apps/order-service/overlays/production
  
  destination:
    server: https://kubernetes.default.svc
    namespace: order-service
  
  syncPolicy:
    automated:
      prune: true          # Delete resources removed from Git
      selfHeal: true       # Revert manual changes
      allowEmpty: false     # Don't sync if source is empty
    
    syncOptions:
      - CreateNamespace=true
      - PruneLast=true
      - ApplyOutOfSyncOnly=true
    
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Repository Structure

gitops-config/
├── apps/
│   ├── order-service/
│   │   ├── base/
│   │   │   ├── deployment.yaml
│   │   │   ├── service.yaml
│   │   │   ├── configmap.yaml
│   │   │   └── kustomization.yaml
│   │   └── overlays/
│   │       ├── development/
│   │       │   ├── kustomization.yaml
│   │       │   └── replicas-patch.yaml
│   │       ├── staging/
│   │       │   ├── kustomization.yaml
│   │       │   └── replicas-patch.yaml
│   │       └── production/
│   │           ├── kustomization.yaml
│   │           ├── replicas-patch.yaml
│   │           └── resources-patch.yaml
│   │
│   └── payment-service/
│       ├── base/
│       └── overlays/

├── infrastructure/
│   ├── monitoring/
│   ├── ingress/
│   └── cert-manager/

└── clusters/
    ├── dev-cluster/
    ├── staging-cluster/
    └── prod-cluster/

Environment Promotion

# Promotion workflow: dev → staging → production
# Each environment is a separate directory/overlay

# Step 1: Developer opens PR to update dev overlay
# Step 2: ArgoCD auto-syncs dev
# Step 3: Tests pass → PR to promote to staging
# Step 4: ArgoCD auto-syncs staging
# Step 5: Smoke tests pass → PR to promote to production
# Step 6: ArgoCD auto-syncs production (with approval gate)

# Image promotion example:
# dev:  image: registry.company.com/order-service:v1.2.4-dev
# staging: image: registry.company.com/order-service:v1.2.4-rc1
# prod: image: registry.company.com/order-service:v1.2.4

# Automated image updater (ArgoCD Image Updater):
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: >
      order=registry.company.com/order-service
    argocd-image-updater.argoproj.io/order.update-strategy: semver
    argocd-image-updater.argoproj.io/order.allow-tags: "regexp:^v\\d+\\.\\d+\\.\\d+$"

Drift Detection

What is drift?
  Someone manually changes production (kubectl edit, console click)
  Live state ≠ Git state
  
How GitOps handles drift:
  selfHeal: true → ArgoCD automatically reverts manual changes
  selfHeal: false → ArgoCD alerts but doesn't revert
  
Best practice:
  Production: selfHeal: true (no manual changes allowed)
  Development: selfHeal: false (developers need flexibility)
  
  Combined with RBAC:
  - Developers: No direct kubectl access to production
  - SREs: Emergency break-glass only (audited)
  - ArgoCD service account: Full production access

Anti-Patterns

Anti-PatternConsequenceFix
Push deployment in GitOps repoCI has production credentialsPull model with ArgoCD/Flux only
No automated syncGit and live state driftautomated + selfHeal enabled
Single repo for app + configTriggers deploy on app code changesSeparate app repo and config repo
No promotion gatesBad code reaches productionPR approvals + automated tests per env
Manual kubectl in productionBypasses Git audit trailRBAC: no human kubectl in prod

GitOps is not a tool — it is a practice. The core principle: if it is not in Git, it does not exist in production.

Jakub Dimitri Rezayev
Jakub Dimitri Rezayev
Founder & Chief Architect • Garnet Grid Consulting

Jakub holds an M.S. in Customer Intelligence & Analytics and a B.S. in Finance & Computer Science from Pace University. With deep expertise spanning D365 F&O, Azure, Power BI, and AI/ML systems, he architects enterprise solutions that bridge legacy systems and modern technology — and has led multi-million dollar ERP implementations for Fortune 500 supply chains.

View Full Profile →