Deployment Guide
This comprehensive guide covers deploying NatsPubsub applications to production, including Docker, Kubernetes, environment configuration, monitoring, and operational best practices.
Table of Contents
- Overview
- Environment Configuration
- Docker Deployment
- Kubernetes Deployment
- NATS Server Setup
- Database Setup
- Monitoring and Observability
- Health Checks
- Scaling Strategies
- High Availability
- Security
- Production Checklist
- Troubleshooting
Overview
Deploying a NatsPubsub application involves several components:
Environment Configuration
Environment Variables
JavaScript/TypeScript
# .env.production
# NATS Configuration
NATS_URLS=nats://nats-1:4222,nats://nats-2:4222,nats://nats-3:4222
NATS_USER=nats_user
NATS_PASS=secure_password
NATS_TLS=true
# Application Configuration
NODE_ENV=production
APP_NAME=order-service
ENV=production
LOG_LEVEL=info
# Consumer Configuration
CONCURRENCY=20
MAX_DELIVER=5
ACK_WAIT=30000
BATCH_SIZE=25
USE_DLQ=true
# Database Configuration (for Outbox pattern)
DATABASE_URL=postgresql://user:password@postgres:5432/orders_production
DB_POOL_SIZE=20
# Monitoring
PROMETHEUS_PORT=9090
HEALTH_CHECK_PORT=8080
# Tracing (Optional)
JAEGER_ENDPOINT=http://jaeger:14268/api/traces
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
Ruby
# .env.production
# NATS Configuration
NATS_URLS=nats://nats-1:4222,nats://nats-2:4222,nats://nats-3:4222
NATS_USER=nats_user
NATS_PASS=secure_password
NATS_TLS=true
# Application Configuration
RAILS_ENV=production
APP_NAME=order-service
ENV=production
LOG_LEVEL=info
# Consumer Configuration
CONCURRENCY=20
MAX_DELIVER=5
ACK_WAIT=30
BATCH_SIZE=25
USE_DLQ=true
# Database Configuration
DATABASE_URL=postgresql://user:password@postgres:5432/orders_production
RAILS_MAX_THREADS=20
# Redis (for caching/locks)
REDIS_URL=redis://redis:6379/0
# Monitoring
PROMETHEUS_PORT=9090
Configuration Files
JavaScript/TypeScript
// config/production.ts
export default {
nats: {
urls: process.env.NATS_URLS?.split(",") || [],
user: process.env.NATS_USER,
pass: process.env.NATS_PASS,
tls: process.env.NATS_TLS === "true",
maxReconnectAttempts: -1, // Infinite
reconnectTimeWait: 2000,
timeout: 10000,
},
app: {
env: process.env.ENV || "production",
appName: process.env.APP_NAME || "app",
logLevel: process.env.LOG_LEVEL || "info",
},
consumer: {
concurrency: parseInt(process.env.CONCURRENCY || "20"),
maxDeliver: parseInt(process.env.MAX_DELIVER || "5"),
ackWait: parseInt(process.env.ACK_WAIT || "30000"),
batchSize: parseInt(process.env.BATCH_SIZE || "25"),
useDlq: process.env.USE_DLQ === "true",
},
database: {
url: process.env.DATABASE_URL,
poolSize: parseInt(process.env.DB_POOL_SIZE || "20"),
},
monitoring: {
prometheusPort: parseInt(process.env.PROMETHEUS_PORT || "9090"),
healthCheckPort: parseInt(process.env.HEALTH_CHECK_PORT || "8080"),
},
};
Ruby
# config/initializers/nats_pubsub.rb
NatsPubsub.configure do |config|
config.servers = ENV['NATS_URLS']&.split(',') || ['nats://localhost:4222']
config.user = ENV['NATS_USER']
config.password = ENV['NATS_PASS']
config.tls = ENV['NATS_TLS'] == 'true'
config.env = ENV['ENV'] || Rails.env
config.app_name = ENV['APP_NAME'] || 'app'
config.concurrency = ENV['CONCURRENCY']&.to_i || 20
config.max_deliver = ENV['MAX_DELIVER']&.to_i || 5
config.ack_wait = ENV['ACK_WAIT']&.to_i || 30
config.batch_size = ENV['BATCH_SIZE']&.to_i || 25
config.use_dlq = ENV['USE_DLQ'] == 'true'
config.use_outbox = true
config.use_inbox = true
# Structured logging
config.logger = ActiveSupport::Logger.new(STDOUT)
config.logger.level = ENV['LOG_LEVEL']&.to_sym || :info
end