Skip to content
In this Guide

In this Guide

Deep Dives

AI: Claude and Codex patterns

ConfigHub: Deploy and manage

A Guide

Compose and check a stack

Free until upload

Get a stack, check it before anything runs, then run and govern it. The Stacks list holds every shipped stack.

To build a stack from Catalog entries instead of a shipped one, follow Make a stack from Catalog entries.

one install, three commands
$ cub plugin install confighub/cub-workshop@v0.6.61

$ cub stack sandbox eks-inference
  [PASS] no resource conflicts across components (130 objects)
  [WARN] 2 object(s) carried more than once inside one component with identical content; kubectl apply keeps the last, but cub stack upload refuses the component:
      apiextensions.k8s.io/v1|CustomResourceDefinition||fieldexports.services.k8s.aws  x3  inside  ack-controllers
      apiextensions.k8s.io/v1|CustomResourceDefinition||iamroleselectors.services.k8s.aws  x3  inside  ack-controllers
  [PASS] CRD ordering: 46 CRDs are delivered before the 25 custom resources that need them
  [PASS] served API versions: 25 custom resource(s) match their bundled CRD; target availability is not checked
  [PASS] no admission webhooks need a certificate
  [WARN] namespaces: 4 created, 1 must already exist (kube-system)
  => CHECKED
  130 objects total
  Rendered, but `cub stack upload` will refuse it: ack-controllers defines an object more than once (the WARN above).

$ cub stack check metrics-double
  [FAIL] 9 resource conflict(s) - the same object is claimed by more than one component:
      rbac.authorization.k8s.io/v1|ClusterRoleBinding||metrics-server:system:auth-delegator  <=  metrics-server + metrics-server-again
  => REFUSED

The check is a hard gate. A real conflict refuses the whole stack and exits non-zero, which is why metrics-double fails: two of its components claim the same nine objects. A warning is not a rejection. eks-inference still passes the check with a warning that identical CRDs appear more than once inside one component. That is not a clash between components, so the check passes. cub stack upload refuses that component until it is rebuilt, and the sandbox says so.

Get a stack

You want a stack — a set of configs checked for conflicts before they render. Here is how you get one.

1. Want a ready-made one?

First time here? Install the Workshop plugin, then run cub stack sandbox eks-inference in a scratch directory. Despite the name, this renders and checks local configuration; it does not create an EKS cluster or request a GPU. Read the check result and missing prerequisites before considering delivery.

Pick a shipped stack and check it in one command. cub stack sandbox eks-inference renders 130 objects from eight certified bundles, each hash-verified against its receipt. Sixteen ship, from a full inference platform to three services; see the stacks that ship.

2. Composing your own?

Write a manifest that names catalog parts by digest, or let an assistant draft one from images you have already checked. Each part is a bundle pinned by digest with a receipt, or a file of rendered objects the stack owns. Then run cub stack check <file>, read what it names wrong, fix it, and run again until it passes. The check is the contract you build against; read the manifest specification.

3. Already have a Kubara platform?

Turn a Kubara platform into a stack with cub stack from-kubara .. It renders with the values Kubara generated, so the check reads the platform you actually have. Build a platform walks the whole Kubara journey, generate to deploy.

4. Ready to run it with a team?

Upload the stack, place it on clusters, then promote and gate it in ConfigHub. That is where a stack becomes a platform, in Run and govern it below.

Checking your stack

Resource conflicts

No two components may claim the same object. This is the hard failure, and it exits non-zero.

CRD before CR

Every custom resource's CRD must be present and delivered first, across components.

Admission webhooks

Which webhooks need a certificate, and whether cert-manager is in the stack to issue it.

Namespaces

Which namespaces the stack creates, and which must already exist before it lands.

What each app needs

An app's own objects say what the platform must carry: an ingress controller that answers to its class, cert-manager, a Prometheus operator, external-secrets. A stack that lacks one is refused, and the message names the fix.

Two shipped stacks exist to be refused. metrics-double carries two copies of metrics-server that claim the same nine objects. conflict-demo carries two authored components that define one ConfigMap differently.

Check your own app on a shipped platform

Start from your app's rendered YAML. The app check names what it needs. Save a shipped platform as a workspace, add your app to it, and check the whole stack. cub stack list names the shipped platforms: web-platform carries ingress, certificates and monitoring, and app-platform adds a database and a cache.

New to cub? Install the cub CLI first. Public catalog packages pull and render anonymously, and you sign in only once a command saves or changes ConfigHub data.

cub app check ./my-app.yaml
cub stack sandbox web-platform --workspace my-platform
cp ./my-app.yaml my-platform/components/99-my-app.yaml
cat >> my-platform/stack.yaml <<'YAML'
    - name: my-app
      authored: components/99-my-app.yaml
YAML
cub stack check my-platform/stack.yaml

A passing check says whether the stack carries what your app needs, and lists what must exist first: namespaces, a ClusterIssuer your Certificate names, or CRDs a component does not ship. It checks configuration only. It installs nothing and does not show that the app works on a cluster.

A refusal is a starting point, not a dead end. Change either side, adapt the app or grow the platform by the service it needs, and run the check again until it passes. The app and the platform negotiate through the check, so the platform ends up shaped by its apps. That is how the kubara-shop-first-try refusal becomes kubara-shop-platform.

Deploy a tiny first stack

web-tiny is the bounded teaching path: two components, each holding one ConfigMap in the web namespace. The steps below continue beyond upload into two ConfigHub Bases, two target-bound dev variants, two Releases, two Argo CD Applications, and two object checks. They are a runnable path, not a retained live receipt, and they do not claim that every arbitrary stack is safe to deploy this way.

1. Check the composition and create a target

$ cub plugin install confighub/cub-workshop@v0.6.61

$ cub stack check web-tiny
CHECKED; two ConfigMaps; no cluster write

$ cub auth login

$ cub cluster up --name workshop

$ source ~/.confighub/clusters/workshop.env

2. Download the same two component files

$ curl -fsSLO https://raw.githubusercontent.com/confighub/cub-workshop/v0.6.58/components/frontend-config.yaml

$ curl -fsSLO https://raw.githubusercontent.com/confighub/cub-workshop/v0.6.58/components/backend-config.yaml

Read both files. Each holds one ConfigMap in the web namespace and no Namespace object. Step 3 creates the Namespace in the first component with --create-namespace, and the second component reuses it, so two Argo Applications do not compete to manage the same Namespace object.

3. Import, place, and release each component

$ cub variant upload --component first-stack-frontend --variant base --namespace web --create-namespace ./frontend-config.yaml

$ cub variant upload --component first-stack-backend --variant base --namespace web ./backend-config.yaml

$ cub variant create dev first-stack-frontend-base --target workshop/target --namespace web

$ cub variant create dev first-stack-backend-base --target workshop/target --namespace web

$ cub release publish first-stack-frontend-dev

$ cub release publish first-stack-backend-dev

4. Prove controller and cluster state

$ kubectl get applications -n argocd first-stack-frontend-dev first-stack-backend-dev
both rows must report Synced and Healthy

$ kubectl get configmap -n web frontend-config backend-config

The Releases prove ConfigHub accepted immutable desired configuration. The Argo rows prove the controller saw it. The ConfigMaps prove the target received both components. If one checkpoint is missing, stop there instead of calling the stack live.

From v0.6.57 the Workshop plugin also lists a bounded stack deploy helper for web-tiny, which performs step 3 and refuses every other stack. This page keeps the explicit commands, so each step stays visible.

The stacks that ship, by altitude

A full stack, cloud to workload

StackComposed fromResult
eks-inferenceeight digest-pinned bundles with receipts across all three planes: a cloud network, an EKS cluster, node autoscaling, a GPU runtime, and the inference workloadCHECKED, 130 objects

Platform services on a cluster you already run

StackComposed fromResult
app-platformcert-manager, ingress-nginx, postgresql, redis, kube-prometheus-stackCHECKED
data-servicesredis, postgresql, rabbitmqCHECKED, 31 objects, no CRDs
gitops-secretscert-manager, external-secrets, argo-cdCHECKED, 26 CRDs composed together
gpu-nodeNVIDIA's GPU Operator, NVSentinel and cluster-readiness-engine, from the Catalog's published bundlesCHECKED, 89 objects; a static composition only, and nothing runs on a GPU
kubara-gitops-shopKubara components with Argo CD and the adapted shop appCHECKED, 184 objects; a static composition only
kubara-platformthe catalog's reviewed renders for a Kubara platformCHECKED, 86 objects
kubara-shop-platformthe Kubara platform grown by external-secrets, with the app adapted to Traefik's classCHECKED, 135 objects, every app need carried
observability-basecert-manager, metrics-server, kube-prometheus-stackCHECKED, 175 objects, 10 CRDs before 50 custom resources
redis-platformredis, external-secrets, kube-prometheus-stackCHECKED
shop-platformcert-manager, ingress-nginx, kube-prometheus-stack, rabbitmq, and the shop appCHECKED, 192 objects, every app need carried
web-platformcert-manager, ingress-nginx, kube-prometheus-stackCHECKED; carries what an app like shop-web depends on
web-tinytwo authored ConfigMaps, sized for a live uploadCHECKED

Made to be refused, to show the gate

StackComposed fromResult
conflict-demotwo authored components, one ConfigMap defined two waysREFUSED
kubara-shop-first-trythe Kubara platform as first picked, with the shop app placed on itREFUSED: the app asks for the nginx ingress class and a Prometheus operator, and the platform carries neither
metrics-doublemetrics-server, twiceREFUSED: nine objects claimed twice

The bundle-form stacks pull from public registries by digest. The render-form stacks ship inside the plugin, so they check offline.

What a stack is, in full

One manifest, checked first

A stack is a set of charts and YAML named in one manifest and checked for conflicts before it renders.

A fleet places it

A fleet says which stacks and apps land on which clusters.

Runs as a cub plugin today

Both run today as a cub plugin.

Free until upload

Check and sandbox need no cluster and no account. Upload and the fleet verbs need a ConfigHub organization you can write to.

A stack is a set of parts named in one manifest and checked before any of it runs. A platform is what a stack becomes once it is running under governance with your apps on it. A fleet is that stack and its apps placed across many clusters as data. So a stack is what you get and check, a platform is the outcome once it runs, and each cluster in a fleet becomes its own platform.

An app, in turn, is “a workload you bring,” as Apps on a platform defines it. Stacks range from a cloud network, cluster, and GPU runtime built from an empty account down to three services on a cluster you already run, and an AICR-generated AI platform is a stack in this same sense. The taxonomy note sets these paths out in full.

Run and govern it

cub stack upload <name> --run checks first, then builds one base Space per component in ConfigHub and the links the manifest declares. It does not place or release those components. Without --run it prints the plan and changes nothing. The tiny first stack shows the additional target placement, Release, controller, and live-object checkpoints explicitly. From there ConfigHub's own verbs take over: cub variant create places a base on a target, cub release publish releases it by digest, and cub variant promote moves a reviewed change up the tree.

A fleet places a stack across many clusters as data. cub fleet up meridian scaffolds ten regional cluster Spaces, uploads twenty component bases, and places and releases their deployments through those same governed verbs. cub fleet status meridian then recomputes four attention tiles, blocking gates, unreleased changes, upgrades available, and outstanding rollouts, from the queries the product runs. The fleet model is specified alongside the stack manifest.

A stack can also leave as OCI with no account. cub stack publish <name> --out oci://… publishes it as an index of images with the manifest and verdict attached, and cub stack sandbox <name> --out oci://… publishes the flattened form a reconciler pulls. Every result is an image. See every OCI shape in one table.

What you can do with the workshop plugin

Config's tool table introduces the plugin as one free path. Here is its full command surface, from a first check to a fleet.

LevelDo thisCommandWhat you get
BasicSee what a chart installscub config check redisThe objects, what the chart hides, and what the cluster must already have.
BasicSee what an app needs from its platformcub app check shop-webThe services the app's own objects ask for: an ingress controller, cert-manager, an operator.
BasicCheck and render a stackcub stack sandbox kubara-shop-platformCHECKED or REFUSED, with every check named, and the rendered objects. No cluster.
BasicSee a refusalcub stack check kubara-shop-first-tryThe two reasons the shop app cannot run on the platform as first picked.
AdvancedHand a check on as a verified imagecub config check redis --out oci://REGISTRY/redis:v1
cub config verify oci://REGISTRY/redis@sha256:…
An image with its receipt attached, and a verify that refuses an image with no receipt.
AdvancedPublish a stack as an indexcub stack publish shop-platform --out oci://REGISTRY/shop-platform:v1
cub stack check oci://REGISTRY/shop-platform@sha256:…
One image per part under one index digest, checkable straight from the registry.
AdvancedUpload a checked stack into ConfigHubcub stack upload kubara-shop-platform --runA base Space per part, one Unit per file, linked the way the manifest says.
AdvancedBuild a fleet from a manifestcub fleet plan demo-platform
cub fleet up demo-platform
cub fleet status demo-platform
Clusters, bases, deployments, and releases for every placement, then four tiles: gates, unreleased, upgrades, rollouts.

Fleet operations live here too. cub changeorder create traefik-wave --space traefik-base --in-scope-space traefik-demo-dev,traefik-demo-staging --description "…" rolls one change across every Space in its scope, and cub fleet status reports the same gates, unreleased changes, upgrades, and rollouts for the whole fleet.

Fleet status, gates, and rollouts sit here rather than on the Operations page, because a fleet is a stack placed across many clusters, and stack is where that noun is defined. Operate keeps the single-target verbs: release, promote, gate, and roll back.

Run it

These four run here. The ten-minute demo walks all of them end to end, from one chart to a governed fleet.

$ cub plugin install confighub/cub-workshop@v0.6.61

# CHECKED, 130 objects, no cluster
$ cub stack sandbox eks-inference

# REFUSED: nine objects claimed twice
$ cub stack check metrics-double

# a real Kubara platform, as a stack to check
$ cub stack from-kubara ./my-kubara-platform

# an index of images
$ cub stack publish shop-platform --out oci://REGISTRY/shop-platform:v1

Every manifest on this page ships in the plugin: the stacks directory, with eks-inference as the worked example and the ten-minute walkthrough. The site links these files and never copies them, so the file you read is the file the plugin runs.