Quick Start: Deploying Applications with Flux (Infra-Owned Registry)
This guide shows how to deploy a new application into a cluster using one shared Flux installation and an infra-owned app registry.
You will:
- Keep your application repo clean (no Flux CRDs)
- Use standard Kustomize
base/+overlays/ - Register the app with one small change in the infra repo
Prerequisites
- You have
kubectlaccess to the cluster - You have the Flux CLI installed
- You have an infra/cluster Git repository ready (can be empty)
Step 0: Bootstrap Flux (Infra Repo)
Flux bootstrap installs Flux controllers into the cluster and commits the core sync manifests into your infra repo.
Validate prerequisites
flux check --pre
Bootstrap (example: GitHub)
flux bootstrap github \
--owner=YOUR_GH_ORG \
--repository=YOUR_INFRA_REPO \
--branch=main \
--path=clusters/prod \
--personal=false
After bootstrap, your infra repo will include:
clusters/prod/flux-system/
gotk-components.yaml
gotk-sync.yaml
kustomization.yaml
Flux will now continuously reconcile the infra repo path you bootstrapped.
Step 1: Add the Apps Registry Entry Point
Flux bootstrap syncs only clusters/prod/flux-system/ by default. To enable app onboarding via an infra-owned registry, add one additional Flux Kustomization that points at your apps registry directory.
Create the apps registry directory
In your infra repo:
clusters/prod/apps/
kustomization.yaml
clusters/prod/apps/kustomization.yaml:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources: []
This file will later list one registry file per application.
Create the Flux Kustomization that activates the registry
Create clusters/prod/apps-registry.yaml:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: apps-registry
namespace: flux-system
spec:
interval: 10m
prune: true
sourceRef:
kind: GitRepository
name: flux-system
path: ./clusters/prod/apps
Ensure Flux sync includes it
Edit clusters/prod/flux-system/kustomization.yaml (this is the Kustomize file, not the Flux CR) and include the new registry Kustomization:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- gotk-components.yaml
- gotk-sync.yaml
- ../apps-registry.yaml
Commit and push. Your cluster now has a single entry point that activates all app registry entries under clusters/prod/apps/.
At this point:
- Flux is installed
- Infra repo is being reconciled
- App registry directory is active
- No applications are deployed yet
Understanding Path Resolution: Flux vs Kustomize
Understanding how paths are resolved is critical when working with Flux and Kustomize. They intentionally behave differently.
Flux Kustomization.spec.path
Always resolved relative to the Git repository root referenced by sourceRef. Never relative to the location of the YAML file.
Example:
spec:
path: ./clusters/prod/apps
This always means:
<git-repo-root>/clusters/prod/apps
This is why Flux paths often look “absolute” inside the repo.
Kustomize kustomization.yaml paths
Paths in kustomization.yaml (e.g. resources:) are resolved relative to the directory containing that kustomization.yaml.
Example:
resources:
- app-foo.yaml
Resolved as:
clusters/prod/apps/app-foo.yaml
Mental model
Flux chooses the entry directory. Kustomize resolves everything underneath it.
Keeping this distinction clear avoids the most common Flux path mistakes.
Step 2: Create the Application Repository
Create a new Git repository for your app with the following structure:
base/
kustomization.yaml
deployment.yaml
service.yaml
overlays/
prod/
kustomization.yaml
base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml
overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../../base
patchesStrategicMerge:
- replicas.yaml
Verify your manifests work locally:
kustomize build overlays/prod
Step 3: Create a Deploy Key for the App Repo
Create a deploy key for the app repository and grant it read-only access.
In the cluster, create a Secret (in the flux-system namespace):
apiVersion: v1
kind: Secret
metadata:
name: app-foo-git-ssh
namespace: flux-system
type: Opaque
stringData:
identity: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
known_hosts: |
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...
Step 4: Register the App in the Infra Repo
In the infra repo, add a new registry entry:
clusters/prod/apps/app-foo.yaml:
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: app-foo
namespace: flux-system
spec:
interval: 1m
url: ssh://git@github.com/yourorg/app-foo.git
ref:
branch: main
secretRef:
name: app-foo-git-ssh
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: app-foo
namespace: flux-system
spec:
interval: 10m
prune: true
sourceRef:
kind: GitRepository
name: app-foo
path: ./overlays/prod
targetNamespace: app-foo
Add the file to the registry Kustomize list:
# clusters/prod/apps/kustomization.yaml
resources:
- app-foo.yaml
Commit and push.
Step 5: Watch Flux Deploy the App
Flux will now:
- Fetch the app repository
- Build
overlays/prod - Apply the manifests into namespace
app-foo - Continuously reconcile changes
Observe progress with:
flux get kustomizations
flux get sources git
Updating the App
Push changes to the app repo and Flux reconciles automatically. No infra repo changes required.
Removing the App
- Remove
app-foo.yamlfromclusters/prod/apps/ - Commit and push
Flux will prune the app’s registry objects and stop reconciliation.
Why This Model Works
- Clear ownership: infra owns topology, apps own manifests
- Minimal Flux surface area: one registry entry point
- Predictable lifecycle: Git add/remove == deploy/undeploy
- Scales cleanly to many apps and teams
TL;DR
- One Flux installation per cluster
- Infra repo owns the app registry
- App repos use
base/+overlays/(standard Kustomize, no Flux CRDs) - One small registry entry in the infra repo deploys an app
- Git add/remove in the registry == deploy/undeploy