Skip to content
In this Guide

In this Guide

Deep Dives

AI: Claude and Codex patterns

ConfigHub: Deploy and manage

A Guide

Bring your Flux fleet into ConfigHub

Flux stays your delivery controller. ConfigHub adds reviewed configuration, approvals, and immutable releases; begin by reading the repository it already delivers.

Prefer to do this with your AI agent?

1. What changes, and what does not

Flux stays the delivery controller. Preview has no account or cluster mutation; import makes a parallel ConfigHub copy while Git still delivers; handover then moves sources to reviewed releases. Handover has checks and recovery steps, not zero risk.

Start with a small disposable estate. Roots, generators, and pruning can make production migration an ordered fleet operation.

Who does what, before and after

Before the handoverAfter the handover
Source of truthGitConfigHub
Fluxreconciles each layer from Gitstill reconciles each layer, from the release ConfigHub published
A changeis a commit to the Git pathis an edit in ConfigHub, released after the approvals its stage asks for
A commit to the old Git pathreaches the clusterno longer reaches the cluster

The handover is the step that moves the source of truth. Until handover.sh runs, ConfigHub holds a copy that nothing reads. The flux-system bootstrap and the Flux controllers stay outside ConfigHub, and the plan lists them.

Some teams on Argo CD? Bring your Argo CD apps into ConfigHub follows the same steps.

2. Preview the setup

Install the cub CLI and this released plugin:

cub plugin install confighub/examples@cub-flux-v0.5.1 --name flux

What you need: a local checkout of the Git repository this Flux installation reads, the cub CLI, and this plugin. Start in that repository's root; replace the directory placeholder below with its path. Planning reads the repository and needs no ConfigHub account or cluster.

cd <your-flux-gitops-repository>
cub flux plan . --require Healthy

--require Healthy makes later promotions wait for live health. Layers with workloads need wait or healthChecks; otherwise the reporter records health as Unknown. Planning itself does not prove health.

Read the result. The summary gives the estate or fleet size and the component and variant counts. The following lines map shared configuration to bases and cluster differences to variants. Check the stage order and warnings before continuing. This plan does not validate the destination.

Illustrative plan output

This is actual output from the public beginner fixture, not from your repository.

Flux fleet: 2 clusters, 2 layers, 4 variants
Read 16 objects

Clusters, one stage each, in order: dev (clusters/dev), prod (clusters/prod)
Reconcile order (dependsOn): infrastructure -> apps

infrastructure
  base     flux-infrastructure-base  from gitops/flux/beginner/infrastructure/base
  stage dev
    dev         variant flux-infrastructure-dev  ->  Target flux-targets/dev
                Kustomization flux-system/infrastructure, path gitops/flux/beginner/infrastructure/dev
  stage prod
    prod        variant flux-infrastructure-prod  ->  Target flux-targets/prod
                Kustomization flux-system/infrastructure, path gitops/flux/beginner/infrastructure/prod

apps  (after infrastructure)
  base     flux-apps-base  from gitops/flux/beginner/apps/base
  stage dev
    dev         variant flux-apps-dev  ->  Target flux-targets/dev
                Kustomization flux-system/apps, path gitops/flux/beginner/apps/dev
                  adds namespace.yaml
                  namespace apptique-dev
                  label environment=dev
                  Deployment/frontend replace /spec/replicas = 1
                  Flux spec.healthChecks[0].namespace = apptique-dev
                  Flux spec.targetNamespace = apptique-dev
  stage prod
    prod        variant flux-apps-prod  ->  Target flux-targets/prod
                Kustomization flux-system/apps, path gitops/flux/beginner/apps/prod
                  adds namespace.yaml
                  namespace apptique-prod
                  label environment=prod
                  Deployment/frontend replace /spec/replicas = 3
                  Deployment/frontend replace /spec/template/spec/containers/0/resources/requests/cpu = 200m
                  Deployment/frontend replace /spec/template/spec/containers/0/resources/requests/memory = 128Mi
                  Deployment/frontend replace /spec/template/spec/containers/0/resources/limits/cpu = 400m
                  Deployment/frontend replace /spec/template/spec/containers/0/resources/limits/memory = 256Mi
                  Flux spec.healthChecks[0].namespace = apptique-prod
                  Flux spec.targetNamespace = apptique-prod

Sources
  - GitRepository apptique-examples  https://github.com/confighub/examples  (gitops/flux/beginner/infrastructure/base/sources/apptique-examples.yaml)
      branch: dev main, prod main

Bootstrap (stays outside ConfigHub)
  - gitops/flux/beginner/clusters/dev/flux-system
  - gitops/flux/beginner/clusters/prod/flux-system

Handover (apply will write it as handover.sh; plan runs nothing)
  1. keep each layer's Flux Kustomization under its own name and switch its sourceRef to an OCIRepository on the ConfigHub gateway, so Flux keeps its inventory and nothing is reinstalled
  2. first prove each variant renders exactly what Git renders today: infrastructure, apps prune, so anything the release lacks is deleted
  3. leave flux-system alone: flux bootstrap owns it, like the Sveltos management record

Next
  cub flux apply . --require Healthy --out ./flux-onboarding
  That writes apply.sh, handover.sh and cleanup.sh. It runs nothing.

Read the full Flux planning reference for layouts and limits.

Try it on the fixture first

These commands print the output above. They need no repository of your own.

git clone https://github.com/confighub/examples.git
cd examples
git checkout 7f1b8f2fc849bb6488bc2c58f1469172018fc9dd
cd gitops/flux/beginner
cub flux plan . --require Healthy

Run the plan inside a Git checkout. In a copy with no .git directory the plan reports source paths as missing, and --repo-root <checkout> tells it where the repository starts.

What one Kustomization becomes

cub flux apply . --require Healthy --out onboard writes files only. For each cluster and layer it writes what Flux would run after the handover under onboard/layers/. On the fixture, onboard/layers/dev/apps.yaml holds the apps Kustomization from clusters/dev/apps.yaml with two fields changed, and one new OCIRepository beside it.

 kind: Kustomization
 metadata:
   name: apps
   namespace: flux-system
 spec:
-  path: ./gitops/flux/beginner/apps/dev
+  path: ./
   sourceRef:
-    kind: GitRepository
-    name: apptique-examples
+    kind: OCIRepository
+    name: apps

The Kustomization keeps its name, so Flux keeps its record of what it applied. The new OCIRepository reads the Space the plan names as the variant, flux-apps-dev. The generated file holds placeholders for the gateway address, and the scripts fill them in.

A HelmRelease is stored as it is, and helm-controller goes on resolving it. The plugin does not render Helm charts. The fixture has no HelmRelease, so this page shows none.

How to go back

After this stepGo back by
cub flux plan . --require HealthyNothing to undo.
cub flux apply . --require Healthy --out onboardDelete onboard/.
bash onboard/apply.shRun bash onboard/cleanup.sh. It removes what the script made in ConfigHub. Flux still reads Git.
bash onboard/handover.shStop the root pruning, restore both fields on each layer as the script recorded them, then remove the root. The script prints the commands in that order. Do not delete the ConfigHub Spaces first.

You can stop here. The plan is read-only. To generate local scripts, connect delivery, or make a reviewed change, open the advanced steps below.

After the preview: save, connect delivery and make a change

3. Save the reviewed setup in ConfigHub

When the plan is clear, generate the setup directory. This writes files and scripts only.

cub flux apply . --require Healthy --out onboard

Read onboard/; delete it to discard this step. Flux keeps reading Git while you review the generated setup.

Check what a source will store

apply.sh stores what each Kustomization's source path renders to. Before you run it, you can check a source with cub config check from the Workshop plugin. It reads files only. On the fixture, the dev cluster's apps layer reads apps/dev. Check that path, not the files under onboard/layers/, which hold placeholders the scripts fill in:

cub plugin install confighub/cub-workshop@v0.6.61
kustomize build apps/dev > apps-dev.yaml
cub config check apps-dev.yaml

On the fixture it reports 4 objects (a Deployment, a Namespace, a Service and a ServiceAccount), no lifecycle work, and a passing schema check. The schema step names any field the API server would reject, so you can fix it in Git before you save.

Only the next command saves ConfigHub data. It needs cub auth login, kustomize, and any requested gateway. It creates bases, variants, stages, and releases, not cluster changes.

CONFIGHUB_OCI=<gateway> bash onboard/apply.sh

Keep this import separate from production handover; practice first with a disposable estate.

4. Connect deployment

This first cluster-changing step checks the reviewed release against the controller record before moving a source. Replace every angle-bracket value below.

The handover installs one small bootstrap root, then moves the layers it manages. Use the separate join script only for a new Flux cluster that has none of those layers already. Do not assume production can move one application at a time.

Review ownership first. Pruning can delete an object absent from the reviewed release. Confirm the printed way back, ownership, backups, and objects. Keep SOPS-encrypted workload Secrets and registry credentials outside review output. The generated bootstrap pull Secret is delivery access, not an application Secret.

Contexts, gateway, and fleet handover parameters

A gateway is the OCI address controllers use to pull ConfigHub releases: ConfigHub Cloud uses oci.hub.confighub.com, without a scheme. A context is the named kubeconfig context that reaches the stated cluster.

Flux runs handover one existing cluster at a time:

CONFIGHUB_OCI=oci.hub.confighub.com CLUSTER=<cluster> FLUX_CONTEXT=<kubectl-context> bash onboard/handover.sh

Advanced handover and recovery reference. Do not delete ConfigHub spaces as rollback: restore controller sources first, then use the script’s printed order.

5. Change, approve, and release

After handover, a reviewed ConfigHub change moves through stages. Independent approval is not default; configure it and separate credentials when needed.

A small change, approval, and first release

For Flux, make the change in ConfigHub after the layer has moved, then promote it through the stages the generated workflow created. The released guide gives this approval form:

cub variant approve --change-order <space>/<order> --stage <stage>

The server refuses a later stage until the earlier release has been approved and published.

Live status is also a write. This sends the observed revision and health to ConfigHub.

cub flux status . --cluster <cluster> --kube-context <kubectl-context> --watch

That reports for as long as you keep it running. cub flux apply also writes fluxbot.sh, which runs the same reporter on the cluster as one pod. It adds that pod to the Flux namespace and a permission in ConfigHub.

FLUX_CONTEXT=<kubectl-context> CLUSTER=<cluster> CONFIGHUB_URL=<ConfigHub address> bash onboard/fluxbot.sh

Read the Flux status details. A release, controller sync, and workload health are separate results; record the exact revision and target for each.