Kubernetes (Helm)
The rikoo Helm chart deploys the api, the worker, the parsing sidecar and the tool sandbox on a
cluster, with PostgreSQL, Redis and object storage either bundled or pointed at managed services.
Schema migrations run as a Job at install time and before every upgrade.
The chart lives in a public repository, Rikoo-app/rikoo-k8s,
under the MIT license. The container images it deploys are in a private registry: you need the
registry address and credentials from the Rikoo team (see Overview).
Prerequisites
- Kubernetes 1.27 or later, and Helm 3.14 or later.
- A network plugin that enforces NetworkPolicies, such as Cilium or Calico. The sandbox relies on them to cut its network; see Sandbox isolation.
- A default StorageClass, if you keep the bundled stores: they claim 20 GiB for PostgreSQL, 8 GiB for Redis and 50 GiB for MinIO.
- For a public address: an ingress controller and cert-manager, or equivalents.
- Capacity: with the default values, the pods request about 2.2 vCPU and 4 GiB of memory, with memory limits adding up to about 11 GiB.
Install
The steps follow the examples/minimal-installation folder of the chart repository: every store
bundled, all credentials in one Secret created beforehand.
1. Get the chart
git clone https://github.com/Rikoo-app/rikoo-k8s.git
cd rikoo-k8s/examples/minimal-installation
helm dependency update ../../charts/rikoo
2. Create the namespace and the registry secret
kubectl create namespace rikoo
kubectl -n rikoo create secret docker-registry rikoo-registry \
--docker-server=<registry> --docker-username=<user> --docker-password=<token>
3. Create the application secret
Generate the vault's sealing key pair. The chart never generates it, and losing the private key makes every stored secret unreadable.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:3072 -out sealing.private
openssl pkey -in sealing.private -pubout -out sealing.public
Then edit secret.yaml and replace every placeholder:
| Key | Value |
|---|---|
widget-signing-key, totp-key, sandbox-token-secret | Random strings of at least 32 characters, for example from openssl rand -hex 24 |
sealing.pub, sealing.key | The contents of sealing.public and sealing.private |
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB | Credentials of the bundled PostgreSQL |
rootUser, rootPassword | Credentials of the bundled MinIO |
kubectl -n rikoo apply -f secret.yaml
In a GitOps pipeline, produce this Secret with an external secrets operator rather than committing it.
4. Install the chart
helm install rikoo ../../charts/rikoo -n rikoo -f values.yaml \
--set rikoo.image.registry=<registry>/<namespace> \
--set rikoo.image.tag=v0.2.0
Both rikoo.image.registry and rikoo.image.tag are required; the chart refuses to render
without them.
5. Check
kubectl -n rikoo get pods
kubectl -n rikoo port-forward svc/rikoo-api 3000:http
curl -fsS http://localhost:3000/api/v1/health
Open http://localhost:3000 and create the first account: while no organization exists, it may
register and becomes Owner of the first organization.
Expose it
The with-ingress.yaml overlay of the same folder adds an ingress with TLS, assuming ingress-nginx,
cert-manager and a ClusterIssuer named letsencrypt. Replace its example hosts,
rikoo.example.com and s3.rikoo.example.com, with yours. The overlay also:
- sets
rikoo.publicUrlto the public address andrikoo.trustProxyHopsto1, since the ingress controller is one proxy in front of the api; - gives the bundled MinIO a public route, because browsers upload attachments straight to object
storage at the address in
s3.browserEndpoint; - turns proxy buffering off and raises timeouts to one hour: answers stream as server-sent events. With another ingress controller, apply the same settings.
helm upgrade --install rikoo ../../charts/rikoo -n rikoo \
-f values.yaml -f with-ingress.yaml \
--set rikoo.image.registry=<registry>/<namespace> --set rikoo.image.tag=v0.2.0
Use managed stores
Each bundled store can be replaced by a managed service. The examples/external-components folder
has one overlay per store.
| Store | Values | Requirements |
|---|---|---|
| PostgreSQL | postgresql.deploy: false, then postgresql.url, or host, port and auth.* | The vector (pgvector) and citext extensions. The migrating role must be allowed to create extensions and roles. |
| Redis | redis.deploy: false, then redis.url, or host, port and database | maxmemory-policy noeviction: evicting a key loses queued jobs. |
| Object storage | s3.deploy: false, then endpoint, browserEndpoint, region, bucket, forcePathStyle and the key pair | Any S3-compatible service. |
To make PostgreSQL row-level security filter tenant queries, give the application a second,
non-owner role through postgresql.appUrl. Without it, tenant queries use the owner connection.
Configure
The chart sets what it can from its own values. Any other product setting goes into a checked map:
rikoo.settings (read by the api and the worker), rikoo.api.settings or rikoo.worker.settings.
The chart checks each name against the list of variables the product reads, and refuses to render a
name the product does not know, a secret written in clear, or a value in the wrong format.
The complete list of variables, with their format and the service that reads them, is in
charts/rikoo/VARIABLES.md.
Enterprise edition
Deploy Enterprise images (ask for the tag with your license), then store the license in a Secret
and point rikoo.license.deploymentLicense at it:
kubectl -n rikoo create secret generic rikoo-license \
--from-literal=RIKOO_DEPLOYMENT_LICENSE='<license>'
rikoo:
license:
deploymentLicense:
secretKeyRef:
name: rikoo-license
key: RIKOO_DEPLOYMENT_LICENSE
See Enterprise license for what the license unlocks.
Sandbox isolation
The embedded tools run in the mcp-sandbox pods, confined by three NetworkPolicies: the workspace
reaches only the browser, the browser leaves only through the mcp-egress proxy, which applies the
same anti-SSRF guard as the worker, and the api reaches none of them. The workspace container drops
every capability except the four it needs to switch to the conversation's system identity (SETUID,
SETGID, CHOWN, DAC_OVERRIDE), with a read-only root filesystem and the RuntimeDefault
seccomp profile.
Policies are only enforced by a network plugin that supports them. On a cluster without one, the
sandbox workspace can reach the network: install such a plugin, or turn the sandbox off with
rikoo.sandbox.enabled: false. Runs keep working without it; the embedded tools return an error.
The Docker Compose stack adds a dedicated seccomp profile and supports gVisor; the chart does not offer either yet.
Upgrade
Back up the database, then run the same command with the new tag:
helm upgrade --install rikoo ../../charts/rikoo -n rikoo -f values.yaml \
--set rikoo.image.registry=<registry>/<namespace> --set rikoo.image.tag=<new tag>
The migrations Job runs before the new pods. If it fails, the release does not roll out: read
kubectl -n rikoo logs job/rikoo-migrations. helm rollback returns to the previous images but
does not reverse migrations; restore the database backup when a release has to be undone.
Uninstall
helm uninstall rikoo -n rikoo
The chart keeps what cannot be recreated: its Secrets are marked helm.sh/resource-policy: keep,
and the bundled PostgreSQL volume is retained. Delete them by hand, with the namespace, only when
you mean to lose the data.
Try it on a laptop
The examples/local-kind folder runs the chart on a local kind
cluster, with images built from the Rikoo source repository. Its README walks through the steps and
includes a check that the sandbox network is really cut.