| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- version: '3.8'
- services:
- # PostgreSQL Database Service (Production)
- db:
- image: postgres:15-alpine
- container_name: market-data-db-prod
- environment:
- POSTGRES_USER: ${DB_USER:-postgres}
- POSTGRES_PASSWORD: ${DB_PASSWORD}
- POSTGRES_DB: ${DB_NAME:-financial_data}
- PGDATA: /var/lib/postgresql/data/pgdata
- volumes:
- - market_data_db_data_prod:/var/lib/postgresql/data
- - ./docker/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
- # No exposed ports in production (internal only)
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-financial_data}"]
- interval: 10s
- timeout: 5s
- retries: 5
- networks:
- - market-data-network
- restart: unless-stopped
- # Production security: run as non-root
- user: "999:999"
- # Node.js API Service (Production)
- api:
- build:
- context: .
- dockerfile: Dockerfile
- target: production
- container_name: market-data-api-prod
- environment:
- - NODE_ENV=production
- - PORT=3000
- - DB_HOST=db
- - DB_PORT=5432
- - DB_NAME=${DB_NAME:-financial_data}
- - DB_USER=${DB_USER:-postgres}
- - DB_PASSWORD=${DB_PASSWORD}
- - CORS_ORIGIN=${CORS_ORIGIN:-http://localhost:3000,https://beta-app.insightbull.io,https://app.insightbull.io}
- - JWT_SECRET=${JWT_SECRET}
- - LOG_LEVEL=${LOG_LEVEL:-info}
- # No volume mounts in production (code is baked into image)
- # Optional: mount logs volume for persistence
- volumes:
- - market_data_logs_prod:/app/logs
- # No exposed ports (accessed only through nginx)
- depends_on:
- db:
- condition: service_healthy
- networks:
- - market-data-network
- restart: unless-stopped
- healthcheck:
- test: ["CMD", "node", "-e", "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"]
- interval: 30s
- timeout: 10s
- start_period: 40s
- retries: 3
- # Nginx Reverse Proxy (Production)
- nginx:
- image: nginx:alpine
- container_name: market-data-nginx-prod
- ports:
- - "80:80"
- - "443:443"
- volumes:
- - ./nginx/nginx.prod.conf:/etc/nginx/nginx.conf:ro
- - ./docker/nginx-entrypoint.sh:/docker-entrypoint-nginx.sh:ro
- # SSL certificates from certbot (shared volume)
- - certbot_etc:/etc/letsencrypt:ro
- - certbot_www:/var/www/certbot:ro
- - certbot_reload:/var/run/certbot-reload:rw
- environment:
- - DOMAIN_NAME=${DOMAIN_NAME:-default}
- depends_on:
- - api
- - certbot
- networks:
- - market-data-network
- restart: unless-stopped
- entrypoint: ["/bin/sh", "/docker-entrypoint-nginx.sh"]
- healthcheck:
- test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
- interval: 30s
- timeout: 10s
- retries: 3
- # Certbot for SSL Certificate Management
- certbot:
- image: certbot/certbot:latest
- container_name: market-data-certbot
- volumes:
- - certbot_etc:/etc/letsencrypt
- - certbot_www:/var/www/certbot
- - certbot_logs:/var/log/letsencrypt
- - certbot_reload:/var/run/certbot-reload
- networks:
- - market-data-network
- restart: unless-stopped
- entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew --quiet && touch /var/run/certbot-reload/reload 2>/dev/null || true; sleep 12h & wait $${!}; done;'"
- # Note: Initial certificate must be obtained using certbot-init service
- # Run: DOMAIN_NAME=yourdomain.com SSL_EMAIL=your@email.com docker-compose -f docker-compose.prod.yml run --rm certbot-init
- # Certbot Initialization Service (one-time use)
- certbot-init:
- image: certbot/certbot:latest
- container_name: market-data-certbot-init
- volumes:
- - certbot_etc:/etc/letsencrypt
- - certbot_www:/var/www/certbot
- - certbot_logs:/var/log/letsencrypt
- - ./docker/init-ssl.sh:/docker/init-ssl.sh:ro
- networks:
- - market-data-network
- entrypoint: /bin/sh
- command: /docker/init-ssl.sh
- environment:
- - DOMAIN_NAME=${DOMAIN_NAME}
- - SSL_EMAIL=${SSL_EMAIL}
- - SSL_STAGING=${SSL_STAGING:-0}
- volumes:
- market_data_db_data_prod:
- driver: local
- market_data_logs_prod:
- driver: local
- certbot_etc:
- driver: local
- certbot_www:
- driver: local
- certbot_logs:
- driver: local
- certbot_reload:
- driver: local
- networks:
- market-data-network:
- driver: bridge
|