Skip to main content
← All Articles Β· Β· 10 min read

GitOps Best Practices 2026: ArgoCD, Flux, and Beyond

Master GitOps in 2026: compare ArgoCD vs Flux, structure your GitOps repositories, handle secrets, manage multi-cluster deployments, and implement progressive delivery.

gitopsargocdfluxkubernetes deploymentcontinuous deploymentdevops

GitOps has moved from a novel idea to the de facto standard for Kubernetes deployments. In 2026, the question isn’t whether to adopt GitOps β€” it’s how to implement it correctly at scale. Misconfigured GitOps workflows are a common source of drift, deployment failures, and security incidents.

This guide covers the principles, tooling choices, repository structures, secrets management, and multi-cluster strategies that separate mature GitOps implementations from basic ones.


GitOps Principles (Refresher)

Four core principles define GitOps, formalized by the OpenGitOps working group:

  1. Declarative β€” desired system state is expressed declaratively (YAML, JSON, Helm charts)
  2. Versioned and immutable β€” all desired state is stored in Git; history is auditable
  3. Pulled automatically β€” software agents (ArgoCD, Flux) pull and apply changes, not CI pushes
  4. Continuously reconciled β€” agents detect and correct drift between desired and actual state

The critical insight: the Git repository is the single source of truth for cluster state. Nobody manually kubectl applys anything in production.


ArgoCD vs Flux: Choosing Your Operator

Both are CNCF graduated projects. The choice depends on your operational preferences:

FeatureArgoCDFlux v2
UIRich web UI includedMinimal (Weave GitOps adds UI)
Multi-tenancyProject-based isolationNamespace-based isolation
App-of-apps patternNative (ApplicationSet)Kustomization composition
Helm supportNativeHelmRelease CRD
Secret managementSealed Secrets, VaultSOPS, Sealed Secrets, Vault
NotificationsArgoCD NotificationsNotification Controller
CLIargocd CLIflux CLI
RBAC modelArgoCD RBACKubernetes RBAC native

Choose ArgoCD if: you want a visual dashboard for operators, project-level multi-tenancy, or if your team is less Kubernetes-native and values a polished UI.

Choose Flux if: you prefer a fully GitOps-native approach with minimal in-cluster state, want tight SOPS integration for secrets, or are building a GitOps-based platform.


Repository Structure: Mono-Repo vs Poly-Repo

gitops-repo/
β”œβ”€β”€ clusters/
β”‚   β”œβ”€β”€ production/
β”‚   β”‚   β”œβ”€β”€ apps.yaml          # points to apps/ for production
β”‚   β”‚   └── infrastructure.yaml
β”‚   └── staging/
β”‚       └── apps.yaml
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ base/                  # shared Kustomize base
β”‚   β”‚   └── payment-service/
β”‚   β”‚       β”œβ”€β”€ deployment.yaml
β”‚   β”‚       └── service.yaml
β”‚   └── overlays/
β”‚       β”œβ”€β”€ production/        # prod-specific patches
β”‚       └── staging/
β”œβ”€β”€ infrastructure/
β”‚   β”œβ”€β”€ cert-manager/
β”‚   β”œβ”€β”€ ingress-nginx/
β”‚   └── monitoring/
└── .flux.yaml                 # or ArgoCD ApplicationSet
  • Config repo: cluster configuration, infrastructure, GitOps tooling itself
  • App repos: each service repo contains its own Kubernetes manifests or Helm charts
  • Config repo references app repos at specific Git SHAs or Helm chart versions

Poly-repo enables independent team ownership but requires image update automation to keep deployments current.


ArgoCD Application-of-Apps Pattern

# apps/applications.yaml β€” "app of apps" root Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: applications
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/your-org/gitops-repo
    targetRevision: HEAD
    path: apps/production
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true      # Remove resources deleted from Git
      selfHeal: true   # Fix manual changes to cluster
    syncOptions:
      - CreateNamespace=true

Using ApplicationSet for multi-cluster deployments:

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
spec:
  generators:
  - list:
      elements:
      - cluster: staging    # deploy to staging cluster
        url: https://staging.k8s.example.com
      - cluster: production # deploy to production cluster
        url: https://prod.k8s.example.com
  template:
    spec:
      project: default
      source:
        repoURL: https://github.com/your-org/gitops-repo
        targetRevision: HEAD
        path: apps/overlays/{{cluster}}
      destination:
        server: '{{url}}'
        namespace: guestbook

Secrets Management in GitOps

Never store plaintext secrets in Git. Three battle-tested approaches:

1. SOPS (Secrets Operations) β€” Best for Flux

# Encrypt with Age key
sops --encrypt --age age1xxx... \
  --encrypted-regex '^(data|stringData)$' \
  secret.yaml > secret.enc.yaml

# Flux automatically decrypts with .sops.yaml config
# .sops.yaml
creation_rules:
  - path_regex: .*.yaml
    age: age1xxx...

2. Sealed Secrets β€” Works with Both ArgoCD and Flux

# Install controller
helm install sealed-secrets sealed-secrets/sealed-secrets -n kube-system

# Seal a secret (client-side)
kubectl create secret generic db-password \
  --from-literal=password=supersecret \
  --dry-run=client -o yaml | \
  kubeseal --controller-namespace kube-system -o yaml > sealed-secret.yaml

# Commit sealed-secret.yaml β€” only the controller can decrypt it

Syncs secrets from Vault, AWS Secrets Manager, or GCP Secret Manager into Kubernetes:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-password
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-password        # creates a regular K8s Secret
  data:
    - secretKey: password
      remoteRef:
        key: secret/data/prod/db
        property: password

Progressive Delivery with Argo Rollouts

GitOps becomes more powerful when combined with progressive delivery β€” canary releases and blue-green deployments with automated promotion or rollback:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: payment-service
spec:
  replicas: 10
  strategy:
    canary:
      steps:
      - setWeight: 10      # 10% of traffic to new version
      - pause: {duration: 5m}
      - setWeight: 30
      - pause: {duration: 5m}
      - analysis:          # auto-promote if metrics look good
          templates:
          - templateName: success-rate
      - setWeight: 100     # full rollout
  selector:
    matchLabels:
      app: payment-service
  template:
    # ... pod spec

Drift Detection and Alerts

One of GitOps’ key benefits is detecting drift β€” when cluster state diverges from Git state. Configure alerts:

ArgoCD: Applications show OutOfSync status. Configure notifications:

# argocd-notifications-cm
context: |
  argocdUrl: https://argocd.example.com
template.app-out-of-sync: |
  message: |
    Application {{.app.metadata.name}} is out of sync.
    Drift detected: {{.app.status.sync.status}}
trigger.on-out-of-sync: |
  - when: app.status.sync.status == 'OutOfSync'
    send: [app-out-of-sync]

Image Update Automation

Automatically update image tags in Git when a new container image is pushed:

Flux Image Automation:

# Image Repository scan
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: payment-service
spec:
  image: registry.example.com/payment-service
  interval: 5m

# Update policy (latest semver patch)
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: payment-service
spec:
  imageRepositoryRef:
    name: payment-service
  policy:
    semver:
      range: '>=1.0.0 <2.0.0'

Flux then commits the updated image tag directly to your GitOps repository.


Best Practices Summary

Repository hygiene:

  • Pin Helm chart versions and image tags β€” never use latest
  • Use separate branches or repos for staging and production to enforce promotion gating
  • Enable branch protection on your GitOps repo β€” all changes via PR

Security:

  • RBAC: restrict ArgoCD/Flux service account permissions to needed namespaces only
  • Audit Git history for accidental secret commits; rotate any exposed credentials immediately
  • Scan Helm charts and manifests with Checkov or Trivy in CI before merge

Operations:

  • Enable selfHeal: true β€” let the operator fix drift rather than alerting on it
  • Set resource limits on all deployments to prevent noisy-neighbor cluster pressure
  • Use syncWindows in ArgoCD to restrict automated syncs during business hours if needed

Observability:

  • Track deployment frequency and lead time via DORA metrics pulled from ArgoCD events
  • Alert on sync failures and out-of-sync applications before they become incidents
  • Link ArgoCD deployment events to your observability stack (Grafana, Datadog) for correlation

GitOps in 2026 is mature, well-tooled, and battle-tested. The hardest part is no longer β€œhow to set it up” β€” it’s establishing the discipline to never bypass it, even in an incident.

Free Download

50 CLI Commands That Save Hours Every Week

The exact Git shortcuts, file search tricks, Docker commands, and productivity hacks that senior developers use daily. Compiled from 5+ years of shipping production code.

  • Git mastery (10 cmds)
  • File & search wizardry
  • Docker & DevOps tricks
  • Process & network tools
  • Productivity boosters
  • macOS & Linux install guide

No spam. 1 email/week max. Unsubscribe anytime.

Found this guide useful? Check out our free developer tools.