SentrySentry
Deploy

Deploy on Kubernetes

Kubernetes manifests, Kustomize and the inline edge sidecar

Deploy on Kubernetes

The manifests live in deploy/k8s/, all in the dedicated sentry namespace:

ManifestContents
namespace.yamlsentry namespace (Pod Security baseline)
configmap.yamlnon-secret sentry.toml (packs + nginx source)
secret.yamlsentry-secrets (cf-token, cf-zone, llm-key, pg-password)
postgres.yamlPostgres 16 StatefulSet + 10Gi PVC + Service
sentry.yamldaemon Deployment + Service 8080
pdb.yamlPodDisruptionBudget (minAvailable: 1)
kustomization.yamlapplies all of the above at once
edge-sidecar.yamlseparate example: inline edge as a sidecar to your app

Apply the manifests

kubectl apply -k deploy/k8s/    # via Kustomize (recommended)
kubectl apply -f deploy/k8s/    # or file by file

Verify the deploy

The namespace is sentry — pass -n on every command:

kubectl get pods -n sentry
kubectl logs -f deployment/sentry -n sentry
kubectl describe pod -n sentry -l app=sentry

The Deployment has a sentry config validate liveness probe — a pod with an invalid config restarts with the error visible in kubectl logs.

Secrets

Secrets (Cloudflare tokens, LLM key, Postgres password) live in secret.yaml (sentry-secrets) — fill in real values before applying:

kubectl create secret generic sentry-secrets -n sentry \
    --from-literal=cf-token=$SENTRY_CF_TOKEN \
    --from-literal=cf-zone=$SENTRY_CF_ZONE \
    --from-literal=llm-key=$SENTRY_LLM_KEY \
    --from-literal=pg-password=$SENTRY_PG_PASSWORD

The Deployment consumes them via valueFrom: secretKeyRef (cf-token, cf-zone, llm-key); Postgres consumes pg-password.

Postgres

postgres.yaml runs a postgres:16-alpine StatefulSet with a 10Gi PVC and the postgres.sentry.svc.cluster.local:5432 Service. For production, a managed Postgres (Cloud SQL, RDS, …) works too: point SENTRY_STORAGE__POSTGRES__URL at it and drop the StatefulSet from the kustomization.

Inline edge as a sidecar

edge-sidecar.yaml shows the inline topology (sentry-edge): the sentry-edge container runs with [deployment] mode = "inline", owns the Service's public port ([edge] listen = "0.0.0.0:80") and forwards to the application on 127.0.0.1:8080 — the app port is never exposed. Same binary as the daemon, different command/config:

kubectl apply -f deploy/k8s/edge-sidecar.yaml

For TLS 443 on the sidecar, use an image built with the edge-tls feature and set [edge] tls_cert/tls_key/tls_listen (JA3/JA4 telemetry included).

Horizontal scaling

Shared state lives in Postgres: rules and blocks sync across pods via LISTEN/NOTIFY (sentry_rules_changed, sentry_blocks_changed) and duplicate events from sibling nodes are deduped by payload_hash inside the 10s window (F4.7). Documented limitations: behavioral trackers (scan/behavior/offender) and the in-memory rate limiter are per-node — for shared counters use the Redis backend ([rate_limit] backend = "redis" + the rate-redis feature).

kubectl scale deployment/sentry -n sentry --replicas=3

On multi-node setups, give each pod a distinct instance_id ([deployment] instance_id) for the sentry_instance_info{instance} gauge.

Update the configuration

Edit the ConfigMap and restart the deployment (DB-managed rules hot-reload via NOTIFY, no restart needed):

kubectl edit configmap sentry-config -n sentry
kubectl rollout restart deployment/sentry -n sentry

On this page