GitOps with Flux
I used to SSH into servers and run docker-compose up -d. It worked. Until I forgot what flags I used. Or I changed a config file on the server and forgot to commit it.
GitOps solves this. The Git repository is the only source of truth.
How It Works
Flux runs inside the Kubernetes cluster. It watches a Git repository. When the repo changes, Flux applies those changes to the cluster.
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ Dev โโโโโโถโ Git โโโโโโถโ Flux โ
โ (laptop) โ โ Repo โ โ (in K3s) โ
โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโ
โ Cluster โ
โ State โ
โโโโโโโโโโโโโโโ
I never run kubectl apply manually. I push to Git. Flux does the rest.
The Kustomization Structure
Flux uses Kustomize for organizing manifests. My repo structure:
infrastructure/
โโโ clusters/
โ โโโ homelab/
โ โโโ flux-system/ # Flux bootstrap files
โ โโโ infrastructure.yaml
โโโ infrastructure/
โ โโโ base/ # Base definitions
โ โ โโโ monitoring/
โ โ โโโ ingress/
โ โ โโโ storage/
โ โโโ overlays/
โ โโโ prod/ # Production patches
โ โโโ dev/ # Development patches
โโโ apps/
โโโ base/
โโโ overlays/
Base definitions are generic. Overlays patch them for specific environments.
The Entrypoint
# clusters/homelab/infrastructure.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: infrastructure
namespace: flux-system
spec:
interval: 10m0s
path: ./infrastructure/overlays/prod
prune: true
sourceRef:
kind: GitRepository
name: flux-system
Flux checks the repo every 10 minutes. If something changed, it applies. prune: true means if I delete a manifest from Git, Flux deletes it from the cluster.
Automatic Image Updates
Flux can also watch container registries. When a new image is pushed, Flux updates the deployment and commits the change back to Git.
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
name: app-policy
namespace: flux-system
spec:
imageRepositoryRef:
name: app-repo
policy:
semver:
range: 1.x
Flow:
- CI builds a new image and pushes
myapp:1.2.5 - Flux detects the new tag matching the policy
- Flux updates the deployment YAML to use
1.2.5 - Flux commits that change back to Git
- Flux applies the new manifest to the cluster
Fully automated. I donโt touch anything.
Handling Secrets
Secrets shouldnโt be in Git. But GitOps requires everything in Git. The solution: SOPS (Secrets OPerationS).
apiVersion: v1
kind: Secret
metadata:
name: database-credentials
stringData:
username: ENC[AES256_GCM,data:...,type:str]
password: ENC[AES256_GCM,data:...,type:str]
Secrets are encrypted in Git. Flux decrypts them at apply time using a key stored in the cluster.
Disaster Recovery
This is the real power of GitOps.
If my K3s node dies:
- Provision new hardware
- Install K3s
- Bootstrap Flux pointing at the same repo
- Wait 10 minutes
The entire cluster state rebuilds automatically. Every deployment, every config, every secret โ all from Git.
No runbooks. No โwhat was running on that server?โ moments. Git remembers.
Why GitOps?
| Manual Approach | GitOps |
|---|---|
| โWhatโs running on that server?โ | Check Git |
| โWho changed that config?โ | Check Git history |
| โCan we roll back?โ | git revert |
| โHow do I rebuild this?โ | Bootstrap Flux |
| โIs prod in sync with the repo?โ | Flux guarantees it |
Git is the source of truth. Everything else is just a cache.