Skip to content

Latest commit

 

History

History
458 lines (370 loc) · 8.72 KB

File metadata and controls

458 lines (370 loc) · 8.72 KB

Docker Deployment

Complete guide to deploying the GraphQL proxy server using Docker containers.

Prerequisites

  • Docker Engine 20.10+
  • Docker Compose (recommended)

Quick Start

Basic Docker Run

docker run -d \
  --name graphql-proxy \
  -p 5001:5001 \
  -e UPSTREAM_GRAPHQL_ENDPOINT=https://api.example.com/graphql \
  -e GRAPHQL_MODE=SETMODE \
  --restart unless-stopped \
  your-registry/graphql-proxy:latest

Docker Compose

Create docker-compose.yml:

version: '3.8'
services:
  graphql-proxy:
    image: your-registry/graphql-proxy:latest
    ports:
      - "5001:5001"
    environment:
      - UPSTREAM_GRAPHQL_ENDPOINT=https://api.example.com/graphql
      - GRAPHQL_MODE=SETMODE
      - AUTH_TOKEN=your-token-here
    volumes:
      - ./data:/app/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Deploy with:

docker compose up -d

Dockerfile

Multi-stage Build

# Build stage
FROM oven/bun:1 AS builder
WORKDIR /app
COPY package.json ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build

# Production stage
FROM oven/bun:1 AS runner
WORKDIR /app

# Copy built application
COPY --from=builder /app/server/index.ts ./server/
COPY --from=builder /app/package.json ./
COPY --from=builder /app/node_modules ./node_modules

# Create data directories
RUN mkdir -p /app/data/graphql-cache /app/data/mutation-queue

# Set environment
ENV NODE_ENV=production
ENV PORT=5001

EXPOSE 5001

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:5001/health || exit 1

CMD ["bun", "run", "server/index.ts"]

Build and Push

# Build image
docker build -t graphql-proxy .

# Tag for registry
docker tag graphql-proxy your-registry/graphql-proxy:latest

# Push to registry
docker push your-registry/graphql-proxy:latest

Production Deployment

Full Production Setup

version: '3.8'
services:
  graphql-proxy:
    image: your-registry/graphql-proxy:latest
    container_name: graphql-proxy-prod
    ports:
      - "80:5001"
    environment:
      - NODE_ENV=production
      - PORT=5001
      - UPSTREAM_GRAPHQL_ENDPOINT=https://api.production.com/graphql
      - AUTH_TOKEN=${AUTH_TOKEN}
      - GRAPHQL_MODE=SETMODE
      - CORS_ORIGIN=https://yourapp.com
    volumes:
      - graphql_cache:/app/data/graphql-cache
      - graphql_queue:/app/data/mutation-queue
      - graphql_db:/app/data/local-db.json
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    networks:
      - proxy

volumes:
  graphql_cache:
    driver: local
  graphql_queue:
    driver: local
  graphql_db:
    driver: local

networks:
  proxy:
    driver: bridge

Environment File

Create .env.prod:

# Production environment
NODE_ENV=production
PORT=5001
UPSTREAM_GRAPHQL_ENDPOINT=https://api.production.com/graphql
AUTH_TOKEN=your-production-token
GRAPHQL_MODE=SETMODE
CORS_ORIGIN=https://yourapp.com

# Storage paths
CACHE_DIR=/app/data/graphql-cache
QUEUE_DIR=/app/data/mutation-queue
LOCAL_DB_PATH=/app/data/local-db.json

Nginx Reverse Proxy

version: '3.8'
services:
  graphql-proxy:
    # ... proxy configuration

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl:/etc/ssl:ro
    depends_on:
      - graphql-proxy
    networks:
      - proxy

Nginx configuration (nginx.conf):

events {
    worker_connections 1024;
}

http {
    upstream graphql_backend {
        server graphql-proxy:5001;
    }

    server {
        listen 80;
        server_name your-domain.com;

        # Redirect to HTTPS
        return 301 https://$server_name$request_uri;
    }

    server {
        listen 443 ssl http2;
        server_name your-domain.com;

        ssl_certificate /etc/ssl/cert.pem;
        ssl_certificate_key /etc/ssl/key.pem;

        # Security headers
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";

        # GraphQL endpoint
        location /graphql {
            proxy_pass http://graphql_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            # Timeout settings
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }

        # Health check
        location /health {
            proxy_pass http://graphql_backend;
        }
    }
}

Scaling and Load Balancing

Horizontal Scaling

version: '3.8'
services:
  graphql-proxy:
    image: your-registry/graphql-proxy:latest
    deploy:
      mode: replicated
      replicas: 3
      restart_policy:
        condition: on-failure
    environment:
      - UPSTREAM_GRAPHQL_ENDPOINT=https://api.production.com/graphql
      - GRAPHQL_MODE=GETMODE  # Read-only for scaling
    networks:
      - proxy

  load-balancer:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./load-balancer.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - graphql-proxy
    networks:
      - proxy

Load balancer configuration:

events {
    worker_connections 1024;
}

http {
    upstream graphql_proxies {
        server graphql-proxy:5001;
    }

    server {
        listen 80;
        server_name api.your-domain.com;

        location / {
            proxy_pass http://graphql_proxies;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
        }
    }
}

Monitoring and Observability

Health Checks

services:
  graphql-proxy:
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:5001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Logging

services:
  graphql-proxy:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "service"
    environment:
      - NODE_ENV=production

Metrics with Prometheus

version: '3.8'
services:
  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    networks:
      - monitoring

  graphql-proxy:
    # ... proxy configuration
    environment:
      - METRICS_PORT=9090
    networks:
      - proxy
      - monitoring

Security Best Practices

Non-Root User

# Use non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001

USER nodejs

Secrets Management

services:
  graphql-proxy:
    environment:
      - UPSTREAM_GRAPHQL_ENDPOINT=https://api.production.com/graphql
    secrets:
      - auth_token

secrets:
  auth_token:
    file: ./secrets/auth_token.txt

Resource Limits

services:
  graphql-proxy:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M

Troubleshooting

Container Won't Start

# Check container logs
docker logs graphql-proxy

# Check container status
docker ps -a

# Inspect container
docker inspect graphql-proxy

Health Check Failures

# Test health endpoint manually
docker exec graphql-proxy curl -f http://localhost:5001/health

# Check if port is bound
docker exec graphql-proxy netstat -tlnp | grep 5001

Storage Issues

# Check volume permissions
docker run --rm -v graphql_cache:/data alpine ls -la /data

# Clean up volumes
docker volume rm $(docker volume ls -q | grep graphql)

Network Issues

# Test upstream connectivity from container
docker exec graphql-proxy curl -f $UPSTREAM_GRAPHQL_ENDPOINT

# Check network configuration
docker network ls
docker network inspect proxy