Platform requirements
Konduit ships in the Konstruct chart with the theme-operator disabled (replicaCount: 0). Enabling it requires registry, build, and deployment infrastructure. Everything below was validated live on a Civo control plane with self-hosted GitLab.
Checklist
- Harbor registry — reachable at
harbor.<domain>behind the platform gateway. The operator needs admin credentials to create per-org projects and robot accounts. - kpack with a Paketo ClusterBuilder named
defaultthat pushes to Harbor. Grant its ServiceAccount adockerconfigjsonsecret for the registry. - A target cluster pool — each entry in the operator's
VALID_CLUSTERSmust exist as a named Argo CD cluster (the operator's Applications usedestination.name). - A
theme-appsArgo CD Application watchingregistry/clusters/<pool-cluster>/in the GitOps repository the operator commits to (the org GitAccount's repository). - An apps wildcard listener on the gateway with a wildcard certificate for
*.<region>.<domain>(DNS-01 — HTTP-01 cannot issue wildcards). This same listener serves theme hostnames (theme-<name>-<org-host>) — there's no separate listener for themes. - theme-operator enabled in the konstruct chart values.
Show Konduit in the navigation
Konduit and other platform theme entries are visible by default only on the managed SaaS. A self-hosted control plane that meets the checklist above opts in with one API flag — the UI reads it from /api/v1/config (konduit_enabled):
konstruct-api:
konduitEnabled: true
Without the flag, the pages still exist at their direct routes (/theme, /theme/settings) — only the navigation entries are hidden.
Operator configuration
theme-operator:
replicaCount: 1
config:
harbor:
existingSecret: theme-operator-config
externalSecret: # sync HARBOR_URL/USERNAME/PASSWORD from Vault
enabled: true
secretStoreRef: { name: vault-kv-secret, kind: ClusterSecretStore }
remoteRefs:
url: { key: konstruct/theme/harbor, property: url }
username: { key: konstruct/theme/harbor, property: username }
password: { key: konstruct/theme/harbor, property: password }
kpackBuilder: "default"
managedOrgNamespace: "<platform-org-namespace>"
baseDomain: "<domain>"
gitOps: { branch: main }
chart:
repoURL: "https://github.com/konstructio/konstruct-templates"
path: "templates/konstruct-web-service"
revision: "<branch-or-ref>"
validClusters:
- k-nyc1
Hard-won gotchas
A declarative cluster secret pointing at https://kubernetes.default.svc silently renames Argo CD's implicit in-cluster entry — every Application addressed by destination.name: in-cluster breaks. For a named pool entry on the same cluster, use the cluster's external API endpoint with credentials synced from Vault.
The konstruct-web-service chart's HTTPRoute parentRef expects the apps wildcard listener to be named exactly https-apps on gateway eg in namespace default. A differently named listener rejects every app route with "No listeners match this parent ref".
Paketo buildpack images live at docker.io/paketobuildpacks/*. The old gcr.io/paketo-buildpacks mirror is dead and fails with an authentication error.
The registry hostname must resolve DNS-only (no CDN/proxy in front). Proxied records break TLS to the origin and cap upload bodies below container-layer sizes.
Verify
# builder ready and pushed to Harbor
kubectl get clusterbuilder default
# operator running with Harbor credentials synced
kubectl get pods -n konstruct-system | grep theme-operator
kubectl get externalsecret -n konstruct-system theme-operator-config
# register a test app, then follow it
kubectl get themedapps -A -w