Skip to main content
ship it and sleep

Migration Path and When Flux Is the Better Choice

4 min read Chapter 36 of 66

Migration Path and When Flux Is the Better Choice

The Failure

A platform team decided to migrate from ArgoCD to Flux over a weekend. They disabled ArgoCD, installed Flux, and created Kustomization resources for all 30 applications. By Sunday evening, 8 applications were not syncing correctly. Flux’s Kustomize rendering produced slightly different output than ArgoCD’s for resources using Helm post-renderers. The team spent Monday debugging and reverted to ArgoCD by Tuesday.

Migration between GitOps tools is not a weekend project. It requires parallel operation, application-by-application migration, and validation at each step.

The Mechanism

Migration Strategy

  1. Install Flux alongside ArgoCD (different namespace)
  2. Migrate one non-critical application (dev environment) to Flux
  3. Verify Flux produces identical cluster state
  4. Migrate remaining dev applications
  5. Migrate staging applications
  6. Migrate production applications (one at a time)
  7. Decommission ArgoCD after 2 weeks of stable Flux operation

Pre-Migration Checklist

CheckAction
Manifest renderingRun kustomize build and compare with argocd app manifests for each app
Helm valuesVerify Flux HelmRelease produces same output as ArgoCD Helm source
Sync wavesMap ArgoCD sync waves to Flux dependsOn
SecretsEnsure Flux can access encrypted secrets (SOPS, Sealed Secrets)
NotificationsRecreate notification configuration for Flux notification-controller
RBACMap ArgoCD project roles to Kubernetes RBAC for Flux
WebhooksUpdate Git webhooks from ArgoCD endpoint to Flux receiver

The Implementation

Step 1: Install Flux Alongside ArgoCD

# Install Flux without touching ArgoCD's namespace
flux install --namespace=flux-system --components-extra=image-reflector-controller,image-automation-controller

Step 2: Create Flux Equivalent for One Application

# Disable ArgoCD auto-sync for the test application
# argocd app set catalog-service-dev --sync-policy none

# Create Flux GitRepository (shared across all apps)
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: ecommerce-infra
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/acme/ecommerce-infra.git
  ref:
    branch: main
---
# Create Flux Kustomization for the test app
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: catalog-service-dev
  namespace: flux-system
spec:
  interval: 5m
  sourceRef:
    kind: GitRepository
    name: ecommerce-infra
  path: ./apps/catalog-service/overlays/dev
  prune: true
  targetNamespace: dev
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: catalog-service
      namespace: dev

Step 3: Validate

# Compare ArgoCD's rendered manifests with Flux's
argocd app manifests catalog-service-dev > /tmp/argocd-manifests.yaml
flux build kustomization catalog-service-dev > /tmp/flux-manifests.yaml
diff /tmp/argocd-manifests.yaml /tmp/flux-manifests.yaml

Step 4: Decommission ArgoCD Application

# After validation, delete the ArgoCD Application
# IMPORTANT: Remove the finalizer first to prevent ArgoCD from deleting cluster resources
kubectl -n argocd patch application catalog-service-dev \
  --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]'
kubectl -n argocd delete application catalog-service-dev

When Flux Is the Better Choice

Scenario 1: Image Automation Pipeline

Flux’s image-reflector-controller watches container registries for new tags and automatically updates Git with the latest image. This creates a fully automated deployment loop:

  1. CI builds and pushes image with semver tag
  2. Flux image-reflector detects the new tag
  3. Flux image-automation updates the Kustomization with the new tag
  4. Flux kustomize-controller applies the updated manifests

ArgoCD requires a separate tool (ArgoCD Image Updater) or a CI step to update the Git repository. Flux’s approach is more elegant and requires fewer moving parts.

Scenario 2: 50+ Teams with Namespace Isolation

When each team manages their own deployments and the platform team provides guardrails via admission controllers and network policies, Flux’s namespace-scoped model is more appropriate. Each team installs their own Flux controllers in their namespace. No central ArgoCD instance to become a bottleneck.

Scenario 3: Terraform + Kubernetes GitOps

If the infrastructure (VPCs, databases, load balancers) and the Kubernetes workloads are managed through the same GitOps workflow, Flux’s tf-controller provides native Terraform reconciliation. No separate Terraform CI pipeline needed.

The Gate

Migration is complete when all applications are managed by the target tool (ArgoCD or Flux) and the source tool has been decommissioned. The gate is a 2-week burn-in period where both tools run in parallel for the last batch of migrated applications.

The Recovery

Flux produces different manifests than ArgoCD: The rendering engines differ slightly. ArgoCD uses its own Kustomize/Helm rendering with specific versions. Flux uses the controller’s embedded versions. Pin the Kustomize and Helm versions in Flux controllers to match ArgoCD’s versions.

Mid-migration incident: Both tools are running. Use whichever tool manages the affected application. Do not attempt to fix the incident and continue migration simultaneously.