Migration Path and When Flux Is the Better Choice
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
- Install Flux alongside ArgoCD (different namespace)
- Migrate one non-critical application (dev environment) to Flux
- Verify Flux produces identical cluster state
- Migrate remaining dev applications
- Migrate staging applications
- Migrate production applications (one at a time)
- Decommission ArgoCD after 2 weeks of stable Flux operation
Pre-Migration Checklist
| Check | Action |
|---|---|
| Manifest rendering | Run kustomize build and compare with argocd app manifests for each app |
| Helm values | Verify Flux HelmRelease produces same output as ArgoCD Helm source |
| Sync waves | Map ArgoCD sync waves to Flux dependsOn |
| Secrets | Ensure Flux can access encrypted secrets (SOPS, Sealed Secrets) |
| Notifications | Recreate notification configuration for Flux notification-controller |
| RBAC | Map ArgoCD project roles to Kubernetes RBAC for Flux |
| Webhooks | Update 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:
- CI builds and pushes image with semver tag
- Flux image-reflector detects the new tag
- Flux image-automation updates the Kustomization with the new tag
- 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.