DevOps Trending Tutorial

GitOps with Flux and ArgoCD: The 2026 Guide

πŸ“… Feb 27, 2026 ⏱️ 20 min read ☸️ Kubernetes 1.30+

If your Kubernetes deployments still involve manual kubectl apply, SSH-ing into jump boxes, or tribal knowledge scattered across Slack threads, you're doing it wrong in 2026. GitOps has become the standard operating model for cloud-native infrastructureβ€”and for good reason. It brings the rigor of version control to infrastructure management, with automation, auditability, and rollback capabilities built in.

This guide covers everything you need to know about GitOps in 2026: the core principles, the leading tools (Flux and ArgoCD), progressive delivery patterns, and production-ready implementation strategies. Whether you're migrating from manual deployments or evaluating GitOps tools, this article has you covered.

What is GitOps?

GitOps, coined by Weaveworks in 2017, extends the DevOps principles of automation and collaboration with one key insight: Git should be the single source of truth for both application code and infrastructure configuration.

The GitOps model defines four core principles:

The Four Principles of GitOps

Declarative: All infrastructure is described declaratively (Kubernetes manifests, Terraform, etc.)
Versioned and Immutable: The desired state is stored in version control (Git), providing audit trails and rollback capability
Pulled Automatically: Software agents automatically pull the desired state from Git and apply it to the infrastructure
Continuously Reconciled: Agents continuously monitor the actual state and ensure it matches the desired state (self-healing)
GitOps Architecture
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Push β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Pull β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Git Repo │───────────────▢│ CI/CD │──────────────▢│ Registry β”‚ β”‚ (Source of β”‚ Changes β”‚ Pipelineβ”‚ Artifacts β”‚ (Images) β”‚ β”‚ Truth) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Kubernetes Cluster β”‚β—€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ └──────────────│ β”‚ GitOps Agent β”‚ β”‚ Declarative β”‚ β”‚ (Flux/ArgoCD) β”‚ β”‚ Manifests β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Watches Git β”‚ β”‚ β”‚ β”‚ β€’ Applies State β”‚ β”‚ β”‚ β”‚ β€’ Reconciles β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Crucially, GitOps decouples CI from CD. Your CI pipeline builds and pushes artifacts; your CD system (Flux or ArgoCD) independently pulls and deploys them. This separation improves security (CD doesn't need write access to the registry) and enables deployment strategies that CI systems struggle with.

Flux vs ArgoCD: The 2026 Comparison

The two dominant GitOps tools have matured significantly. Here's how they compare in 2026:

Feature Flux ArgoCD
Architecture Modular controllers, one per concern Unified application with controller + UI
UI Optional (Weave GitOps), primarily CLI Rich web UI included
Multi-tenancy Native via RBAC and resource isolation Projects + RBAC, mature
Secret Management SOPS, Mozilla SOPS, External Secrets SOPS, External Secrets, Vault
Progressive Delivery Flagger integration (native) Argo Rollouts (separate component)
Image Automation ImagePolicy + ImageUpdateAutomation Image Updater (separate controller)
Notification Notification controller (webhook, Slack, etc.) Built-in notifications
Best For Git-native users, minimal UI needs, SRE-focused Teams wanting visual oversight, mixed skill levels

Key Differences in 2026

Flux has doubled down on its modular, composable approach. Each concern (source fetching, Kustomize/Helm, image automation, notifications) runs as a separate controller. This makes Flux lightweight and Kubernetes-native but requires understanding the component model.

ArgoCD remains the choice for teams wanting immediate visual feedback. Its Application resource abstracts the complexity, and the UI provides real-time sync status, diff views, and manual sync controls. ArgoCD 3.0 (released in late 2025) added improved ApplicationSets for multi-cluster management.

In 2026, both tools support OCI artifacts (storing manifests in container registries), multi-source applications (combining multiple Git repos), and advanced sync windows. The choice often comes down to team culture: Git-centric teams prefer Flux; UI-centric teams prefer ArgoCD.

Implementing Flux: A Practical Walkthrough

Let's implement a complete GitOps pipeline with Flux v2. You'll need a Kubernetes cluster and kubectl access.

Step 1: Install Flux CLI

Install Flux CLI
# macOS
brew install fluxcd/tap/flux

# Linux
curl -s https://fluxcd.io/install.sh | sudo bash

# Verify
flux --version
# flux version 2.4.0

Step 2: Bootstrap Flux

Bootstrap installs the Flux controllers in your cluster and creates a Git repository for your configurations:

Bootstrap Flux
# Set your GitHub credentials
export GITHUB_TOKEN=
export GITHUB_USER=

# Bootstrap with GitHub
flux bootstrap github \
  --owner=$GITHUB_USER \
  --repository=fleet-infra \
  --branch=main \
  --path=clusters/production \
  --personal

# This creates:
# - GitHub repo 'fleet-infra'
# - Flux controllers in flux-system namespace
  # - Commit with initial structure

Step 3: Understand the Structure

After bootstrap, your repo has this structure:

Repository structure
fleet-infra/
β”œβ”€β”€ clusters/
β”‚   └── production/
β”‚       β”œβ”€β”€ flux-system/           # Flux controllers
β”‚       β”‚   β”œβ”€β”€ gotk-components.yaml
β”‚       β”‚   └── kustomization.yaml
β”‚       └── kustomization.yaml     # Root kustomization
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ base/                      # Base manifests
β”‚   β”‚   β”œβ”€β”€ nginx/
β”‚   β”‚   └── podinfo/
β”‚   └── production/                # Production overlays
β”œβ”€β”€ infrastructure/
β”‚   β”œβ”€β”€ sources/                   # GitSource, HelmRepository
β”‚   └── controllers/               # Helm releases for infra
└── tenants/
    └── team-a/                    # Namespace-based isolation

Step 4: Add a Source (Git Repository)

Flux uses Custom Resources to define sources. Create a GitRepository that watches your application repo:

clusters/production/apps-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/stefanprodan/podinfo
  ref:
    semver: "6.x"  # Track latest 6.x tag
  ignore:
    clusters/**
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 10m
  path: ./kustomize
  prune: true
  sourceRef:
    kind: GitRepository
    name: podinfo
  targetNamespace: default
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: podinfo
      namespace: default

Commit and push this file. Flux will automatically detect it, fetch the source, and apply the manifests.

Step 5: Verify the Deployment

Check Flux status
# List sources
flux get sources git

# List Kustomizations
flux get kustomizations

# Check reconciliation status
flux reconcile source git podinfo
flux reconcile kustomization podinfo

# See events
flux events

Step 6: Image Automation

Automate deployments when new container images are published:

Image automation
# ImageRepository polls the registry
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
  name: podinfo
  namespace: flux-system
spec:
  image: ghcr.io/stefanprodan/podinfo
  interval: 1m
  secretRef:
    name: regcred
---
# ImagePolicy defines which tags to select
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
  name: podinfo
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: podinfo
  policy:
    semver:
      range: "6.x"
---
# ImageUpdateAutomation writes tag changes back to Git
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageUpdateAutomation
metadata:
  name: podinfo
  namespace: flux-system
spec:
  interval: 1m
  sourceRef:
    kind: GitRepository
    name: flux-system
  git:
    checkout:
      ref:
        branch: main
    commit:
      author:
        name: Flux Bot
        email: [email protected]
      messageTemplate: |
        Automated image update
        
        Images:
        {{ range .Updated.Images -}}
        - {{.}}
        {{ end }}
    push:
      branch: main
  policy:
    semver:
      range: "6.x"

When Flux detects a new image matching your policy, it updates the manifest in Git, commits the change, and reconciles. You get a complete audit trail: Git shows exactly when and why the deployment changed.

Implementing ArgoCD: A Practical Walkthrough

Now let's implement the same workflow with ArgoCD. ArgoCD's architecture differs in that it centralizes more functionality into a single application with a powerful UI.

Step 1: Install ArgoCD

Install ArgoCD
# Create namespace
kubectl create namespace argocd

# Install ArgoCD (non-HA for testing)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# For HA production, use:
# kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/ha/install.yaml

# Wait for pods
kubectl wait -n argocd --for=condition=ready pod -l app.kubernetes.io/name=argocd-server --timeout=300s

Step 2: Access the UI

Access ArgoCD
# Port-forward to access UI
kubectl port-forward svc/argocd-server -n argocd 8080:443

# Get initial password
argocd admin initial-password -n argocd

# Login via CLI (optional)
argocd login localhost:8080 --username admin --password 

Open https://localhost:8080 and accept the self-signed certificate. You'll see the ArgoCD dashboard with no applications yet.

Step 3: Define an Application

ArgoCD uses the Application CRD to define what to deploy and from where:

applications/podinfo.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: podinfo
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  source:
    repoURL: https://github.com/stefanprodan/podinfo
    targetRevision: HEAD
    path: kustomize
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
      allowEmpty: false
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
      - PruneLast=true
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Apply this, and ArgoCD will immediately detect and sync the application. The UI shows real-time sync status, resource tree, and logs.

Step 4: ApplicationSets for Multi-Environment

ArgoCD's ApplicationSet controller (now GA) generates Applications from templates. This is powerful for multi-environment setups:

applicationset.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: podinfo
  namespace: argocd
spec:
  generators:
    - list:
        elements:
          - env: staging
            revision: HEAD
          - env: production
            revision: v6.2.0  # Pin production to specific version
  template:
    metadata:
      name: 'podinfo-{{env}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/stefanprodan/podinfo
        targetRevision: '{{revision}}'
        path: kustomize
        kustomize:
          namePrefix: '{{env}}-'
      destination:
        server: https://kubernetes.default.svc
        namespace: 'podinfo-{{env}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

This generates two Applications: podinfo-staging (tracking HEAD) and podinfo-production (pinned to v6.2.0).

Step 5: Image Updater (Optional)

ArgoCD Image Updater provides Flux-like image automation:

Install and configure Image Updater
# Install Image Updater
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml

# Annotate Application for image updates
metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: podinfo=ghcr.io/stefanprodan/podinfo:^6.x
    argocd-image-updater.argoproj.io/podinfo.update-strategy: semver
    argocd-image-updater.argoproj.io/podinfo.allow-tags: regexp:^[0-9]\.[0-9]+\.[0-9]+$
    argocd-image-updater.argoproj.io/write-back-method: git

Progressive Delivery: Canary and Blue-Green

Basic GitOps syncs your desired state. Progressive delivery gradually shifts traffic while monitoring metrics. In 2026, this is essential for production services.

Flux with Flagger

Flagger is the progressive delivery operator for Flux (and works with other GitOps tools too):

Canary deployment with Flagger
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: podinfo
  namespace: default
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: podinfo
  service:
    port: 9898
  analysis:
    interval: 30s
    threshold: 5
    maxWeight: 50
    stepWeight: 10
    metrics:
      - name: request-success-rate
        thresholdRange:
          min: 99
        interval: 1m
      - name: request-duration
        thresholdRange:
          max: 500
        interval: 1m
    webhooks:
      - name: load-test
        url: http://flagger-loadtester.test/
        timeout: 5s
        metadata:
          cmd: "hey -z 1m -q 10 -c 2 http://podinfo-canary.default:9898/"
  skipAnalysis: false

When Flux updates the Deployment, Flagger intercepts it, creates a canary Deployment, shifts traffic gradually (10%, 20%, 30%...), monitors Prometheus metrics, and either promotes the new version or rolls back. All automated; GitOps triggers it, Flagger manages the rollout.

Argo Rollouts

ArgoCD users typically adopt Argo Rollouts for progressive delivery:

Argo Rollout definition
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: podinfo
  namespace: default
spec:
  replicas: 5
  strategy:
    canary:
      canaryService: podinfo-canary
      stableService: podinfo
      trafficRouting:
        nginx:
          stableIngress: podinfo
          annotationPrefix: nginx.ingress.kubernetes.io
      steps:
        - setWeight: 10
        - pause: {duration: 2m}
        - setWeight: 20
        - pause: {duration: 2m}
        - setWeight: 50
        - pause: {duration: 2m}
      analysis:
        templates:
          - templateName: success-rate
        args:
          - name: service-name
            value: podinfo-canary
  selector:
    matchLabels:
      app: podinfo
  template:
    metadata:
      labels:
        app: podinfo
    spec:
      containers:
        - name: podinfo
          image: ghcr.io/stefanprodan/podinfo:6.2.0
          ports:
            - containerPort: 9898

Argo Rollouts replaces the standard Deployment with a Rollout resource that supports canary, blue-green, and A/B testing strategies. It integrates with ingress controllers (NGINX, ALB, Istio) for traffic splitting.

Secret Management in GitOps

Git is not for secrets. Here are the 2026-standard approaches:

SOPS (Secrets OPerationS)

Mozilla SOPS encrypts secrets with age or GPG. Encrypted files live in Git; only the cluster can decrypt them:

SOPS with Flux
# 1. Generate age key
age-keygen -o key.txt

# 2. Create .sops.yaml
creation_rules:
  - path_regex: .*\.enc\.yaml$
    age: age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2el6...

# 3. Encrypt secret
sops --encrypt --in-place secret.enc.yaml

# In Flux, add SOPS decryption:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
spec:
  decryption:
    provider: sops
    secretRef:
      name: sops-age

External Secrets Operator

Store secrets in HashiCorp Vault, AWS Secrets Manager, or Azure Key Vault; sync them to Kubernetes as needed:

External Secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: database-credentials
  namespace: default
spec:
  refreshInterval: 1h
  secretStoreRef:
    kind: ClusterSecretStore
    name: vault-backend
  target:
    name: database-credentials
    creationPolicy: Owner
  data:
    - secretKey: username
      remoteRef:
        key: secret/data/database
        property: username
    - secretKey: password
      remoteRef:
        key: secret/data/database
        property: password

Multi-Cluster GitOps

Production deployments span multiple clusters: regions, environments, or on-prem + cloud. Both Flux and ArgoCD handle this, but differently.

Flux with Cluster API

Flux treats each cluster as a target. The management cluster runs Flux and applies to remote clusters:

Flux multi-cluster
# Kubeconfig for target cluster
apiVersion: v1
kind: ConfigMap
metadata:
  name: eu-west-1-kubeconfig
  namespace: flux-system
data:
  value: |
    apiVersion: v1
    kind: Config
    clusters:
      - cluster:
          certificate-authority-data: ...
          server: https://eu-west-1.example.com
        name: eu-west-1
---
# Kustomization targeting remote cluster
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: apps-eu-west-1
  namespace: flux-system
spec:
  interval: 10m
  path: ./apps/overlays/eu-west-1
  prune: true
  sourceRef:
    kind: GitRepository
    name: fleet-infra
  kubeConfig:
    secretRef:
      name: eu-west-1-kubeconfig

ArgoCD with Applications in Any Namespace

ArgoCD 3.0 can manage Applications in any namespace, enabling hub-and-spoke patterns:

ArgoCD ApplicationSet for clusters
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: guestbook
  namespace: argocd
spec:
  generators:
    - clusters:
        selector:
          matchLabels:
            environment: production
        values:
          revision: HEAD
  template:
    metadata:
      name: '{{name}}-guestbook'
      namespace: argocd
    spec:
      project: default
      source:
        repoURL: https://github.com/argoproj/argocd-example-apps
        targetRevision: '{{values.revision}}'
        path: guestbook
      destination:
        server: '{{server}}'
        namespace: guestbook

Monitoring and Observability

GitOps without observability is flying blind. Key metrics to track:

Metric Description Tool
Reconciliation Duration Time to apply changes from Git Flux metrics, ArgoCD metrics
Drift Detection Resources out of sync with Git ArgoCD UI, Flux alerts
Sync Success Rate Percentage of successful reconciliations Prometheus + Grafana
Deployment Frequency How often deployments occur DORA metrics
Lead Time for Changes Time from commit to production Git history + deployment time
Time to Recovery Time to recover from failure Incident tracking + GitOps rollback

Both Flux and ArgoCD expose Prometheus metrics. Grafana dashboards are available in the official repositories. Set up alerts for reconciliation failuresβ€”these often indicate issues that will affect application availability.

Production Checklist

Before running GitOps in production:

GitOps Production Readiness

Enable RBAC and limit controller permissions to necessary namespaces
Configure resource quotas to prevent GitOps controllers from consuming cluster resources
Implement network policies restricting controller egress
Set up backup/restore for GitOps state (especially ArgoCD's Redis)
Enable audit logging for all Git operations
Configure health checks and readiness probes for controllers
Implement graceful shutdown for controllers
Set up alerting for sync failures and reconciliation errors
Test rollback procedures regularly
Document disaster recovery runbooks

Conclusion

GitOps is no longer experimentalβ€”it's the standard for Kubernetes deployments in 2026. Whether you choose Flux for its modularity and Git-native approach or ArgoCD for its rich UI and simpler abstractions, you're adopting a deployment model that brings auditability, automation, and reliability to your infrastructure.

The key is consistency: Git becomes your source of truth, automation handles the drudgery, and your team focuses on higher-level concerns. With progressive delivery, secret management, and multi-cluster patterns well-established, GitOps has matured into a production-ready platform for teams of any size.

Start small: pick one non-critical service, implement GitOps, and iterate. The investment in learning pays dividends in reduced deployment anxiety and faster recovery when things go wrong.

Need Help With GitOps?

We design and implement GitOps pipelines for organizations across Europe. From tool selection to production rollout, we can accelerate your GitOps journey.

Discuss Your Project