Top Tags

FluxCD App Onboarding Guide

Step-by-step instructions to add a new application to your FluxCD fleet repo.

How to add any new application to your FluxCD fleet repo — step by step.

Overview

You have one fleet repo that acts as the control center for all your apps. Each app lives in its own independent repo and is registered in the fleet repo via a dedicated folder.

text
1fleet/
2 clusters/my-cluster/
3 flux-system/ ← Flux itself (DO NOT TOUCH)
4 app1/ ← Registration for App 1
5 app2/ ← Registration for App 2
6 your-new-app/ ← Add new apps here

Prerequisites

  • FluxCD bootstrapped (flux bootstrap already run once)
  • kubectl and flux CLI installed
  • Your app has a GitHub repo with k8s manifests inside a /k8s folder

Part 1 — Prepare your App Repo

Your app repo only needs standard Kubernetes manifest files plus one kustomization.yaml that lists them.

App repo structure

text
1your-app-repo/
2 k8s/
3 kustomization.yaml ← lists all k8s files below
4 deployment.yaml
5 service.yaml
6 ingress.yaml ← optional

k8s/kustomization.yaml

yaml
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - deployment.yaml
5 - service.yaml
6 - ingress.yaml

⚠️ This file is not a Flux Kustomization — it's a plain kustomize resource list. No spec: field here.

k8s/deployment.yaml (example)

yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: your-app
5 namespace: default
6spec:
7 replicas: 1
8 selector:
9 matchLabels:
10 app: your-app
11 template:
12 metadata:
13 labels:
14 app: your-app
15 spec:
16 containers:
17 - name: your-app
18 image: ghcr.io/yourorg/your-app:latest
19 ports:
20 - containerPort: 3000

k8s/service.yaml (example)

yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: your-app
5 namespace: default
6spec:
7 selector:
8 app: your-app
9 ports:
10 - port: 80
11 targetPort: 3000
12 type: ClusterIP

Part 2 — Register the App in Your Fleet Repo

In your fleet repo, create a folder for the app under clusters/my-cluster/. Each folder needs exactly 3 files.

Fleet repo structure for the app

text
1clusters/my-cluster/your-app/
2 kustomization.yaml ← lists the other two files (native kustomize)
3 gitrepository.yaml ← tells Flux where the app repo is
4 flux-kustomization.yaml ← tells Flux how to deploy from that repo

File 1 — kustomization.yaml

This is the native kustomize file. It just lists the other two files so Flux can find them.

yaml
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - gitrepository.yaml
5 - flux-kustomization.yaml

✅ Make sure the filename is spelled correctly: kustomization.yaml (not kustomizaton.yaml)


File 2 — gitrepository.yaml

Tells Flux which Git repo to watch and how to authenticate.

yaml
1apiVersion: source.toolkit.fluxcd.io/v1
2kind: GitRepository
3metadata:
4 name: your-app # must be unique across all apps
5 namespace: flux-system
6spec:
7 interval: 1m0s
8 ref:
9 branch: main
10 secretRef:
11 name: flux-system # reuse the bootstrap secret for GitHub access
12 url: https://github.com/yourorg/your-app-repo.git

💡 secretRef.name: flux-system reuses the SSH/PAT key that was created during bootstrap. All your private repos under the same GitHub account can use this secret.


File 3 — flux-kustomization.yaml

Tells Flux where inside the app repo to find k8s manifests, and how to apply them.

yaml
1apiVersion: kustomize.toolkit.fluxcd.io/v1
2kind: Kustomization
3metadata:
4 name: your-app # must match the GitRepository name above
5 namespace: flux-system
6spec:
7 interval: 10m
8 path: ./k8s # path inside your app repo where k8s files live
9 prune: true # delete resources removed from git
10 targetNamespace: default # namespace to deploy into
11 sourceRef:
12 kind: GitRepository
13 name: your-app # must match GitRepository metadata.name

⚠️ prune: true means if you delete a file from Git, Flux will delete it from the cluster too.


Part 3 — Push and Verify

1. Push to fleet repo

bash
1cd fleet
2git add clusters/my-cluster/your-app/
3git commit -m "Add your-app to fleet"
4git push

2. Force reconcile (optional, skips the wait interval)

bash
1flux reconcile source git flux-system
2flux reconcile kustomization flux-system

3. Check status

bash
1# See all Flux resources
2flux get all
3
4# Check your specific app
5flux get kustomization your-app
6flux get source git your-app
7
8# If something is wrong, check logs
9flux logs --level=error
10kubectl describe kustomization your-app -n flux-system

Real Examples

Example: chat2md app

clusters/my-cluster/chat2md/gitrepository.yaml

yaml
1apiVersion: source.toolkit.fluxcd.io/v1
2kind: GitRepository
3metadata:
4 name: chat2md
5 namespace: flux-system
6spec:
7 interval: 1m0s
8 ref:
9 branch: main
10 secretRef:
11 name: flux-system
12 url: https://github.com/dedkola/chat2MD.git

clusters/my-cluster/chat2md/flux-kustomization.yaml

yaml
1apiVersion: kustomize.toolkit.fluxcd.io/v1
2kind: Kustomization
3metadata:
4 name: chat2md
5 namespace: flux-system
6spec:
7 interval: 10m
8 path: ./k8s
9 prune: true
10 targetNamespace: default
11 sourceRef:
12 kind: GitRepository
13 name: chat2md

clusters/my-cluster/chat2md/kustomization.yaml

yaml
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - gitrepository.yaml
5 - flux-kustomization.yaml

Example: tk-doc app

clusters/my-cluster/tk-doc/gitrepository.yaml

yaml
1apiVersion: source.toolkit.fluxcd.io/v1
2kind: GitRepository
3metadata:
4 name: tk-doc
5 namespace: flux-system
6spec:
7 interval: 1m0s
8 ref:
9 branch: main
10 secretRef:
11 name: flux-system
12 url: https://github.com/dedkola/tk-doc.git

clusters/my-cluster/tk-doc/flux-kustomization.yaml

yaml
1apiVersion: kustomize.toolkit.fluxcd.io/v1
2kind: Kustomization
3metadata:
4 name: tk-doc
5 namespace: flux-system
6spec:
7 interval: 5m
8 path: ./k8s
9 prune: true
10 targetNamespace: default
11 sourceRef:
12 kind: GitRepository
13 name: tk-doc

clusters/my-cluster/tk-doc/kustomization.yaml

yaml
1apiVersion: kustomize.config.k8s.io/v1beta1
2kind: Kustomization
3resources:
4 - gitrepository.yaml
5 - flux-kustomization.yaml

Quick Reference

Adding a new app checklist

text
1[ ] App repo has /k8s folder with manifests
2[ ] App repo has /k8s/kustomization.yaml listing all manifest files
3[ ] Fleet repo: create clusters/my-cluster/<app-name>/ folder
4[ ] Fleet repo: add kustomization.yaml (lists the other two files)
5[ ] Fleet repo: add gitrepository.yaml (points to app repo)
6[ ] Fleet repo: add flux-kustomization.yaml (deployment config)
7[ ] Push to fleet repo
8[ ] Run flux reconcile source git flux-system
9[ ] Verify with flux get all

Common mistakes

MistakeSymptomFix
kustomizaton.yaml (typo)Flux ignores the folderRename to kustomization.yaml
Wrong path: in flux-kustomizationkustomize build failedCheck where your k8s files actually are
sourceRef.name doesn't match GitRepository.metadata.namenot found errorMake sure both names are identical
Re-running flux bootstrapOther apps disappearNever re-run bootstrap; just add folders
prune: true + deleted fileResources deleted from clusterIntentional — keep files in git to keep resources

Useful commands

bash
1# Watch all Flux resources live
2flux get all --watch
3
4# Force sync a specific app
5flux reconcile kustomization your-app
6
7# Force sync the app's git source
8flux reconcile source git your-app
9
10# See what Flux deployed for an app
11kubectl get all -n default -l app=your-app
12
13# Debug a failing kustomization
14kubectl describe kustomization your-app -n flux-system
15
16# See recent Flux events
17flux events

Fleet Repo Final Structure

After adding multiple apps, your fleet repo should look like this:

text
1fleet/
2 clusters/
3 my-cluster/
4 flux-system/
5 gotk-components.yaml ← auto-generated, DO NOT EDIT
6 gotk-sync.yaml ← auto-generated, DO NOT EDIT
7 kustomization.yaml ← auto-generated, DO NOT EDIT
8 chat2md/
9 kustomization.yaml
10 gitrepository.yaml
11 flux-kustomization.yaml
12 tk-doc/
13 kustomization.yaml
14 gitrepository.yaml
15 flux-kustomization.yaml
16 new-app/ ← just add a new folder, nothing else needed
17 kustomization.yaml
18 gitrepository.yaml
19 flux-kustomization.yaml

🎯 Golden rule: To add a new app — create a folder, add 3 files, push. That's it. Nobody needs to touch any other app's files.