Architecture
Dploy is built as a Kubernetes operator plus a thin API. The two communicate only through custom resources — a deliberate separation that keeps the API stateless and prevents it from touching the deployment engine directly.
Overview
Section titled “Overview”Components
Section titled “Components”Dploy API
Section titled “Dploy API”A stateless GoFiber server that:
- authenticates requests via JWT/OIDC (JWKS, cached 15 min),
- serves the catalog by listing
DployTemplateresources, - creates/claims/extends/deletes
DployInstanceresources, - serves the embedded web UI.
It has no Flux permissions — its RBAC only allows reading DployTemplates and CRUD on
DployInstances in a single namespace. It physically cannot create a HelmRelease.
Dploy operator
Section titled “Dploy operator”Two controllers built with controller-runtime:
- DployInstance controller — the core. For each instance it generates an immutable UUID,
creates the workload namespace, renders the connection URL and Helm values, ensures a Flux
source +
HelmRelease, projects the release’s status back, and enforces the TTL. - DployTemplate controller — maintains the warm pool for pool-method templates (creating
unclaimed instances up to
pool.size) and reports occupancy in the template status.
Dploy delegates all deployment to Flux. Because Dploy only exposes git/helm chart sources,
the operator always builds a HelmRelease whose chart references a GitRepository or
HelmRepository (OCI Helm registries use a HelmRepository of type oci). The
HelmRelease and its source live in the instance’s own namespace (so owner references are
valid) and install into the per-instance workload namespace via targetNamespace.
OIDC provider
Section titled “OIDC provider”External identity provider (Authentik, Keycloak, Dex, …) that issues JWTs and exposes a JWKS endpoint. See OIDC Providers.
The RBAC boundary
Section titled “The RBAC boundary”The operator/API split is enforced by two service accounts:
| Identity | Can do |
|---|---|
API (namespaced Role) | read dploytemplates; CRUD dployinstances — nothing else |
Operator (ClusterRole) | CRUD dploy CRs + status/finalizers, helmreleases, Flux sources, namespaces, events |
Only the operator can reach Flux. This makes the trust boundary auditable: a compromised API can at most create instance requests, never arbitrary workloads.
Instance lifecycle
Section titled “Instance lifecycle”TTL anchoring
Section titled “TTL anchoring”spec.expiresAtset by the API is authoritative (used at creation and on/extend).- Otherwise, when an instance first becomes active the operator anchors expiry at
now + ttlSeconds. ttlSeconds: -1means unlimited.- An unclaimed pool member never expires — its clock starts when a user claims it.
Teardown
Section titled “Teardown”DployInstance carries a finalizer (dploy.dev/instance-cleanup). On deletion the operator
removes the HelmRelease (waiting for Flux to finish the Helm uninstall), then deletes the
workload namespace. The Flux source is owner-referenced and garbage-collected.
Labels & annotations
Section titled “Labels & annotations”labels: dploy.dev/managed: "true" dploy.dev/owner: "john-doe" # sanitized owner dploy.dev/template: "webterm" # source template dploy.dev/instance: "a1b2c3d4" # short UUID dploy.dev/pooled: "true" # warm-pool members onlyannotations: dploy.dev/extend-count: "2" # API-managed TTL extension counterValue & URL templating
Section titled “Value & URL templating”Both valuesTemplate and connectionURLTemplate are rendered with Go text/template + sprig.
The data context exposes:
| Field | Description |
|---|---|
.Owner | sanitized owner (empty for unclaimed pool members) |
.UUID | immutable short UUID |
.BaseDomain | OperatorConfig.baseDomain |
.Host | <name>-<uuid>.<baseDomain> |
.URL | resolved connection URL (available to valuesTemplate) |
.Namespace | workload namespace |
.Template | the DployTemplate object |
.Params | request parameters |
.Claims | the requester’s JWT claims |
.Config.Values | OperatorConfig.spec.values |
The rendered values YAML is converted to JSON and set as the HelmRelease’s spec.values.
Authentication flow
Section titled “Authentication flow”Scalability & HA
Section titled “Scalability & HA”- The API is stateless — scale it horizontally behind a load balancer.
- The operator runs a single active replica by default; set
operator.leaderElection=trueto run more than one safely. - All deployment heavy-lifting (sync, health, retries) is handled by Flux’s controllers.