740 lines
17 KiB
Markdown
740 lines
17 KiB
Markdown
# Trigger.dev v4 Helm Chart
|
|
|
|
This Helm chart deploys Trigger.dev v4 self-hosting stack to Kubernetes.
|
|
|
|
## Quick Start
|
|
|
|
### Prerequisites
|
|
|
|
```bash
|
|
# Build Helm dependencies (required for Bitnami charts)
|
|
helm dependency build
|
|
|
|
# Extract dependency charts for local template testing
|
|
for file in ./charts/*.tgz; do echo "Extracting $file"; tar -xzf "$file" -C ./charts; done
|
|
|
|
# Alternative: Use --dependency-update flag for template testing
|
|
helm template trigger . --dependency-update
|
|
```
|
|
|
|
### Installation
|
|
|
|
```bash
|
|
# Deploy with default values (testing/development only)
|
|
helm install trigger .
|
|
|
|
# Deploy to specific namespace
|
|
helm install trigger . -n trigger --create-namespace
|
|
|
|
# Deploy with custom values for production
|
|
helm install trigger . -f values-production.yaml -n trigger --create-namespace
|
|
```
|
|
|
|
### Upgrading
|
|
|
|
```bash
|
|
# Upgrade existing release
|
|
helm upgrade trigger .
|
|
|
|
# Upgrade with new values
|
|
helm upgrade trigger . -f values-production.yaml
|
|
```
|
|
|
|
### Access the dashboard
|
|
|
|
```bash
|
|
kubectl port-forward svc/trigger-webapp 3040:3030 --address 0.0.0.0
|
|
```
|
|
|
|
Dashboard: http://localhost:3040/
|
|
|
|
### Deploying your tasks
|
|
|
|
```bash
|
|
# The --push arg is required when testing locally
|
|
npx trigger.dev@latest deploy --push
|
|
```
|
|
|
|
## ⚠️ Security Requirements
|
|
|
|
### Secrets Configuration
|
|
|
|
**IMPORTANT**: The default secrets are for **TESTING ONLY** and must be changed for production.
|
|
|
|
#### Required Secrets
|
|
|
|
All secrets must be exactly **32 hexadecimal characters** (16 bytes):
|
|
|
|
- `sessionSecret` - User authentication sessions
|
|
- `magicLinkSecret` - Passwordless login tokens
|
|
- `encryptionKey` - Sensitive data encryption
|
|
- `managedWorkerSecret` - Worker authentication
|
|
|
|
#### Generate Production Secrets
|
|
|
|
```bash
|
|
for i in {1..4}; do openssl rand -hex 16; done
|
|
```
|
|
|
|
#### Configure Production Secrets
|
|
|
|
```yaml
|
|
# values-production.yaml
|
|
secrets:
|
|
sessionSecret: "your-generated-secret-1"
|
|
magicLinkSecret: "your-generated-secret-2"
|
|
encryptionKey: "your-generated-secret-3"
|
|
managedWorkerSecret: "your-generated-secret-4"
|
|
objectStore:
|
|
accessKeyId: "your-s3-access-key"
|
|
secretAccessKey: "your-s3-secret-key"
|
|
```
|
|
|
|
## Architecture
|
|
|
|
This chart deploys the following components:
|
|
|
|
### Core Services
|
|
- **Webapp** - Main Trigger.dev application (port 3030)
|
|
- **PostgreSQL** - Primary database with logical replication
|
|
- **Redis** - Cache and job queue
|
|
- **Electric** - Real-time sync service (ElectricSQL)
|
|
|
|
### Worker Services
|
|
- **Supervisor** - Kubernetes worker orchestrator for executing runs
|
|
|
|
### Supporting Services
|
|
- **ClickHouse** - Analytics database
|
|
- **MinIO** - S3-compatible object storage
|
|
- **Registry** - Private Docker registry for deployed code (EXPERIMENTAL - disabled by default)
|
|
|
|
## Configuration
|
|
|
|
### Basic Configuration
|
|
|
|
```yaml
|
|
webapp:
|
|
# Application URLs
|
|
appOrigin: "https://trigger.example.com"
|
|
loginOrigin: "https://trigger.example.com"
|
|
apiOrigin: "https://trigger.example.com"
|
|
|
|
# Bootstrap mode (auto-creates worker group)
|
|
bootstrap:
|
|
enabled: true # Enable for combined setups
|
|
workerGroupName: "bootstrap"
|
|
```
|
|
|
|
### External Services
|
|
|
|
Use external managed services instead of bundled components:
|
|
|
|
```yaml
|
|
# External PostgreSQL
|
|
postgres:
|
|
deploy: false
|
|
external:
|
|
host: "your-postgres.rds.amazonaws.com"
|
|
port: 5432
|
|
database: "trigger"
|
|
username: "trigger_user"
|
|
password: "your-password"
|
|
|
|
# External Redis
|
|
redis:
|
|
deploy: false
|
|
external:
|
|
host: "your-redis.cache.amazonaws.com"
|
|
port: 6379
|
|
password: "your-password"
|
|
|
|
# External Docker Registry (e.g., Kind local registry)
|
|
registry:
|
|
deploy: true
|
|
external:
|
|
host: "localhost"
|
|
port: 5001
|
|
username: ""
|
|
password: ""
|
|
```
|
|
|
|
### Ingress Configuration
|
|
|
|
```yaml
|
|
# Webapp ingress
|
|
webapp:
|
|
ingress:
|
|
enabled: true
|
|
className: "nginx"
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
hosts:
|
|
- host: trigger.example.com
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
tls:
|
|
- secretName: trigger-tls
|
|
hosts:
|
|
- trigger.example.com
|
|
|
|
# Registry ingress
|
|
registry:
|
|
ingress:
|
|
enabled: true
|
|
className: "nginx"
|
|
annotations:
|
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
|
hosts:
|
|
- host: registry.example.com
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
tls:
|
|
- secretName: registry-tls
|
|
hosts:
|
|
- registry.example.com
|
|
```
|
|
|
|
### Resource Configuration
|
|
|
|
```yaml
|
|
resources:
|
|
webapp:
|
|
limits:
|
|
cpu: 2000m
|
|
memory: 4Gi
|
|
requests:
|
|
cpu: 1000m
|
|
memory: 2Gi
|
|
|
|
postgres:
|
|
primary:
|
|
resources:
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 2Gi
|
|
```
|
|
|
|
## Deployment Modes
|
|
|
|
### Testing/Development
|
|
- Use default values
|
|
- Single replica
|
|
- Lower resource limits
|
|
- Bootstrap mode enabled
|
|
|
|
### Production
|
|
- Custom secrets (required)
|
|
- Multiple replicas with anti-affinity
|
|
- Production resource limits
|
|
- External services recommended
|
|
- Ingress with TLS
|
|
- Persistent storage
|
|
|
|
## Persistence
|
|
|
|
All services support persistent storage and allow you to control the storage class globally or per service. Our internal services (Registry) now support the full Bitnami persistence configuration pattern:
|
|
|
|
### Basic Persistence Configuration
|
|
|
|
```yaml
|
|
global:
|
|
storageClass: "fast-ssd" # Default for all services
|
|
|
|
# Bitnami chart services (simplified configuration)
|
|
postgres:
|
|
primary:
|
|
persistence:
|
|
enabled: true
|
|
size: 10Gi
|
|
storageClass: "postgres-nvme" # Optional: override for PostgreSQL
|
|
|
|
redis:
|
|
master:
|
|
persistence:
|
|
enabled: true
|
|
size: 5Gi
|
|
storageClass: "redis-ssd" # Optional: override for Redis
|
|
|
|
clickhouse:
|
|
persistence:
|
|
enabled: true
|
|
size: 10Gi
|
|
storageClass: "analytics-hdd" # Optional: override for ClickHouse
|
|
|
|
s3:
|
|
persistence:
|
|
enabled: true
|
|
size: 10Gi
|
|
storageClass: "objectstore-ssd" # Optional: override for S3
|
|
```
|
|
|
|
### Internal Services - Full Bitnami-Style Configuration
|
|
|
|
Our internal services (Registry) support the complete Bitnami persistence configuration pattern:
|
|
|
|
```yaml
|
|
# Registry - Full persistence configuration options
|
|
registry:
|
|
persistence:
|
|
enabled: true
|
|
# Name to assign the volume
|
|
volumeName: "data"
|
|
# Name of an existing PVC to use
|
|
existingClaim: ""
|
|
# The path the volume will be mounted at
|
|
mountPath: "/var/lib/registry"
|
|
# The subdirectory of the volume to mount to
|
|
subPath: ""
|
|
# PVC Storage Class for Registry data volume
|
|
storageClass: "registry-ssd"
|
|
# PVC Access Mode for Registry volume
|
|
accessModes:
|
|
- "ReadWriteOnce"
|
|
# PVC Storage Request for Registry volume
|
|
size: 10Gi
|
|
# Annotations for the PVC
|
|
annotations:
|
|
backup.velero.io/backup-volumes: "data"
|
|
# Labels for the PVC
|
|
labels:
|
|
app.kubernetes.io/component: "storage"
|
|
# Selector to match an existing Persistent Volume
|
|
selector:
|
|
matchLabels:
|
|
tier: "registry"
|
|
# Custom PVC data source
|
|
dataSource:
|
|
name: "registry-snapshot"
|
|
kind: "VolumeSnapshot"
|
|
apiGroup: "snapshot.storage.k8s.io"
|
|
|
|
# Shared persistent volume for worker token file
|
|
persistence:
|
|
shared:
|
|
enabled: true
|
|
size: 5Mi
|
|
accessMode: ReadWriteOnce
|
|
# accessMode: ReadWriteMany # Use for cross-node deployment
|
|
storageClass: ""
|
|
retain: true # Prevents deletion on uninstall
|
|
```
|
|
|
|
### Persistence Configuration Rules
|
|
|
|
- **Service-level storageClass** overrides the global value for that service only
|
|
- **Global storageClass** applies to all services that don't specify their own
|
|
- **Cluster default** is used if neither global nor service-level storageClass is set
|
|
- **Internal services** (Registry) support full Bitnami-style configuration
|
|
- **Bitnami chart services** use their respective chart's configuration patterns
|
|
|
|
## Monitoring
|
|
|
|
### Health Checks
|
|
|
|
Health checks are configured for all services:
|
|
- HTTP endpoints for web services
|
|
- Database connection tests
|
|
- Readiness and liveness probes
|
|
|
|
### Health Probe Configuration
|
|
|
|
All non-Bitnami services support configurable health probes:
|
|
|
|
```yaml
|
|
# Webapp health probes
|
|
webapp:
|
|
livenessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
readinessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 1
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
startupProbe:
|
|
enabled: false
|
|
initialDelaySeconds: 0
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 60
|
|
successThreshold: 1
|
|
|
|
# Supervisor health probes
|
|
supervisor:
|
|
livenessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
readinessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 1
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
startupProbe:
|
|
enabled: false
|
|
initialDelaySeconds: 0
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 60
|
|
successThreshold: 1
|
|
|
|
# Electric health probes
|
|
electric:
|
|
livenessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
readinessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 1
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
startupProbe:
|
|
enabled: false
|
|
initialDelaySeconds: 0
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 60
|
|
successThreshold: 1
|
|
|
|
# Registry health probes
|
|
registry:
|
|
livenessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 5
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
readinessProbe:
|
|
enabled: true
|
|
initialDelaySeconds: 5
|
|
periodSeconds: 5
|
|
timeoutSeconds: 1
|
|
failureThreshold: 5
|
|
successThreshold: 1
|
|
startupProbe:
|
|
enabled: false
|
|
initialDelaySeconds: 0
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 60
|
|
successThreshold: 1
|
|
```
|
|
|
|
### Prometheus Integration
|
|
|
|
ServiceMonitors are available for webapp and supervisor services:
|
|
|
|
```yaml
|
|
webapp:
|
|
serviceMonitor:
|
|
enabled: true
|
|
interval: "30s"
|
|
path: "/metrics"
|
|
labels:
|
|
release: prometheus-stack
|
|
|
|
supervisor:
|
|
serviceMonitor:
|
|
enabled: true
|
|
interval: "30s"
|
|
path: "/metrics"
|
|
labels:
|
|
release: prometheus-stack
|
|
```
|
|
|
|
## Operations
|
|
|
|
### Force Pod Restart
|
|
|
|
When you need to force all pods to restart (e.g., to pick up updated secrets or config):
|
|
|
|
```bash
|
|
# Force restart using timestamp annotation (Helm-native approach)
|
|
helm upgrade <release-name> . --set-string podAnnotations.restartedAt="$(date +%s)"
|
|
|
|
# Example
|
|
helm upgrade trigger . --set-string podAnnotations.restartedAt="$(date +%s)"
|
|
```
|
|
|
|
This approach:
|
|
- ✅ Uses Helm's built-in annotation mechanism
|
|
- ✅ Safe - doesn't recreate immutable resources like PVCs
|
|
- ✅ Targeted - only restarts pods that need updates
|
|
- ✅ Trackable - increments Helm revision number
|
|
|
|
### Configuration Updates
|
|
|
|
After changing secrets or ConfigMaps in your values file:
|
|
|
|
```bash
|
|
# 1. Upgrade with new values
|
|
helm upgrade trigger . -f values-production.yaml
|
|
|
|
# 2. Force pod restart to pick up changes
|
|
helm upgrade trigger . -f values-production.yaml \
|
|
--set-string podAnnotations.restartedAt="$(date +%s)"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Check Pod Status
|
|
```bash
|
|
kubectl get pods -l app.kubernetes.io/name=trigger.dev
|
|
```
|
|
|
|
### View Logs
|
|
```bash
|
|
# Webapp logs
|
|
kubectl logs -l app.kubernetes.io/component=webapp
|
|
|
|
# Database logs
|
|
kubectl logs -l app.kubernetes.io/component=postgres
|
|
```
|
|
|
|
### Run Tests
|
|
```bash
|
|
helm test trigger.dev
|
|
```
|
|
|
|
## Testing
|
|
|
|
### Validate Deployment
|
|
|
|
```bash
|
|
# Check Helm template syntax
|
|
helm template trigger.dev . --dry-run > /dev/null && echo "Template validation successful"
|
|
|
|
# Test webapp health endpoint (requires port forwarding)
|
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:3040/healthcheck || echo "Connection failed"
|
|
|
|
# Port forward to access webapp locally
|
|
kubectl port-forward svc/trigger.dev-webapp 3040:3030 --address 0.0.0.0
|
|
```
|
|
|
|
### Common Issues
|
|
|
|
1. **Secrets errors**: Ensure all secrets are exactly 32 hex characters
|
|
2. **Database connection**: Check PostgreSQL is ready before webapp starts
|
|
3. **Resource limits**: Increase limits for ClickHouse in constrained environments
|
|
4. **Config not applying**: Use the pod restart technique above to force config reload
|
|
5. **Image pull errors**: When testing locally, deploy with `npx trigger.dev@latest deploy --push`
|
|
|
|
## Examples
|
|
|
|
See `values-production-example.yaml` for a complete production configuration example.
|
|
|
|
## Version Management
|
|
|
|
### Understanding Versions
|
|
|
|
The Helm chart uses three types of versions:
|
|
|
|
1. **Chart Version** (`Chart.yaml:version`) - Helm chart packaging version
|
|
2. **App Version** (`Chart.yaml:appVersion`) - Trigger.dev application version
|
|
3. **Component Versions** (`values.yaml`) - Individual service versions (Electric, ClickHouse, etc.)
|
|
|
|
### Release Process
|
|
|
|
#### For Chart Maintainers
|
|
|
|
1. **Update Chart Version** for chart changes:
|
|
```bash
|
|
# Edit Chart.yaml
|
|
version: 4.1.0 # Increment for chart changes (semver)
|
|
```
|
|
|
|
2. **Update App Version** when Trigger.dev releases new version:
|
|
```bash
|
|
# Edit Chart.yaml
|
|
appVersion: "v4.1.0" # Match Trigger.dev release (v-prefixed image tag)
|
|
```
|
|
|
|
3. **Release via GitHub**:
|
|
```bash
|
|
# Tag and push
|
|
git tag helm-v4.1.0
|
|
git push origin helm-v4.1.0
|
|
|
|
# GitHub Actions will automatically build and publish to GHCR
|
|
```
|
|
|
|
#### For Users
|
|
|
|
```bash
|
|
# Install specific chart version
|
|
helm upgrade --install trigger \
|
|
oci://ghcr.io/triggerdotdev/charts/trigger.dev \
|
|
--version 4.1.0
|
|
|
|
# Install latest chart version
|
|
helm upgrade --install trigger \
|
|
oci://ghcr.io/triggerdotdev/charts/trigger.dev
|
|
|
|
# Override app version (advanced)
|
|
helm upgrade --install trigger . \
|
|
--set webapp.image.tag=v4.0.1
|
|
```
|
|
|
|
## Production Readiness Checklist
|
|
|
|
### 🔒 Security (REQUIRED)
|
|
|
|
- [ ] **Generate unique secrets** (never use defaults):
|
|
```bash
|
|
# Generate 4 secrets
|
|
for i in {1..4}; do openssl rand -hex 16; done
|
|
```
|
|
|
|
- [ ] **Configure security contexts**:
|
|
```yaml
|
|
webapp:
|
|
podSecurityContext:
|
|
fsGroup: 1000
|
|
securityContext:
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
allowPrivilegeEscalation: false
|
|
readOnlyRootFilesystem: true
|
|
capabilities:
|
|
drop: [ALL]
|
|
```
|
|
|
|
- [ ] **Enable network policies** (if supported by cluster)
|
|
- [ ] **Configure proper RBAC** for supervisor
|
|
- [ ] **Use TLS ingress** with cert-manager
|
|
|
|
### 📊 Resource Management (REQUIRED)
|
|
|
|
- [ ] **Set resource limits and requests** - for example:
|
|
```yaml
|
|
webapp:
|
|
resources:
|
|
limits:
|
|
cpu: 2000m
|
|
memory: 4Gi
|
|
requests:
|
|
cpu: 1000m
|
|
memory: 2Gi
|
|
|
|
postgres:
|
|
primary:
|
|
resources:
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 2Gi
|
|
requests:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
|
|
redis:
|
|
master:
|
|
resources:
|
|
limits:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
requests:
|
|
cpu: 250m
|
|
memory: 512Mi
|
|
|
|
# ClickHouse can be very resource intensive, so we recommend setting limits and requests accordingly
|
|
# Note: not doing this can cause OOM crashes which will cause issues across many different features
|
|
clickhouse:
|
|
resources:
|
|
limits:
|
|
cpu: 4000m
|
|
memory: 16Gi
|
|
requests:
|
|
cpu: 2000m
|
|
memory: 8Gi
|
|
|
|
supervisor:
|
|
resources:
|
|
limits:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
requests:
|
|
cpu: 250m
|
|
memory: 512Mi
|
|
```
|
|
|
|
- [ ] **Configure persistent storage for all services** - for example:
|
|
```yaml
|
|
global:
|
|
storageClass: "fast-nvme" # Default for all services
|
|
|
|
postgres:
|
|
primary:
|
|
persistence:
|
|
size: 500Gi
|
|
|
|
redis:
|
|
master:
|
|
persistence:
|
|
size: 20Gi
|
|
|
|
clickhouse:
|
|
persistence:
|
|
size: 100Gi
|
|
|
|
s3:
|
|
persistence:
|
|
size: 200Gi
|
|
|
|
# Internal services support full Bitnami-style configuration
|
|
registry:
|
|
persistence:
|
|
enabled: true
|
|
size: 100Gi
|
|
storageClass: "registry-ssd"
|
|
annotations:
|
|
backup.velero.io/backup-volumes: "data"
|
|
```
|
|
|
|
### 🏗️ High Availability (RECOMMENDED)
|
|
|
|
- [ ] **Multiple replicas** with pod anti-affinity
|
|
- [ ] **Pod disruption budgets**
|
|
- [ ] **External managed services** (RDS, ElastiCache, etc.)
|
|
- [ ] **Multi-AZ storage classes**
|
|
- [ ] **Backup strategies** for databases
|
|
|
|
### 📈 Monitoring (RECOMMENDED)
|
|
|
|
- [ ] **Enable ServiceMonitors** for Prometheus
|
|
- [ ] **Configure alerting** for critical services
|
|
- [ ] **Set up log aggregation**
|
|
- [ ] **Monitor resource usage** and adjust limits
|
|
|
|
### 🚀 Performance (OPTIONAL)
|
|
|
|
- [ ] **Horizontal Pod Autoscaler** for webapp
|
|
- [ ] **Vertical Pod Autoscaler** for data services
|
|
- [ ] **Node affinity** for data services
|
|
- [ ] **Separate storage classes** for different workloads
|
|
|
|
## Support
|
|
|
|
- Documentation: https://trigger.dev/docs/self-hosting
|
|
- GitHub Issues: https://github.com/triggerdotdev/trigger.dev/issues
|
|
- Discord: https://discord.gg/untWVke9aH
|