NQDEV Containers - Examples & Best Practices

Examples Best Practices

Tổng hợp các ví dụ thực tế và best practices khi sử dụng NQDEV containers trong production.

📋 Mục lục

🏗️ Architecture Patterns

1. Microservices Architecture

# Full microservices stack
version: "3.8"

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
  database:
    driver: bridge

services:
  # Load Balancer
  haproxy:
    image: nqdev/haproxy-alpine-custom:3.1.5
    ports:
      - "80:80"
      - "443:443"
      - "7001:7001"
    networks:
      - frontend
      - backend
    configs:
      - source: haproxy_config
        target: /usr/local/etc/haproxy/haproxy.cfg

  # API Gateway
  nginx-gateway:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    networks:
      - frontend
      - backend
    volumes:
      - ./nginx/gateway.conf:/etc/nginx/conf.d/default.conf

  # Application Services
  user-service:
    image: user-service:latest
    networks:
      - backend
      - database
    environment:
      - DATABASE_URL=postgresql://user:pass@postgres:5432/users

  order-service:
    image: order-service:latest
    networks:
      - backend
      - database

  # Database
  postgres:
    image: nqdev/postgres-pgagent:latest
    networks:
      - database
    volumes:
      - postgres_data:/var/lib/postgresql/data

  # Message Queue
  rabbitmq:
    image: bitnamilegacy/rabbitmq:4.1
    networks:
      - backend

volumes:
  postgres_data:

configs:
  haproxy_config:
    file: ./haproxy/microservices.cfg

2. Three-Tier Web Application

# Classic three-tier: Presentation, Application, Database
version: "3.8"

services:
  # Presentation Tier - NGINX serving static content + reverse proxy
  web:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/three-tier.conf:/etc/nginx/nginx.conf
      - ./static:/usr/share/nginx/html
    depends_on:
      - app

  # Application Tier - WordPress or custom app
  app:
    image: nqdev/wordpress:6-debian-12
    environment:
      - WORDPRESS_DATABASE_HOST=database
      - WORDPRESS_DATABASE_NAME=webapp
    volumes:
      - app_data:/bitnami/wordpress
    depends_on:
      - database

  # Database Tier - PostgreSQL with pgAgent
  database:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_DB=webapp
      - POSTGRES_USER=webuser
      - POSTGRES_PASSWORD=securepassword
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  app_data:
  db_data:

🚀 Production Examples

1. High-Traffic E-commerce Site

# E-commerce platform with auto-scaling
version: "3.8"

x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "100m"
    max-file: "3"

services:
  # Load Balancer with SSL termination
  loadbalancer:
    image: nqdev/haproxy-alpine-custom:3.1.5
    ports:
      - "80:80"
      - "443:443"
    environment:
      - REDIS_HOST=redis-cache
    volumes:
      - ./ssl:/usr/local/etc/haproxy/ssl:ro
      - ./haproxy/ecommerce.cfg:/usr/local/etc/haproxy/haproxy.cfg
    logging: *default-logging
    deploy:
      replicas: 2
      resources:
        limits:
          memory: 1G
          cpus: "1"

  # NGINX for static assets và CDN
  cdn:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    volumes:
      - ./nginx/cdn.conf:/etc/nginx/nginx.conf
      - media_storage:/usr/share/nginx/html/media
    logging: *default-logging
    deploy:
      replicas: 3

  # WordPress application servers
  wordpress:
    image: nqdev/wordpress:6-debian-12
    environment:
      - WORDPRESS_DATABASE_HOST=database
      - WORDPRESS_ENABLE_HTTPS=yes
      - WORDPRESS_DATABASE_NAME=ecommerce
    volumes:
      - wordpress_data:/bitnami/wordpress
    logging: *default-logging
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 2G
          cpus: "2"

  # Database cluster
  database:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_DB=ecommerce
      - POSTGRES_USER=ecommerce_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
    volumes:
      - db_data:/var/lib/postgresql/data
    secrets:
      - db_password
    logging: *default-logging

  # Redis for caching và sessions
  redis-cache:
    image: redis:alpine3.18
    command: redis-server --appendonly yes --requirepass redis_password
    volumes:
      - redis_data:/data
    logging: *default-logging

  # Message queue cho background jobs
  rabbitmq:
    image: bitnamilegacy/rabbitmq:4.1
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS_FILE=/run/secrets/rabbitmq_password
    volumes:
      - rabbitmq_data:/bitnami/rabbitmq/mnesia
    secrets:
      - rabbitmq_password
    logging: *default-logging

volumes:
  wordpress_data:
  db_data:
  redis_data:
  rabbitmq_data:
  media_storage:

secrets:
  db_password:
    file: ./secrets/db_password.txt
  rabbitmq_password:
    file: ./secrets/rabbitmq_password.txt

2. API-First Application

# Microservices API platform
version: "3.8"

services:
  # API Gateway với rate limiting
  api-gateway:
    image: nqdev/haproxy-alpine-custom:3.1.5
    ports:
      - "80:80"
      - "443:443"
    environment:
      - REDIS_HOST=redis-rate-limit
      - REDIS_PORT=6379
    volumes:
      - ./haproxy/api-gateway.cfg:/usr/local/etc/haproxy/haproxy.cfg
      - ./haproxy/lua:/nqdev/haproxy/lua
    depends_on:
      - redis-rate-limit

  # Authentication service
  auth-service:
    image: auth-api:latest
    environment:
      - JWT_SECRET_FILE=/run/secrets/jwt_secret
      - DATABASE_URL=postgresql://auth_user:auth_pass@postgres:5432/auth
    secrets:
      - jwt_secret

  # User management service
  user-service:
    image: user-api:latest
    environment:
      - DATABASE_URL=postgresql://user_user:user_pass@postgres:5432/users

  # Order processing service
  order-service:
    image: order-api:latest
    environment:
      - DATABASE_URL=postgresql://order_user:order_pass@postgres:5432/orders
      - RABBITMQ_URL=amqp://admin:admin@rabbitmq:5672

  # Notification service
  notification-service:
    image: notification-api:latest
    environment:
      - RABBITMQ_URL=amqp://admin:admin@rabbitmq:5672
      - EMAIL_SERVICE_KEY_FILE=/run/secrets/email_key
    secrets:
      - email_key

  # Database
  postgres:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_MULTIPLE_DATABASES=auth,users,orders
    volumes:
      - ./postgres/init:/docker-entrypoint-initdb.d
      - postgres_data:/var/lib/postgresql/data

  # Message queue
  rabbitmq:
    image: bitnamilegacy/rabbitmq:4.1
    environment:
      - RABBITMQ_DEFAULT_USER=admin
      - RABBITMQ_DEFAULT_PASS=admin

  # Rate limiting cache
  redis-rate-limit:
    image: redis:alpine3.18

volumes:
  postgres_data:

secrets:
  jwt_secret:
    file: ./secrets/jwt_secret.txt
  email_key:
    file: ./secrets/email_key.txt

🔒 Security Best Practices

1. SSL/TLS Configuration

HAProxy SSL Termination

# /haproxy/ssl-config.cfg
global
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-bind-options ssl-min-ver TLSv1.2 no-tls-tickets

frontend https_frontend
    bind *:443 ssl crt /usr/local/etc/haproxy/ssl/ alpn h2,http/1.1

    # Security headers
    http-response set-header Strict-Transport-Security "max-age=31536000; includeSubDomains"
    http-response set-header X-Frame-Options DENY
    http-response set-header X-Content-Type-Options nosniff
    http-response set-header X-XSS-Protection "1; mode=block"

    # Hide server information
    http-response del-header Server
    http-response del-header X-Powered-By

NGINX SSL Configuration

# /nginx/ssl-security.conf
server {
    listen 443 ssl http2;

    # Modern SSL configuration
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;

    # SSL optimization
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;

    # Security headers
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options DENY always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'" always;
}

2. Access Control & Authentication

IP-based Access Control

# docker-compose.security.yml
version: "3.8"

services:
  secure-app:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    volumes:
      - ./nginx/security.conf:/etc/nginx/nginx.conf
    environment:
      - TRUSTED_IPS=192.168.1.0/24,10.0.0.0/8
# /nginx/security.conf
geo $trusted_ip {
    default 0;
    192.168.1.0/24 1;
    10.0.0.0/8 1;
    172.16.0.0/12 1;
}

server {
    if ($trusted_ip = 0) {
        return 403;
    }

    # Rate limiting
    limit_req zone=general burst=10 nodelay;

    location /admin {
        auth_basic "Admin Area";
        auth_basic_user_file /etc/nginx/.htpasswd;
    }
}

3. Database Security

# Secure PostgreSQL setup
version: "3.8"

services:
  database:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_DB_FILE=/run/secrets/db_name
      - POSTGRES_USER_FILE=/run/secrets/db_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/db_password
      - POSTGRES_HOST_AUTH_METHOD=scram-sha-256
      - POSTGRES_INITDB_ARGS=--auth-host=scram-sha-256 --data-checksums
    secrets:
      - db_name
      - db_user
      - db_password
    volumes:
      - db_data:/var/lib/postgresql/data
      - ./postgres/postgresql.conf:/var/lib/postgresql/data/postgresql.conf
    networks:
      - database_network

secrets:
  db_name:
    file: ./secrets/db_name.txt
  db_user:
    file: ./secrets/db_user.txt
  db_password:
    file: ./secrets/db_password.txt

networks:
  database_network:
    driver: bridge
    internal: true # No external access

📊 Monitoring & Logging

1. Centralized Logging

# ELK Stack integration
version: "3.8"

x-logging: &elk-logging
  driver: "gelf"
  options:
    gelf-address: "udp://logstash:12201"
    tag: "//"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    logging: *elk-logging
    volumes:
      - ./nginx/logging.conf:/etc/nginx/nginx.conf

  haproxy:
    image: nqdev/haproxy-alpine-custom:3.1.5
    logging: *elk-logging

  # Log aggregation
  logstash:
    image: logstash:8.11.0
    ports:
      - "12201:12201/udp"
    volumes:
      - ./logstash/pipeline:/usr/share/logstash/pipeline
    environment:
      - "LS_JAVA_OPTS=-Xmx256m -Xms256m"

  elasticsearch:
    image: elasticsearch:8.11.0
    environment:
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    volumes:
      - elasticsearch_data:/usr/share/elasticsearch/data

  kibana:
    image: kibana:8.11.0
    ports:
      - "5601:5601"
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200

volumes:
  elasticsearch_data:

2. Metrics Collection

# Prometheus monitoring
version: "3.8"

services:
  # Application với metrics endpoint
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    volumes:
      - ./nginx/metrics.conf:/etc/nginx/nginx.conf
    labels:
      - "prometheus.io/scrape=true"
      - "prometheus.io/port=8080"
      - "prometheus.io/path=/nginx_status"

  # Metrics collector
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--web.console.libraries=/etc/prometheus/console_libraries"
      - "--web.console.templates=/etc/prometheus/consoles"

  # Dashboard
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
      - ./grafana/dashboards:/etc/grafana/provisioning/dashboards

volumes:
  grafana_data:

⚡ Performance Optimization

1. Caching Strategy

# Multi-layer caching
version: "3.8"

services:
  # CDN layer
  nginx-cdn:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    volumes:
      - ./nginx/cdn.conf:/etc/nginx/nginx.conf
      - static_content:/usr/share/nginx/html
    deploy:
      replicas: 3

  # Application cache
  redis-app-cache:
    image: redis:alpine3.18
    command: redis-server --maxmemory 1gb --maxmemory-policy allkeys-lru

  # Session store
  redis-sessions:
    image: redis:alpine3.18
    command: redis-server --maxmemory 512mb --maxmemory-policy noeviction

  # Database query cache
  postgres:
    image: nqdev/postgres-pgagent:latest
    volumes:
      - ./postgres/optimized.conf:/var/lib/postgresql/data/postgresql.conf

volumes:
  static_content:
# /nginx/cdn.conf - Aggressive caching
server {
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Vary Accept-Encoding;
        gzip_static on;
    }

    location /api/ {
        # API response caching
        proxy_cache api_cache;
        proxy_cache_valid 200 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_use_stale error timeout updating;
        add_header X-Cache-Status $upstream_cache_status;
    }
}

2. Database Optimization

-- /postgres/init/optimization.sql
-- Connection pooling
ALTER SYSTEM SET max_connections = 200;
ALTER SYSTEM SET shared_buffers = '256MB';
ALTER SYSTEM SET effective_cache_size = '1GB';

-- Query optimization
ALTER SYSTEM SET random_page_cost = 1.1;
ALTER SYSTEM SET seq_page_cost = 1;
ALTER SYSTEM SET default_statistics_target = 100;

-- Logging optimization
ALTER SYSTEM SET log_statement = 'mod';
ALTER SYSTEM SET log_min_duration_statement = 1000;

SELECT pg_reload_conf();

🔧 DevOps Workflows

1. CI/CD Pipeline

# .github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Build and push images
        env:
          REGISTRY: ghcr.io
        run: |
          echo $ | docker login $REGISTRY -u $ --password-stdin

          # Build custom images
          docker build -t $REGISTRY/nqdev/app:$ ./app
          docker push $REGISTRY/nqdev/app:$

      - name: Deploy to production
        uses: appleboy/ssh-action@v0.1.5
        with:
          host: $
          username: deploy
          key: $
          script: |
            cd /opt/app
            export IMAGE_TAG=$
            docker-compose -f docker-compose.prod.yml pull
            docker-compose -f docker-compose.prod.yml up -d --remove-orphans
            docker system prune -f

2. Health Checks & Auto-healing

# docker-compose.health.yml
version: "3.8"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3

  postgres:
    image: nqdev/postgres-pgagent:latest
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
      interval: 10s
      timeout: 5s
      retries: 5

3. Backup & Disaster Recovery

#!/bin/bash
# scripts/backup.sh

set -euo pipefail

BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)

# Database backup
docker-compose exec -T postgres pg_dumpall -U postgres > "$BACKUP_DIR/db_backup_$DATE.sql"

# Application data backup
docker run --rm \
  -v app_data:/data \
  -v "$BACKUP_DIR:/backup" \
  alpine tar czf "/backup/app_data_$DATE.tar.gz" -C /data .

# Configuration backup
tar czf "$BACKUP_DIR/configs_$DATE.tar.gz" \
  ./nginx \
  ./haproxy \
  ./docker-compose*.yml

# Upload to S3 (optional)
aws s3 sync "$BACKUP_DIR" "s3://mybucket/backups/$(date +%Y/%m/%d)/"

# Cleanup old backups (keep 7 days)
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +7 -delete
find "$BACKUP_DIR" -name "*.sql" -mtime +7 -delete

echo "Backup completed: $DATE"

4. Auto-scaling Configuration

# docker-compose.scale.yml
version: "3.8"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

  app:
    image: myapp:latest
    deploy:
      replicas: 5
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        max_replicas_per_node: 2
      resources:
        limits:
          memory: 1G
          cpus: "1"
        reservations:
          memory: 512M
          cpus: "0.5"

🎯 Environment-specific Configurations

Development Environment

# docker-compose.dev.yml
version: "3.8"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    volumes:
      - ./nginx/dev.conf:/etc/nginx/nginx.conf
      - ./app:/usr/share/nginx/html
    environment:
      - NGINX_LOG_LEVEL=debug

  postgres:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_HOST_AUTH_METHOD=trust # Dev only!
    ports:
      - "5432:5432" # Expose for dev tools

Staging Environment

# docker-compose.staging.yml
version: "3.8"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    environment:
      - ENVIRONMENT=staging
    labels:
      - "staging=true"

  postgres:
    image: nqdev/postgres-pgagent:latest
    environment:
      - POSTGRES_HOST_AUTH_METHOD=scram-sha-256
    # No port exposure for security

Production Environment

# docker-compose.prod.yml
version: "3.8"

x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "100m"
    max-file: "3"

services:
  nginx:
    image: nqdev/nginx:1.27.2-alpine-vhs-custom-1.5.1
    logging: *default-logging
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 1G
          cpus: "1"
    secrets:
      - ssl_cert
      - ssl_key

secrets:
  ssl_cert:
    external: true
  ssl_key:
    external: true

📚 Additional Resources

Monitoring Tools

Security Resources


NQDEV Team - Platform Engineering
📧 quynh@nhquydev.net | 🌐 nhquydev.net