# docker-compose.ha.yml # HA 覆盖配置(建议与 docker-compose.yml 叠加使用) # # 启动示例: # docker compose -f docker-compose.yml -f docker-compose.ha.yml up -d services: # ============================================== # 应用服务 Sentinel 配置覆盖 # ============================================== backend: environment: - DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-dreamweaver}:${POSTGRES_PASSWORD:-dreamweaver_password}@db:5432/${POSTGRES_DB:-dreamweaver_db} - REDIS_SENTINEL_ENABLED=true - REDIS_SENTINEL_NODES=redis-sentinel-1:26379,redis-sentinel-2:26379,redis-sentinel-3:26379 - REDIS_SENTINEL_MASTER_NAME=mymaster - REDIS_SENTINEL_DB=0 - REDIS_SENTINEL_SOCKET_TIMEOUT=0.5 backend-admin: environment: - DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-dreamweaver}:${POSTGRES_PASSWORD:-dreamweaver_password}@db:5432/${POSTGRES_DB:-dreamweaver_db} - REDIS_SENTINEL_ENABLED=true - REDIS_SENTINEL_NODES=redis-sentinel-1:26379,redis-sentinel-2:26379,redis-sentinel-3:26379 - REDIS_SENTINEL_MASTER_NAME=mymaster - REDIS_SENTINEL_DB=0 - REDIS_SENTINEL_SOCKET_TIMEOUT=0.5 worker: environment: - DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-dreamweaver}:${POSTGRES_PASSWORD:-dreamweaver_password}@db:5432/${POSTGRES_DB:-dreamweaver_db} - REDIS_SENTINEL_ENABLED=true - REDIS_SENTINEL_NODES=redis-sentinel-1:26379,redis-sentinel-2:26379,redis-sentinel-3:26379 - REDIS_SENTINEL_MASTER_NAME=mymaster - REDIS_SENTINEL_DB=0 - REDIS_SENTINEL_SOCKET_TIMEOUT=0.5 celery-beat: environment: - DATABASE_URL=postgresql+asyncpg://${POSTGRES_USER:-dreamweaver}:${POSTGRES_PASSWORD:-dreamweaver_password}@db:5432/${POSTGRES_DB:-dreamweaver_db} - REDIS_SENTINEL_ENABLED=true - REDIS_SENTINEL_NODES=redis-sentinel-1:26379,redis-sentinel-2:26379,redis-sentinel-3:26379 - REDIS_SENTINEL_MASTER_NAME=mymaster - REDIS_SENTINEL_DB=0 - REDIS_SENTINEL_SOCKET_TIMEOUT=0.5 # ============================================== # PostgreSQL 主库(覆盖默认 db) # ============================================== db: image: postgres:15-alpine container_name: dreamweaver_db_primary restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-dreamweaver} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dreamweaver_password} POSTGRES_DB: ${POSTGRES_DB:-dreamweaver_db} command: - postgres - -c - wal_level=replica - -c - max_wal_senders=10 - -c - max_replication_slots=10 - -c - hot_standby=on - -c - hba_file=/etc/postgresql/pg_hba.conf ports: - "52432:5432" volumes: - postgres_primary_data:/var/lib/postgresql/data - ./ops/postgres-ha/pg_hba.conf:/etc/postgresql/pg_hba.conf:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dreamweaver} -d ${POSTGRES_DB:-dreamweaver_db}"] interval: 10s timeout: 5s retries: 10 # ============================================== # PostgreSQL 从库(基于 pg_basebackup 初始化) # ============================================== db-replica: image: postgres:15-alpine container_name: dreamweaver_db_replica restart: unless-stopped user: "postgres" environment: POSTGRES_USER: ${POSTGRES_USER:-dreamweaver} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-dreamweaver_password} POSTGRES_DB: ${POSTGRES_DB:-dreamweaver_db} PGDATA: /var/lib/postgresql/data depends_on: db: condition: service_healthy volumes: - postgres_replica_data:/var/lib/postgresql/data command: - /bin/sh - -ec - | if [ ! -s "$$PGDATA/PG_VERSION" ]; then echo "Initializing replica from primary..." until pg_isready -h db -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"; do sleep 2; done export PGPASSWORD="$$POSTGRES_PASSWORD" rm -rf "$$PGDATA"/* pg_basebackup -h db -D "$$PGDATA" -U "$$POSTGRES_USER" -Fp -Xs -P -R fi chmod 700 "$$PGDATA" exec postgres -c hot_standby=on healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-dreamweaver} -d ${POSTGRES_DB:-dreamweaver_db} && psql -U ${POSTGRES_USER:-dreamweaver} -d ${POSTGRES_DB:-dreamweaver_db} -tAc 'select pg_is_in_recovery();' | grep -q t", ] interval: 10s timeout: 5s retries: 10 # ============================================== # PostgreSQL 备份任务(每日一次,保留 7 天) # ============================================== postgres-backup: image: postgres:15-alpine container_name: dreamweaver_postgres_backup restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER:-dreamweaver} POSTGRES_DB: ${POSTGRES_DB:-dreamweaver_db} PGPASSWORD: ${POSTGRES_PASSWORD:-dreamweaver_password} BACKUP_INTERVAL_SECONDS: ${BACKUP_INTERVAL_SECONDS:-86400} depends_on: db: condition: service_healthy volumes: - postgres_backups:/backups command: - /bin/sh - -ec - | while true; do ts=$$(date +%Y%m%d_%H%M%S); pg_dump -h db -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" -F c -f "/backups/dreamweaver_$${ts}.dump"; find /backups -type f -name '*.dump' -mtime +7 -delete; sleep "$$BACKUP_INTERVAL_SECONDS"; done # ============================================== # Redis 主库(覆盖默认 redis) # ============================================== redis: image: redis:7-alpine container_name: dreamweaver_redis_master restart: unless-stopped ports: - "52379:6379" volumes: - redis_master_data:/data command: ["redis-server", "--appendonly", "yes", "--protected-mode", "no"] networks: default: ipv4_address: 172.29.0.10 healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 # ============================================== # Redis 从库 # ============================================== redis-replica: image: redis:7-alpine container_name: dreamweaver_redis_replica restart: unless-stopped depends_on: redis: condition: service_healthy volumes: - redis_replica_data:/data command: [ "redis-server", "--appendonly", "yes", "--protected-mode", "no", "--replicaof", "172.29.0.10", "6379", ] networks: default: ipv4_address: 172.29.0.11 healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 # ============================================== # Redis Sentinel (3 节点) # ============================================== redis-sentinel-1: image: redis:7-alpine container_name: dreamweaver_redis_sentinel_1 restart: unless-stopped ports: - "52631:26379" depends_on: redis: condition: service_healthy redis-replica: condition: service_healthy networks: default: ipv4_address: 172.29.0.21 command: - /bin/sh - -ec - | cat > /tmp/sentinel.conf < /tmp/sentinel.conf < /tmp/sentinel.conf <