Build Service
Repo: o-apps/build-service · Port: 8098
Build Service turns a tenant's own Git repository into a running app, without the platform ever needing to see anything beyond a public or private clone URL. It's the piece that makes the Deploy Application Wizard's "GitHub Repository" source option real: give it a repository, branch, and Dockerfile path, and it produces a container image that hands off directly into the same deployment path a registry-image deploy already uses — this service never gets its own separate way of running an app, it only ever produces an image and lets KubeOpera API take it from there.
How a build runs
Each build is one Kaniko Job, created in a dedicated kubeopera-builds namespace on the host cluster rather than inside any tenant's vCluster — this keeps build privileges and capacity centrally managed, rather than granting every tenant vCluster the ability to run privileged build pods. The Job clones the requested repository (using a mounted, ephemeral Secret for a private-repo token, or a persistent one stored against a registered Build Config for repeat builds of the same repo), runs Kaniko against the given Dockerfile path and build context, and pushes the resulting image to a per-tenant path in KubeOpera's own self-hosted registry — registry.dev.kubeopera.io:5000/tenant-<tenant_id>/<app_id>:<timestamp>. Kaniko was chosen over Buildpacks (too much implicit magic for a Dockerfile-centric wizard) and over Tekton (a heavier dependency than warranted for "clone, build, push").
Every build's registry credentials are provisioned per tenant, not shared — see Auth Service for how the registry's own token issuer scopes a push/pull credential to exactly one tenant's path, so one tenant's build can never read or overwrite another's images.
Build Configs — auto-rebuild on push
A Build Config is a standing registration of "this repository and branch belong to this app" — register one once, and every future push triggers a fresh build automatically, without needing to go back through the wizard. POST /webhook/github and POST /webhook/gitlab are the receiving end of this: on a push event, the service looks up a matching registered config by repository and branch and starts a build from it. A push to a repository with no registered config is treated as a normal, silent no-op rather than an error — GitHub and GitLab both surface webhook delivery failures to the repository owner, and an unregistered repository is an expected, common case, not a misconfiguration worth alarming anyone about.
A Build Config can also be triggered manually, on demand, without waiting for a push — useful for the very first build after registering a config, or for re-running a build against the same source without a new commit.
Reporting into a Pipeline
When a build is associated with a Pipeline (set once, automatically, the first time a tenant deploys from a given repository — see KubeOpera API's Pipelines section), the service reports its own progress into that Pipeline's run history in the background, independently of whatever triggered the build. This matters because a tenant might close the deploy wizard, or their whole browser, before a build finishes — since the reporting happens server-side rather than depending on the frontend staying open to poll for completion, the Pipeline's run still reaches a correct final status (clone and build-and-push stages, each with real start/finish timestamps read directly from the Kaniko Pod's own container statuses) regardless of whether anyone is still watching.
REST API
| Method | Path | Description |
|---|---|---|
POST | /api/v1/builds | Start a build |
GET | /api/v1/builds | List builds |
GET | /api/v1/builds/{id} | Build status |
GET | /api/v1/builds/{id}/logs | Kaniko Job logs |
POST | /api/v1/build-configs | Register an auto-rebuild-on-push config |
GET | /api/v1/build-configs | List configs |
DELETE | /api/v1/build-configs/{id} | Remove a config |
POST | /api/v1/build-configs/{id}/trigger | Manually launch a build from a registered config |
POST | /webhook/github | /webhook/gitlab | Inbound push webhooks (public, unauthenticated by design — verified by GitHub/GitLab's own signature scheme where configured) |
GET | /health | Health check |
All /api/v1/* routes are internal, API-key-authenticated calls from KubeOpera API, which resolves the caller's tenant from their session and forwards it explicitly — this service itself never trusts a client-supplied tenant ID.
Environment Variables
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection |
MIGRATIONS_DIR | Path to goose migration files |
CICD_GATEWAY_BASE_URL / CICD_GATEWAY_API_KEY | Internal call for the background Pipeline-progress reporting described above |
GITHUB_WEBHOOK_SECRET / GITLAB_WEBHOOK_TOKEN | Optional — verifies inbound webhook signatures when set |
HTTP_PORT | HTTP port (default: 8098) |