Kubernetes
Deploy MPCKit to Kubernetes with Kustomize overlays per network.
The repo ships Kustomize manifests under infra/k8s/ with a base/
that defines every Deployment, Service, and Ingress, and per-network
overlays under overlays/testnet/ and overlays/mainnet/. CI builds
and pushes container images to ghcr.io/dwallet-labs/mpckit-{backend,dashboard,docs};
deploys apply the overlay against your cluster.
Cluster prerequisites
- Kubernetes 1.28+.
- An ingress controller. The manifests assume
ingressClassName: nginxandcert-managerfor TLS. Swap to your controller in the overlays. - Storage class for postgres + redis volumes. The base manifests use whatever the cluster's default is.
For real production, terminate Postgres and Redis externally (managed Postgres, managed Redis) and remove the in-cluster StatefulSets from the overlay. The base ships in-cluster so the manifests are runnable as-is for evaluation.
Layout
infra/k8s/
base/
backend.yaml # api + worker (PROCESS_TYPE=both)
dashboard.yaml
docs.yaml
postgres.yaml
redis.yaml
gas-station.yaml
ingress.yaml
kustomization.yaml
overlays/
testnet/
kustomization.yaml # IKA_NETWORK=testnet + testnet image tag
env.yaml # ConfigMap with non-secret env
secrets.example.yaml
mainnet/
...Bring it up
# 1. Create the namespace and pull-secret for ghcr.io.
kubectl create ns mpckit-testnet
kubectl -n mpckit-testnet create secret docker-registry ghcr \
--docker-server=ghcr.io \
--docker-username=<gh-user> \
--docker-password=<gh-token>
# 2. Populate the secret. Copy the example, fill in real values, apply.
cp infra/k8s/overlays/testnet/secrets.example.yaml /tmp/mpckit-secrets.yaml
$EDITOR /tmp/mpckit-secrets.yaml
kubectl -n mpckit-testnet apply -f /tmp/mpckit-secrets.yaml
rm /tmp/mpckit-secrets.yaml
# 3. Apply the overlay.
kubectl apply -k infra/k8s/overlays/testnetPer-network deployments
Each overlay produces an isolated stack. Run testnet and mainnet in separate namespaces, each with their own image tags, secrets, Treasury, and gas-station sponsor:
kubectl apply -k infra/k8s/overlays/testnet
kubectl apply -k infra/k8s/overlays/mainnetThe runtime is single-network per process, so the testnet backend Deployment must be entirely separate from the mainnet one. The overlays make this the default shape.
CI deploys
The deploy.yml workflow builds and pushes the three app images on
every push to main, then runs kubectl apply -k against each
overlay using the KUBECONFIG_<NETWORK> repository secret. See the
workflow file at .github/workflows/deploy.yml for the exact steps.
To pin a specific image tag, override newTag in the overlay's
kustomization.yaml:
images:
- name: ghcr.io/dwallet-labs/mpckit-backend
newTag: v1.2.3Ingress + TLS
The base ingress routes api.mpckit.xyz to backend, app.mpckit.xyz
to dashboard, docs.mpckit.xyz to docs. Overlays patch the host
names (e.g. api-testnet.mpckit.xyz). Replace these with your own
domain in the overlay's kustomization.yaml.
cert-manager is expected to issue TLS via the letsencrypt-prod
ClusterIssuer; swap or remove the annotation if you terminate TLS
elsewhere.
Operating
- Migrations run on backend container boot. Safe across pods — Drizzle uses an advisory lock.
- Rolling updates:
kubectl rollout restart deployment/backend -n mpckit-testnet. The backend uses graceful shutdown so in-flight requests drain before exit. - Scaling: backend is stateless beyond Postgres + Redis; bump
replicasin the Deployment. The presign-pool warmup is idempotent across replicas. - Worker isolation: the current default is
PROCESS_TYPE=bothso each pod runs the worker too. If you need to scale HTTP without scaling workers, split into two Deployments usingPROCESS_TYPE=apiandPROCESS_TYPE=worker.