Kubernetes Deployment Configuration#
Sequin is deployed on Kubernetes via an official Helm chart. Two categories of problems are worth knowing about before deploying or debugging: env var collisions from Kubernetes service-link injection and boot-crashing env var validation in config/runtime.exs.
Helm Chart: Service-Link Env Var Collisions#
Kubernetes injects Docker-style service-link environment variables for every Service in the pod's namespace. A Service named sequin-metrics produces:
SEQUIN_METRICS_PORT=tcp://10.x.x.x:8376
This shadows Sequin's own SEQUIN_METRICS_PORT config. In config/runtime.exs, that variable is parsed with String.to_integer/1:
metrics_port = String.to_integer(System.get_env("SEQUIN_METRICS_PORT") || "8376")
tcp://10.x.x.x:8376 is not an integer β boot raises β pod enters CrashLoopBackOff. The failure is hard to diagnose because the injected value does not appear in the user's own configuration.
This is reachable through the official chart itself. The chart's metrics Service is named sequin-metrics , so enabling the chart's built-in metrics Service is sufficient to trigger the crash .
Fixes / Workarounds#
| Option | Details |
|---|---|
enableServiceLinks: false (recommended) | Add to the pod spec in values.yaml (via extraEnvVars or a chart override). Prevents the entire class of Service-name collisions. One-line fix. |
| Rename your metrics Service | Use a name that doesn't start with sequin-metrics (e.g., sequin-scrape). Kubernetes will inject SEQUIN_SCRAPE_* vars, which Sequin does not read. |
| Disable the chart's metrics Service | Set metrics.service.enabled: false in values.yaml if you don't need Prometheus scraping. |
See the issue report for full reproduction steps and rationale.
Boot-Crashing Env Var Validation#
config/runtime.exs and Sequin.ConfigParser validate several env vars at startup. Invalid values raise ArgumentError and crash the BEAM before the app starts. This affects self-hosted deployments running in :prod mode.
Variables that crash on bad input#
| Env Var | Problem | Source |
|---|---|---|
SEQUIN_METRICS_PORT | Non-integer value β String.to_integer crash | |
PG_POOL_SIZE | Non-integer value | |
LONG_POLL_FALLBACK_MS | Non-integer value | |
HTTP_POOL_COUNT | Non-integer value | |
HTTP_POOL_SIZE | Non-integer value (only crashes when explicitly set) | |
SERVER_CHECK_ORIGIN | Any value other than true, 1, false, 0 | |
SECRET_KEY_BASE | Missing or fewer than 64 bytes | |
VAULT_KEY | Missing, fewer than 32 bytes, or invalid base64 | |
DEFAULT_WORKERS_PER_SINK | Non-integer or value < 1 | |
REDIS_POOL_SIZE | Non-positive integer | |
REDIS_TLS | Any value outside true, 1, verify-none, false, 0 | |
REDIS_TLS_VERIFY | Any value other than verify-peer or verify-none | |
REDIS_TLS_*_FILE | Path does not exist on disk | |
PG_URL (absent) | All individual PG_* vars must be set if PG_URL is missing |
Note on
LOG_LEVEL: Invalid log level values do not crash βConfigParser.log_level/2falls back to the default with a warning .
Debugging strategy#
When a pod crash-loops and the error isn't obvious in your own config:
- Check whether any Kubernetes Service in the namespace could be injecting env vars that shadow Sequin's expected vars.
- Inspect the pod logs before it exits β Elixir prints the
ArgumentErrormessage and the specific var name. - Use
kubectl execwithenvto see what the pod actually receives.
Key Files#
| File | Purpose |
|---|---|
config/runtime.exs | Runtime env var reading and validation β the primary crash site |
lib/sequin/config_parser.ex | Shared validation helpers (secret_key_base, vault_key, redis_config, etc.) |
templates/deployment.yaml | Helm chart deployment template β env vars injected into the container |
values.yaml | Helm chart values β metrics.service.*, extraEnvVars, pool sizes |