Hey folks! Been tinkering with our Flux setup for a few months now, trying to get environment-specific configs feeling clean and maintainable. We all know the pain of managing dev, staging, and prod manifests that are 95% the same but have those few crucial tweaks.
I found Kustomize overlays paired with Flux to be a really solid combo for this. It keeps our base definitions DRY and lets us patch in the environment-specific bits without duplication. Here's the approach that's been working for us:
We structure our Git repo like this:
```
apps/my-app/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
├── overlays/
│ ├── dev/
│ │ ├── patch-replicas.yaml
│ │ └── kustomization.yaml
│ ├── staging/
│ │ ├── patch-resources.yaml
│ │ └── kustomization.yaml
│ └── prod/
│ ├── patch-resources.yaml
│ ├── patch-hpa.yaml
│ └── kustomization.yaml
└── flux-system/
└── kustomization.yaml
```
The key is pointing Flux at the *overlay* kustomization.yaml, not the base. In our `flux-system/kustomization.yaml`, we define a Kustomization resource for each environment:
```yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app-dev
namespace: flux-system
spec:
interval: 5m
path: "./apps/my-app/overlays/dev"
sourceRef:
kind: GitRepository
name: our-repo
prune: true
```
Then in `overlays/dev/kustomization.yaml`, we simply reference the base and list our patches:
```yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- patch-replicas.yaml
```
The patches themselves are dead simple YAML fragments. For example, `patch-replicas.yaml` for dev might just be:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
```
**What I love about this setup:**
- **Clear separation:** Base config is the single source of truth. Overlays are *only* for differences.
- **Easy to compare:** I can instantly see what's different between dev and prod by looking at the patch files side-by-side.
- **Flux reconciliation is clean:** Each environment gets its own Kustomization resource, so sync status and health are per-environment.
The main gotcha we hit was making sure the patch files target the correct API version and kind. Also, remember that `patchesStrategicMerge` is being deprecated in favor of `patches` (which supports JSON Patch), so we're starting to migrate to that.
Anyone else using a similar pattern? Curious how you handle more complex patches, like adding entire sidecar containers in just one environment.
✌️
✌️
That structure works, but have you tried using `components` instead of nested overlays? They're better for sharing patches between environments.
Also, you're missing a key piece. Your Flux Kustomization needs a health check. Without it, Flux can't tell if the apply worked.
```
spec:
interval: 5m
path: ./apps/my-app/overlays/dev
prune: true
validation: client
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: dev
```
Otherwise you're flying blind on deployments.
That health check point is genuinely important, thanks for bringing it up. I've seen people skip it and then wonder why Flux shows 'ready' while their pods are stuck in ImagePullBackOff.
On the components vs overlays discussion, I've had mixed results. Components are cleaner for sharing patches, but they add a layer of indirection that can confuse newer team members. For us, starting with simple overlays and only introducing components when the duplication becomes painful was the right call.
Keep it civil, keep it real.