Quick Start: Deploying Applications with Flux (Infra-Owned Registry)

• 5 min read
Last updated on

Revised 2026-08-16 — rewritten for clarity. The steps and manifests are unchanged.

This guide shows how to deploy a new application into a cluster using one shared Flux installation and an infra-owned app registry. The application repo stays clean—standard Kustomize base/ and overlays/, no Flux CRDs—and onboarding an app takes a single small change in the infra repo.

Prerequisites

  • kubectl access to the cluster
  • The Flux CLI installed
  • An infra/cluster Git repository ready (it can be empty)

Step 0: Bootstrap Flux (infra repo)

Flux bootstrap installs the Flux controllers into the cluster and commits the core sync manifests into your infra repo.

Validate prerequisites first:

flux check --pre

Then bootstrap. This example uses GitHub:

flux bootstrap github \
  --owner=YOUR_GH_ORG \
  --repository=YOUR_INFRA_REPO \
  --branch=main \
  --path=clusters/prod \
  --personal=false

Your infra repo will now include:

clusters/prod/flux-system/
  gotk-components.yaml
  gotk-sync.yaml
  kustomization.yaml

Flux continuously reconciles the infra repo path you bootstrapped.

Step 1: Add the apps registry entry point

Bootstrap syncs only clusters/prod/flux-system/. To onboard apps through an infra-owned registry, add one more Flux Kustomization pointing at an apps registry directory.

Create the directory in your infra repo:

clusters/prod/apps/
  kustomization.yaml

clusters/prod/apps/kustomization.yaml starts empty and will later list one registry file per application:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources: []

Next, create the Flux Kustomization that activates the registry, at 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

Finally, make sure Flux’s sync picks it up. Edit clusters/prod/flux-system/kustomization.yaml—this is the Kustomize file, not the Flux CR—and add 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. Flux is installed, the infra repo is reconciling, and the registry directory is live—but no applications are deployed yet.

Understanding path resolution: Flux vs Kustomize

Flux and Kustomize resolve paths differently, on purpose, and this is where most mistakes happen.

Flux’s Kustomization.spec.path is always resolved relative to the root of the Git repository referenced by sourceRef—never relative to the location of the YAML file that declares it. So:

spec:
  path: ./clusters/prod/apps

always means <git-repo-root>/clusters/prod/apps. That’s why Flux paths tend to look absolute within the repo.

Paths inside a kustomization.yaml, such as entries under resources:, work the ordinary way: they resolve relative to the directory containing that file. Inside clusters/prod/apps/kustomization.yaml, this:

resources:
  - app-foo.yaml

resolves to clusters/prod/apps/app-foo.yaml.

The short version is that Flux chooses the entry directory and Kustomize resolves everything underneath it.

Step 2: Create the application repository

Create a Git repository for your app with this 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

Check that the manifests build locally before going further:

kustomize build overlays/prod

Step 3: Create a deploy key for the app repo

Create a deploy key for the app repository with read-only access, then store it in the cluster as 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 registry entry at 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

Then add the file to the registry’s Kustomize list:

# clusters/prod/apps/kustomization.yaml
resources:
  - app-foo.yaml

Commit and push.

Step 5: Watch Flux deploy the app

Flux fetches the app repository, builds overlays/prod, applies the manifests into the app-foo namespace, and reconciles changes from then on. Watch it happen with:

flux get kustomizations
flux get sources git

Updating and removing the app

To update, push changes to the app repo. Flux reconciles automatically and the infra repo needs no changes at all.

To remove, delete app-foo.yaml from clusters/prod/apps/, then commit and push. Flux prunes the app’s registry objects and stops reconciling it.

Why this model works

Ownership is clear: infra owns cluster topology, apps own their own manifests. The Flux surface area stays small, since there’s one installation per cluster and one registry entry point. And the lifecycle is predictable—adding or removing a file in the registry is the same thing as deploying or undeploying the app, which is what makes this scale to many apps and teams without turning into a pile of one-off Flux CRDs.