Run it on Kubernetes
Install Pistis on any Kubernetes cluster with the Helm chart.
The Helm chart in deploy/helm/pistis installs Pistis on any Kubernetes cluster. It needs container images, a Postgres database, a TLS proxy and a place to run pods.
Before you start
- A Kubernetes cluster whose network plugin enforces NetworkPolicy, such as Calico, Cilium or the AWS VPC CNI with network policy on
- A Postgres 14 or newer database
- Nodes that can pull from
ghcr.io, or a registry of your own with Pistis's images copied to it - Optional: a sandbox runtime such as gVisor or Kata for extra isolation
Install
- Install the chart:
helm install pistis deploy/helm/pistis \
--set publicUrl=https://pistis.example.com \
--set database.url='postgres://pistis:…@db.example.com:5432/pistis' \
--set sandboxes.runtimeClassName=gvisor \
--set ingress.enabled=true --set ingress.className=alb --set ingress.host=pistis.example.com- Find the setup link and open it:
kubectl logs statefulset/pistis-brain | grep "setup link"The chart runs the release's images from ghcr.io/akshay5995, tagged with the chart's version. image.registry points it at your own registry, image.tag at another release, and image.pistis, image.relay or image.pistisd names one image outright, such as a sandbox image of your own. With image.pullPolicy=Never it runs images you built with pnpm images and loaded onto the nodes yourself (pistis/<name>:dev).
Pass model keys with env or envFrom. Anything else pistis.json takes goes under config.
The chart creates its keys at install and keeps them across upgrades. GitOps tools and helm template can't read the cluster, so with those, provide your own Secret with secrets.existingSecret.
What the chart sets up
- Two Pistis servers that share every session, and the
relayservice sandboxes connect to. - Sandbox pods in their own namespace,
<release>-boxes. The Pistis servers may manage pods there, and have no rights in the namespace that holds your keys. - Locked-down sandbox pods: no service-account token, no privilege escalation, the default seccomp profile and your runtime class.
- A NetworkPolicy: sandboxes accept no connections and reach only Pistis and the cluster's DNS. With
sandboxes.egress=openthey also reach the internet, but never private address ranges. - An optional Ingress. Block
/internal/*on it; Pistis servers talk to each other inside the cluster.
Tested on kind, a local Kubernetes (a brain is a Pistis server): helm install on kind: 2 brains + relay running against an external Postgres. A session ran in a sandbox pod and opened a pull request, and the pod was checked: no SA token, no privilege escalation, Secret-backed join token; NetworkPolicy: no ingress, egress relay:8080 and DNS only.
The same setup on other clouds
| AWS | Google Cloud | Azure | |
|---|---|---|---|
| Kubernetes | EKS | GKE | AKS |
| Postgres | RDS or Aurora | Cloud SQL | Azure Database for PostgreSQL |
| TLS | ALB and ACM | GKE Ingress and managed certificates | Application Gateway |
| Sandbox runtime | gVisor node group | GKE Sandbox (gVisor) | Kata (Pod Sandboxing) |
| Images | ECR | Artifact Registry | ACR |
On your own hardware, k3s or kubeadm with gVisor or Kata works the same way. No Kubernetes? Use the compose file.
Troubleshooting
- Pods never start on a nested or rootless host, and runc reports
can't get final child's PID from pipe. Set containerd'srestrict_oom_score_adj = true. With kind, add it as acontainerdConfigPatchesentry. - Upgrading from a chart that ran sandboxes in the release namespace. Delete the old ones:
kubectl delete pod,secret,networkpolicy -n <release-ns> -l app.kubernetes.io/managed-by=pistis.