Kubernetes¶
This page is about building and testing the charts. To install the platform on a cluster, see
Install on Kubernetes. Lessons from building it are in
dev/kubernetes/LESSONS.md.
The Helm chart in deploy/helm/iceberg-data-platform runs the same images as Compose. Extension
charts live in their own folders (extensions/<id>/deploy/helm/iceberg-<id>) and are versioned and
released with the extension.
How the chart maps Compose¶
| Compose | Chart |
|---|---|
Services on iceberg-platform_default |
Services with the same names in the release namespace, so http://keycloak:8080 and the Bridge aliases stay valid |
scripts.setup writes .env |
The Secret iceberg-platform, generated once with Helm's lookup and kept |
scripts.setup writes the realm import |
An init container runs scripts.setup --realm-json in the portal image |
keycloak start-dev with its own database |
keycloak start on Postgres (database keycloak) |
The postgres service |
The bundled StatefulSet, or postgres.external: no pod, and Polaris, Keycloak and the monitor connect to your server with sslmode (test/test_helm_chart.py renders both) |
polaris-bootstrap |
An init container of the Polaris pod, or with polaris.external (the official Apache Polaris chart) a hook Job before the Keycloak bootstrap. The official chart's values are rendered to the ConfigMap iceberg-polaris-values; POLARIS=official sh dev/kubernetes/kind_check.sh tests that path |
keycloak-bootstrap on every up |
A post-install and post-upgrade hook Job |
.env.bridge per extension |
The Secret iceberg-bridge-<id>, from the extensions value |
Docker socket in users, monitor and the launchers |
The backends below |
Backends¶
Every Docker-specific part has a switch whose default is Docker, so Compose behaves as before:
- Notebooks:
NOTEBOOK_BACKEND=docker|kubernetes|none.user_portal/runtime_kubernetes.pystarts one pod per session inNOTEBOOK_NAMESPACE. The team's storage is a ReadWriteOnce PVC, so sessions of one team and environment share a node (pod affinity). The portal proxies to the pod IP, which keeps the token endpoint's address check. - Monitor:
MONITOR_BACKEND=kuberneteslists the pods ofMONITOR_NAMESPACESand theirmetrics.k8s.iousage. It runs next to RustFS, which lets it mount the RustFS volume read-only. - dbt and Ingestion launchers:
LAUNCHER_BACKEND=kubernetesruns one Job per run inRUNS_NAMESPACE. The runner (runner/remote.py) fetches its staged/workfromGET /jobs/{id}/inputand returnsout/withPUT /jobs/{id}/output, using a ticket that is valid for one run (see the dbt extension'sDECISIONS.md). The launcher is a second container in the portal pod, so both share the artifacts volume. Only that container gets a service account token.
server/kube.py is the small API client the core uses. The extensions have their own copy in
launcher/kube.py, because they never import platform code.
Test on kind¶
The CI job kubernetes does this on every change:
sh dev/kubernetes/tools.sh .local/bin && export PATH="$PWD/.local/bin:$PATH"
kind create cluster
docker build -t local/iceberg-data-platform-portal:dev .
docker build -t local/iceberg-data-platform-users:dev -f user_portal/Dockerfile .
docker build -t local/iceberg-data-platform-notebook:dev -f user_portal/notebook/Dockerfile .
for image in portal users notebook; do kind load docker-image local/iceberg-data-platform-$image:dev; done
helm install iceberg deploy/helm/iceberg-data-platform -n iceberg --create-namespace \
-f deploy/helm/iceberg-data-platform/values-localhost.yaml \
--set image.registry=local --set image.tag=dev --set image.pullPolicy=Never --wait --timeout 15m
Port-forward the Services to the Compose ports, write .env with
python3 dev/kubernetes/local_env.py iceberg > .env, and the smoke tests run unchanged.
dev/kubernetes/notebook_check.py checks what a notebook pod can and cannot reach.
Test on a cloud cluster¶
dev/kubernetes/scaleway.py creates a Scaleway Kapsule cluster with Traefik and cert-manager, pushes
the working tree's images to a private registry, installs the chart on <ip>.sslip.io hostnames and
checks the routed and refused paths. It reads the API key from scaleway.env (git-ignored). Run
scaleway.py down after every session; status shows what is still running. down asks whether to
keep the reserved IP, so the next cluster gets the same hostnames; without a terminal it keeps it, and
--release-ip releases it without asking.