GitOps Scaffolder
Service: gitops-scaffolder · Namespace: kubeopera-core · Jobs run in: kubeopera-provisioning
gitops-scaffolder writes the GitOps environment for a new cluster. Given a cluster's name, domain and region, it generates a complete Flux tree — ingress, certificates, storage, database, monitoring, security and every KubeOpera service, all configured for that cluster's domain, with freshly generated and sealed credentials — and pushes it to Git. host-cluster-controller calls it during the GeneratingGitOpsTree phase.
How a run works
Each run is a Kubernetes Job running scaffold-runner (packaged with the generate-gitops-env tool):
POST /api/v1/scaffolds
▼
Job "scaffold-<id>" in kubeopera-provisioning:
1. clone the target Git repository
2. generate the infrastructure layer only (nothing sealed yet)
3. commit and push
4. wait for the new cluster's Sealed Secrets controller to be Available
5. fetch its public certificate (through the Kubernetes API — no port-forward)
6. generate everything else, sealing fresh credentials with that certificate
7. commit and push
▲
│ polled by host-cluster-controller
Why two passes?
Credentials must be sealed with the new cluster's own Sealed Secrets key — but the Sealed Secrets controller is itself part of the infrastructure layer being generated. So the scaffolder pushes the infrastructure first, waits for Flux to bring Sealed Secrets up on the cluster, and only then seals and pushes the rest.
The generated tree encodes the same order for Flux: the infrastructure Kustomization has no dependencies, and apps, database and cert-manager-config each depend on infrastructure.
What gets generated
Using the reference environment as a template:
- the infrastructure layer — cert-manager, ingress-nginx, storage classes, monitoring, Kyverno, Falco and Sealed Secrets — with external-dns pointed at the new cluster's domain and region;
- a hostname for every service under the cluster's domain, as overlay patches (the shared
base/manifests are never edited); - fresh credentials — PostgreSQL, RabbitMQ and a registry pull secret (or your own, if you supplied one) — sealed before they're committed.
See Setup: creating more environments.
The target can be the platform's shared GitOps repository or your own repository, with credentials supplied when the cluster is created.
API
Only KubeOpera's own services call this API, using their service identities.
| Method | Path | Description |
|---|---|---|
POST | /api/v1/scaffolds | Start a run. Returns 202 immediately with the job. |
GET | /api/v1/scaffolds/{id} | Status, message and the generated gitops_path. |
GET | /api/v1/scaffolds/{id}/logs | Job logs. |
GET | /healthz | Health check. |
Operating it
kubectl logs -n kubeopera-core deploy/gitops-scaffolder -f
kubectl get jobs -n kubeopera-provisioning
kubectl logs -n kubeopera-provisioning job/scaffold-<id> -f
Configuration
| Variable | Default | Description |
|---|---|---|
DATABASE_URL | — | PostgreSQL connection. |
JOB_NAMESPACE | kubeopera-provisioning | Where scaffolding Jobs run. |
SCAFFOLD_RUNNER_IMAGE | pinned release | The scaffold-runner image. |
DEFAULT_GITOPS_REPO_URL | — | The platform's shared GitOps repository. |
REFERENCE_ENVIRONMENT | development | The environment used as the template. |