Skip to content

Kubernetes and Helm

Precept ships a Helm chart that deploys:

  1. init-db — create application Postgres user and database (post-install hook, after bundled Postgres is up)
  2. migrationsyarn node-pg-migrate … up against DATABASE_URL (post-install hook)
  3. serverghcr.io/precept-sh/server on port 8080 with /health probes
  4. workernode dist/temporal/worker.mjs with PRECEPT_BASE_URL pointing 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+
  • kubectl configured 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

sh
helm dependency update deploy/helm/precept-server

2. 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).

sh
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_TOKEN

5. Install

sh
helm upgrade --install mypreview deploy/helm/precept-server \
  --namespace precept \
  -f deploy/helm/precept-server/values-local.yaml \
  --timeout 15m

If a previous install failed, uninstall before retrying: helm uninstall mypreview -n precept.

6. Access the server

sh
kubectl -n precept port-forward svc/mypreview-server 8080:8080
curl http://127.0.0.1:8080/health

Open http://127.0.0.1:8080 and sign in with Auth0 (settings in values-local.yaml).

7. Verify

sh
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=50

See also the chart README.

Production deployment (OCI chart)

Docker registry credentials

sh
helm registry login ghcr.io -u precept-docker -p <TOKEN>
helm show chart oci://ghcr.io/precept-sh/helm/precept-server
sh
kubectl -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:

yaml
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>"
sh
helm install <release> oci://ghcr.io/precept-sh/helm/precept-server \
  --namespace <NAMESPACE> \
  --values precept-values.yaml

The 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:

sh
kubectl -n <NAMESPACE> get deployments,pods,jobs

NetworkPolicy

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.