Kubernetes and Helm
Precept ships a Helm chart that deploys:
- init-db — create application Postgres user and database (post-install hook, after bundled Postgres is up)
- migrations —
yarn node-pg-migrate … upagainstDATABASE_URL(post-install hook) - server —
ghcr.io/precept-sh/serveron port 8080 with/healthprobes - worker —
node dist/temporal/worker.mjswithPRECEPT_BASE_URLpointing at the server Service
Cloud preview environments use shared Postgres and Temporal hosts. values-local.yaml bundles both so a local cluster is functionally equivalent to Docker Compose.
Prerequisites
- Kubernetes 1.23+
kubectlconfigured for your cluster- Helm 3.0+
- Docker (to pull the server image from GHCR)
For local installs use kind, minikube, or Docker Desktop Kubernetes with the chart from this repository (not the published OCI chart).
For production installs you also need a Docker registry token (issued by the Precept team) to pull private images and the published OCI chart.
Local development (in-cluster)
values-local.yaml enables bundled PostgreSQL and Temporal, localDev (JWE secret mount), Auth0 settings aligned with Docker Compose, and PRECEPT_MODULE_PATHS for bundled official modules.
Hook order: credentials Secret (pre-install) → bundled Postgres/Temporal (main chart) → init-db Job (post-install, weight -2) → migrate Job (post-install, weight -1) → server and worker Deployments.
1. Chart dependencies
helm dependency update deploy/helm/precept-server2. Server image
Set image.tag in values-local.yaml to a published GHCR server tag, or use latest with a valid pull secret. Both linux/amd64 and linux/arm64 are published.
The migrate Job uses the same server image as the API.
3. Configure values
values-local.yaml already sets nameOverride: server (Service name <release>-server). Set credentials.env.PRECEPT_TASK_QUEUE to <release>.dev to match your Helm release name (default example: mypreview.dev).
4. GHCR pull secret
ghcr.io/precept-sh/server is private. Create the secret referenced by values-local.yaml (ghcr-credentials) even when using a locally loaded image — the chart lists imagePullSecrets and Kubernetes requires the Secret to exist.
Use your GitHub username and a personal access token with read:packages (not your GitHub password). On Docker Desktop, create the secret with kubectl as below; do not copy ~/.docker/config.json when it uses credsStore (the cluster secret may end up with empty credentials).
kubectl create namespace precept
read -rs GHCR_TOKEN && echo
kubectl -n precept create secret docker-registry ghcr-credentials \
--docker-server=ghcr.io \
--docker-username=<your-github-username> \
--docker-password="${GHCR_TOKEN}" \
--dry-run=client -o yaml | kubectl apply -f -
unset GHCR_TOKEN5. Install
helm upgrade --install mypreview deploy/helm/precept-server \
--namespace precept \
-f deploy/helm/precept-server/values-local.yaml \
--timeout 15mIf a previous install failed, uninstall before retrying: helm uninstall mypreview -n precept.
6. Access the server
kubectl -n precept port-forward svc/mypreview-server 8080:8080
curl http://127.0.0.1:8080/healthOpen http://127.0.0.1:8080 and sign in with Auth0 (settings in values-local.yaml).
7. Verify
kubectl -n precept get pods,jobs
kubectl -n precept logs job/mypreview-init-db --tail=50
kubectl -n precept logs job/mypreview-migrate --tail=50
kubectl -n precept logs deployment/mypreview-server --tail=50See also the chart README.
Production deployment (OCI chart)
Docker registry credentials
helm registry login ghcr.io -u precept-docker -p <TOKEN>
helm show chart oci://ghcr.io/precept-sh/helm/precept-serverkubectl -n <NAMESPACE> create secret docker-registry precept \
--docker-server=ghcr.io \
--docker-username=precept-docker \
--docker-password=<TOKEN>Install against external Postgres
Disable bundled PostgreSQL, enable init-db, and point at your admin host:
nameOverride: server
postgresql:
enabled: false
initDb:
enabled: true
database:
host: <postgres-host>
sslMode: require
adminExistingSecret: <admin-credentials-secret>
credentials:
create: true
postgresPassword: <app-password>
env:
PRECEPT_HTTP_BASE_URL: https://<preview>.dev.precept.sh
PRECEPT_TASK_QUEUE: <preview>.dev
imagePullSecrets:
- name: precept
image:
tag: "<version>"helm install <release> oci://ghcr.io/precept-sh/helm/precept-server \
--namespace <NAMESPACE> \
--values precept-values.yamlThe chart sets PRECEPT_STORAGE_CONNECTION and DATABASE_URL from the credentials Secret (sslmode=require by default). The worker receives PRECEPT_BASE_URL (<release>-server:8080) and, when temporal.enabled is true, TEMPORAL_HOST pointing at the bundled Temporal frontend.
For production-style installs (external shared Postgres and Temporal, as in cloud previews), set postgresql.enabled: false, temporal.enabled: false, and provide database.host, temporal.address, and connection credentials explicitly.
See Helm Chart Values for all options.
Verifying installation
The server pod has three probes, all targeting GET /health on port 8080:
- Startup probe — checks every 10 seconds for up to 5 minutes. Liveness and readiness do not begin until this passes, preventing restarts during slow cold starts.
- Liveness probe — checks every 60 seconds once the pod is started. Failure triggers a pod restart.
- Readiness probe — checks every 15 seconds. Failure removes the pod from the Service endpoints until it recovers.
Check deployment status:
kubectl -n <NAMESPACE> get deployments,pods,jobsNetworkPolicy
NetworkPolicy resources are included in the chart but disabled by default (networkPolicy.enabled: false). Enabling them requires a CNI plugin that enforces NetworkPolicy — such as Calico or Cilium. Clusters using Flannel (including the default k3s and kind setups) do not enforce NetworkPolicy and the resources will have no effect. See Helm Chart Values for configuration options.