|
| 1 | +--- |
| 2 | +title: "Kubernetes" |
| 3 | +description: "You can self-host Trigger.dev in Kubernetes using our official Helm chart." |
| 4 | +--- |
| 5 | + |
| 6 | +The following instructions will help you deploy Trigger.dev to Kubernetes using our official Helm chart. Make sure to read the self-hosting [overview](/self-hosting/overview) first. |
| 7 | + |
| 8 | +As self-hosted deployments tend to have unique requirements and configurations, we don't provide specific advice for securing your deployment, scaling up, or improving reliability. |
| 9 | + |
| 10 | +Should the burden ever get too much, we'd be happy to see you on [Trigger.dev cloud](https://trigger.dev/pricing) where we deal with these concerns for you. |
| 11 | + |
| 12 | +**Warning:** This guide alone is unlikely to result in a production-ready deployment. Security, scaling, and reliability concerns are not fully addressed here. |
| 13 | + |
| 14 | +## Requirements |
| 15 | + |
| 16 | +### Prerequisites |
| 17 | +- Kubernetes cluster 1.19+ |
| 18 | +- Helm 3.8+ |
| 19 | +- Kubectl configured with cluster access |
| 20 | + |
| 21 | +### Resource requirements |
| 22 | + |
| 23 | +The following are minimum requirements for running the entire Trigger.dev stack on Kubernetes: |
| 24 | + |
| 25 | +**Cluster resources:** |
| 26 | +- 6+ vCPU total |
| 27 | +- 12+ GB RAM total |
| 28 | +- Persistent volume support |
| 29 | + |
| 30 | +**Individual components:** |
| 31 | +- **Webapp**: 1 vCPU, 2 GB RAM |
| 32 | +- **Supervisor**: 1 vCPU, 1 GB RAM |
| 33 | +- **PostgreSQL**: 1 vCPU, 2 GB RAM |
| 34 | +- **Redis**: 0.5 vCPU, 1 GB RAM |
| 35 | +- **ClickHouse**: 1 vCPU, 2 GB RAM |
| 36 | +- **Object Storage**: 0.5 vCPU, 1 GB RAM |
| 37 | +- **Workers**: Depending on concurrency and machine preset |
| 38 | + |
| 39 | +These requirements scale based on your task concurrency and can be adjusted via the `resources` section in your `values.yaml`. For example: |
| 40 | + |
| 41 | +```yaml |
| 42 | +webapp: |
| 43 | + resources: |
| 44 | + requests: |
| 45 | + cpu: 500m |
| 46 | + memory: 1Gi |
| 47 | + limits: |
| 48 | + cpu: 2000m |
| 49 | + memory: 4Gi |
| 50 | +``` |
| 51 | +
|
| 52 | +## Installation |
| 53 | +
|
| 54 | +### Quick start |
| 55 | +
|
| 56 | +1. Install with default values (for testing only): |
| 57 | +
|
| 58 | +```bash |
| 59 | +helm upgrade -n trigger --install trigger \ |
| 60 | + oci://ghcr.io/triggerdotdev/charts/trigger:4.0.0-beta.3 \ |
| 61 | + --create-namespace |
| 62 | +``` |
| 63 | + |
| 64 | +2. Access the webapp: |
| 65 | + |
| 66 | +```bash |
| 67 | +kubectl port-forward svc/trigger-webapp 3040:3030 -n trigger |
| 68 | +``` |
| 69 | + |
| 70 | +3. Open the dashboard: `http://localhost:3040` |
| 71 | + |
| 72 | +## Configuration |
| 73 | + |
| 74 | +The default installation uses insecure secrets and is only suitable for testing. You _will_ need to configure your own secrets as a bare minimum. |
| 75 | + |
| 76 | +Most values map directly to the environment variables documented in the [webapp](/self-hosting/env/webapp) and [supervisor](/self-hosting/env/supervisor) environment variable overview. |
| 77 | + |
| 78 | +**Naming convention:** |
| 79 | +- Environment variables use `UPPER_SNAKE_CASE` |
| 80 | +- Helm values use `camelCase` |
| 81 | + |
| 82 | +**Example mapping:** |
| 83 | +```bash |
| 84 | +# Environment variable |
| 85 | +APP_ORIGIN=https://trigger.example.com |
| 86 | + |
| 87 | +# Becomes Helm value |
| 88 | +config: |
| 89 | + appOrigin: "https://trigger.example.com" |
| 90 | +``` |
| 91 | + |
| 92 | +### Custom values |
| 93 | + |
| 94 | +Create a `values-custom.yaml` file. For example: |
| 95 | + |
| 96 | +```yaml |
| 97 | +# Required: Generate new secrets with `openssl rand -hex 16` |
| 98 | +secrets: |
| 99 | + sessionSecret: "your-32-char-hex-secret-1" |
| 100 | + magicLinkSecret: "your-32-char-hex-secret-2" |
| 101 | + encryptionKey: "your-32-char-hex-secret-3" |
| 102 | + managedWorkerSecret: "your-32-char-hex-secret-4" |
| 103 | + |
| 104 | +# Application URLs |
| 105 | +config: |
| 106 | + appOrigin: "https://trigger.example.com" |
| 107 | + loginOrigin: "https://trigger.example.com" |
| 108 | + apiOrigin: "https://trigger.example.com" |
| 109 | + |
| 110 | +# Resource limits |
| 111 | +webapp: |
| 112 | + resources: |
| 113 | + requests: |
| 114 | + cpu: 1000m |
| 115 | + memory: 2Gi |
| 116 | + limits: |
| 117 | + cpu: 2000m |
| 118 | + memory: 4Gi |
| 119 | + |
| 120 | +supervisor: |
| 121 | + resources: |
| 122 | + requests: |
| 123 | + cpu: 200m |
| 124 | + memory: 512Mi |
| 125 | + limits: |
| 126 | + cpu: 1000m |
| 127 | + memory: 2Gi |
| 128 | +``` |
| 129 | +
|
| 130 | +Deploy with your custom values: |
| 131 | +
|
| 132 | +```bash |
| 133 | +helm upgrade -n trigger --install trigger \ |
| 134 | + oci://ghcr.io/triggerdotdev/charts/trigger:4.0.0-beta.3 \ |
| 135 | + --create-namespace \ |
| 136 | + -f values-custom.yaml |
| 137 | +``` |
| 138 | + |
| 139 | +### Extra env |
| 140 | + |
| 141 | +You can set extra environment variables on all services. For example: |
| 142 | + |
| 143 | +```yaml |
| 144 | +webapp: |
| 145 | + extraEnv: |
| 146 | + - name: EXTRA_ENV_VAR |
| 147 | + value: "extra-value" |
| 148 | +``` |
| 149 | +
|
| 150 | +### Extra annotations |
| 151 | +
|
| 152 | +You can set extra annotations on all services. For example: |
| 153 | +
|
| 154 | +```yaml |
| 155 | +webapp: |
| 156 | + podAnnotations: |
| 157 | + "my-annotation": "my-value" |
| 158 | +``` |
| 159 | +
|
| 160 | +### External services |
| 161 | +
|
| 162 | +You can disable the built-in services and use external services instead. For example: |
| 163 | +
|
| 164 | +```yaml |
| 165 | +postgres: |
| 166 | + enabled: false |
| 167 | + external: true |
| 168 | + externalConnection: |
| 169 | + host: "my-postgres.example.com" |
| 170 | + port: 5432 |
| 171 | + database: "my-database" |
| 172 | + username: "my-username" |
| 173 | + password: "my-password" |
| 174 | +``` |
| 175 | +
|
| 176 | +## Worker token |
| 177 | +
|
| 178 | +When using the default bootstrap configuration, worker creation and authentication is handled automatically. The webapp generates a worker token and makes it available to the supervisor via a shared volume. |
| 179 | +
|
| 180 | +### Bootstrap (default) |
| 181 | +
|
| 182 | +```yaml |
| 183 | +webapp: |
| 184 | + bootstrap: |
| 185 | + enabled: true |
| 186 | + workerGroupName: "bootstrap" |
| 187 | +``` |
| 188 | +
|
| 189 | +### Manual |
| 190 | +
|
| 191 | +If you need to set up workers separately or use a custom token: |
| 192 | +
|
| 193 | +1. Get the worker token from the webapp logs: |
| 194 | +
|
| 195 | +```bash |
| 196 | +kubectl logs deployment/trigger-webapp -n trigger | grep -A15 "Worker Token" |
| 197 | +``` |
| 198 | + |
| 199 | +2. Create a secret with the token: |
| 200 | + |
| 201 | +```bash |
| 202 | +kubectl create secret generic worker-token \ |
| 203 | + --from-literal=token=tr_wgt_your_token_here \ |
| 204 | + -n trigger |
| 205 | +``` |
| 206 | + |
| 207 | +3. Configure the supervisor to use the secret: |
| 208 | + |
| 209 | +```yaml |
| 210 | +supervisor: |
| 211 | + bootstrap: |
| 212 | + enabled: false |
| 213 | + workerToken: |
| 214 | + secret: |
| 215 | + name: "worker-token" |
| 216 | + key: "token" |
| 217 | +``` |
| 218 | +
|
| 219 | +## Registry Setup |
| 220 | +
|
| 221 | +See the [Docker registry setup](/self-hosting/docker#registry-setup) for conceptual information. The configuration is specified in your `values.yaml`: |
| 222 | + |
| 223 | +```yaml |
| 224 | +# Use external registry (recommended) |
| 225 | +registry: |
| 226 | + external: true |
| 227 | + # Part of deployment image ref, for example: your-registry.example.com/your-company/proj_123:20250625.1.prod |
| 228 | + repositoryNamespace: "your-company" |
| 229 | + externalConnection: |
| 230 | + host: "your-registry.example.com" |
| 231 | + port: 5000 |
| 232 | + auth: |
| 233 | + enabled: true |
| 234 | + username: "your-username" |
| 235 | + password: "your-password" |
| 236 | +``` |
| 237 | + |
| 238 | +<Note> |
| 239 | +The internal registry (`registry.external: false`) is experimental and requires proper TLS setup and additional cluster configuration. Use an external registry for production. |
| 240 | +</Note> |
| 241 | + |
| 242 | +## Object Storage |
| 243 | + |
| 244 | +See the [Docker object storage setup](/self-hosting/docker#object-storage) for conceptual information. The defaults will use built-in MinIO, but you can use an external S3-compatible storage. The configuration is specified in your `values.yaml`: |
| 245 | + |
| 246 | +```yaml |
| 247 | +# Use external S3-compatible storage |
| 248 | +minio: |
| 249 | + enabled: false |
| 250 | + external: true |
| 251 | + externalConnection: |
| 252 | + url: "https://s3.amazonaws.com" |
| 253 | + # or: "https://your-minio.com:9000" |
| 254 | +
|
| 255 | +# Configure credentials |
| 256 | +secrets: |
| 257 | + objectStore: |
| 258 | + accessKeyId: "admin" |
| 259 | + secretAccessKey: "very-safe-password" |
| 260 | +``` |
| 261 | + |
| 262 | +## Authentication |
| 263 | + |
| 264 | +Authentication options are identical to the [Docker-based installation](/self-hosting/docker#authentication). The configuration is specified in your `values.yaml`: |
| 265 | + |
| 266 | +**GitHub OAuth:** |
| 267 | +```yaml |
| 268 | +webapp: |
| 269 | + extraEnv: |
| 270 | + - name: AUTH_GITHUB_CLIENT_ID |
| 271 | + value: "your-github-client-id" |
| 272 | + - name: AUTH_GITHUB_CLIENT_SECRET |
| 273 | + value: "your-github-client-secret" |
| 274 | +``` |
| 275 | + |
| 276 | +**Email authentication (Resend):** |
| 277 | +```yaml |
| 278 | +webapp: |
| 279 | + extraEnv: |
| 280 | + - name: EMAIL_TRANSPORT |
| 281 | + value: "resend" |
| 282 | + - name: FROM_EMAIL |
| 283 | + value: "noreply@yourdomain.com" |
| 284 | + - name: REPLY_TO_EMAIL |
| 285 | + value: "support@yourdomain.com" |
| 286 | + - name: RESEND_API_KEY |
| 287 | + value: "your-resend-api-key" |
| 288 | +``` |
| 289 | + |
| 290 | +**Restricting access:** |
| 291 | +```yaml |
| 292 | +webapp: |
| 293 | + extraEnv: |
| 294 | + - name: WHITELISTED_EMAILS |
| 295 | + value: "user1@company\\.com|user2@company\\.com" |
| 296 | +``` |
| 297 | + |
| 298 | +## Version Locking |
| 299 | + |
| 300 | +You can lock versions in two ways: |
| 301 | + |
| 302 | +**Helm Chart Version (recommended):** |
| 303 | +```bash |
| 304 | +# Ensure specific chart version |
| 305 | +helm upgrade -n trigger --install trigger \ |
| 306 | + oci://ghcr.io/triggerdotdev/charts/trigger:4.0.0-beta.3 \ |
| 307 | + --version 4.0.0-beta.3 |
| 308 | +``` |
| 309 | + |
| 310 | +**Specific Image Tags:** |
| 311 | +```yaml |
| 312 | +webapp: |
| 313 | + image: |
| 314 | + tag: "v4.0.0-v4-beta.21" |
| 315 | +
|
| 316 | +supervisor: |
| 317 | + image: |
| 318 | + tag: "v4.0.0-v4-beta.21" |
| 319 | +``` |
| 320 | + |
| 321 | +The chart version's `appVersion` field determines the default image tags. Using chart versions ensures compatibility between all components. Newer image tags may be incompatible with older chart versions and vice versa. |
| 322 | + |
| 323 | +## Troubleshooting |
| 324 | + |
| 325 | +**Check logs:** |
| 326 | +```bash |
| 327 | +# Webapp logs |
| 328 | +kubectl logs deployment/trigger-webapp -n trigger -f |
| 329 | +
|
| 330 | +# Supervisor logs |
| 331 | +kubectl logs deployment/trigger-supervisor -n trigger -f |
| 332 | +
|
| 333 | +# All pods |
| 334 | +kubectl logs -l app.kubernetes.io/instance=trigger -n trigger -f |
| 335 | +``` |
| 336 | + |
| 337 | +**Check pod status:** |
| 338 | +```bash |
| 339 | +kubectl get pods -n trigger |
| 340 | +kubectl describe pod <pod-name> -n trigger |
| 341 | +``` |
| 342 | + |
| 343 | +**Start from scratch:** |
| 344 | +```bash |
| 345 | +# Delete the release |
| 346 | +helm uninstall trigger -n trigger |
| 347 | +
|
| 348 | +# Delete persistent volumes (if needed) - careful, this will delete all data |
| 349 | +kubectl delete pvc -l app.kubernetes.io/instance=trigger -n trigger |
| 350 | +
|
| 351 | +# Delete the namespace (optional) |
| 352 | +kubectl delete namespace trigger |
| 353 | +``` |
| 354 | + |
| 355 | +**Common issues:** |
| 356 | +- **Magic links not working**: Check webapp logs for email delivery errors |
| 357 | +- **Deploy fails**: Verify registry access and authentication |
| 358 | +- **Pods stuck pending**: Describe the pod and check the events |
| 359 | +- **Worker token issues**: Check webapp and supervisor logs for errors |
| 360 | + |
| 361 | +## CLI Usage |
| 362 | + |
| 363 | +See the [Docker CLI usage](/self-hosting/docker#cli-usage) section, the commands are identical regardless of deployment method. |
| 364 | + |
| 365 | +<Note> |
| 366 | +While v4 is in beta, always use `@v4-beta` instead of `@latest`. For example: `npx trigger.dev@v4-beta dev` |
| 367 | +</Note> |
| 368 | + |
| 369 | +## CI / GitHub Actions |
| 370 | + |
| 371 | +When running the CLI in a CI environment, your login profiles won't be available. Instead, you can use the `TRIGGER_API_URL` and `TRIGGER_ACCESS_TOKEN` environment |
| 372 | +variables to point at your self-hosted instance and authenticate. |
| 373 | + |
| 374 | +For more detailed instructions, see the [GitHub Actions guide](/github-actions). |
| 375 | + |
| 376 | +## Telemetry |
| 377 | + |
| 378 | +By default, the Trigger.dev webapp sends telemetry data to our servers. This data is used to improve the product and is not shared with third parties. To disable telemetry, set in your `values.yaml`: |
| 379 | + |
| 380 | +```yaml |
| 381 | +telemetry: |
| 382 | + enabled: false |
| 383 | +``` |
0 commit comments