Skip to content

Quickstart

This guide gets you to a running runtime stack on a local kind cluster and confirms that the tenant pod lifecycle and health endpoint work correctly.

  • kind v0.23+ and kubectl installed
  • Docker running
  • Helm 3.14+
  • Go 1.22+ (for the smoke assertion step)
Terminal window
kind create cluster --name pb-local
kubectl cluster-info --context kind-pb-local
Terminal window
kubectl create namespace paper-board

Runtime’s router verifies JWTs via identity.AuthService. For local testing, you can skip JWT verification by setting IDENTITY_GRPC_ADDR to a no-op stub, or install the identity Helm chart first:

Terminal window
# Option A: install identity (full stack)
helm upgrade --install identity oci://ghcr.io/paper-board/charts/identity \
--namespace paper-board \
--set server.config.env=dev
# Option B: point router at a stub addr (router will return 401 for all requests
# but the controller + pod lifecycle still works for smoke testing)
Terminal window
helm upgrade --install runtime oci://ghcr.io/paper-board/charts/runtime \
--namespace paper-board \
--set router.config.env=dev \
--set controller.config.env=dev \
--wait

This deploys three workloads: runtime-server (the gRPC server running inside each tenant pod), runtime-controller (lifecycle manager), and runtime-router (HTTP→gRPC proxy).

Confirm all pods are running:

Terminal window
kubectl get pods -n paper-board -l app.kubernetes.io/name=runtime

Expected output (names will vary by suffix):

NAME READY STATUS RESTARTS AGE
runtime-controller-XXXXXXX-XXXXX 1/1 Running 0 30s
runtime-router-XXXXXXX-XXXXX 1/1 Running 0 30s

Port-forward the router:

Terminal window
kubectl port-forward -n paper-board svc/runtime-router 8080:8080

In a second terminal, send a request. Replace <JWT> with a valid identity JWT (or skip if using the stub):

Terminal window
curl -s -X POST http://localhost:8080/v1/sessions/test-session-1/invoke \
-H "Authorization: Bearer <JWT>" \
-H "X-Request-Id: req-001" \
-H "Content-Type: application/json" \
-d '{}'

The router calls EnsureReady and creates the tenant pod. You will see an SSE stream or a 503 Service Unavailable (if identity is not installed or the JWT is invalid).

Terminal window
kubectl get deployments -n paper-board -l runtime.paper-board.io/tenant=true

Expected output shows one Deployment per unique tenant short-id:

NAME READY UP-TO-DATE AVAILABLE AGE
runtime-t-a1b7558f 1/1 1 1 15s

7. Exec into the tenant pod and assert the health endpoint

Section titled “7. Exec into the tenant pod and assert the health endpoint”
Terminal window
# Get the pod name for the tenant Deployment
POD=$(kubectl get pod -n paper-board -l app=runtime-t-a1b7558f \
-o jsonpath='{.items[0].metadata.name}')
# Call the gRPC health check from inside the pod
kubectl exec -n paper-board "$POD" -- \
/usr/local/bin/grpc_health_probe -addr=localhost:50051

Expected output:

status: SERVING

If grpc_health_probe is not available in the image, use a raw TCP check:

Terminal window
kubectl exec -n paper-board "$POD" -- sh -c \
'echo "health check" && nc -zv localhost 50051 && echo "port open"'

The pod’s env vars confirm which tenant it serves:

Terminal window
kubectl exec -n paper-board "$POD" -- env | grep -E '^(TENANT_ID|ORG_ID)='

Expected output:

TENANT_ID=<tenant-uuid>
ORG_ID=<org-uuid>

9. Confirm the last-seen-at annotation is updated

Section titled “9. Confirm the last-seen-at annotation is updated”

After the request in step 5, the Deployment annotation should carry a recent timestamp:

Terminal window
kubectl get deployment -n paper-board runtime-t-a1b7558f \
-o jsonpath='{.metadata.annotations.runtime\.paper-board\.io/last-seen-at}'
  • See api-reference.md for the full runtime.v1.RuntimeService gRPC contract.
  • See operations.md for Helm values, env var reference, and the controller deployment model.