kubepath

Reference

The stack, condensed.

Every layer, with the consequence that matters and a link to where it sits on the path. Violet layers are the ones whose shape traces back to having no cloud load balancer.

Cluster

Scaleway Kapsule, pl-waw, one worker node, managed control plane

One node is the reason for gVisor, for shared databases, and for the availability ceiling. hop 1 →

Ingress

Traefik v3 (chart 41.0.2), DaemonSet, hostPort 80/443, service.enabled: false

The load-bearing choice. No Service exists for the ingress controller. hop 2 →

TLS

cert-manager v1.21.0, one letsencrypt-prod ClusterIssuer, HTTP-01 only

HTTP-01 only means no wildcards, and means the renewal path is the serving path. hop 3 →

Config

Kustomize, one dir per app, digest-pinned images — no Argo/Flux, no reconciler

No drift detection. Finding #1 is what that costs. hop 10 →

Tenant DB

CloudNativePG 0.29.0, shared clusters, ~100 tenant DBs each

Isolation here is Postgres grants, not a kernel. PITR restores 100 tenants at once. hop 7 →

Analytics

ClickHouse StatefulSet, shared, 500 DBs each

Same shared-cluster trade, one order of magnitude denser. hop 7 →

Forge

Forgejo 17.1.3 in-cluster, SSH on node port 2222 + smart-HTTP through the API

:2222 because :22 is the node’s sshd and there is no second address to give git. hop 8 →

Sandbox

gVisor via installer DaemonSet + RuntimeClass, for all user code

Opt-in per pod. Omit runtimeClassName and you get runc, with no warning. hop 6 →

Builds

BuildKit rootless/daemonless in a Job, no ServiceAccount token, backoffLimit: 0

A Dockerfile is a tenant’s program. The Job is built so running it grants nothing. hop 9 →

← The path