version: '3.8' services: # ==================== 应用服务 ==================== app: build: context: . dockerfile: Dockerfile image: carrotskin/backend:latest container_name: carrotskin-backend restart: unless-stopped ports: - "${APP_PORT:-8080}:8080" environment: # 站点配置 - SITE_NAME=${SITE_NAME:-CarrotSkin} - SITE_DESCRIPTION=${SITE_DESCRIPTION:-一个优秀的Minecraft皮肤站} - REGISTRATION_ENABLED=${REGISTRATION_ENABLED:-true} - DEFAULT_AVATAR=${DEFAULT_AVATAR:-} # 用户限制配置 - MAX_TEXTURES_PER_USER=${MAX_TEXTURES_PER_USER:-50} - MAX_PROFILES_PER_USER=${MAX_PROFILES_PER_USER:-5} # 积分配置 - CHECKIN_REWARD=${CHECKIN_REWARD:-10} - TEXTURE_DOWNLOAD_REWARD=${TEXTURE_DOWNLOAD_REWARD:-1} # 服务器配置 - SERVER_PORT=:8080 - SERVER_MODE=${SERVER_MODE:-release} - SERVER_SWAGGER_ENABLED=${SERVER_SWAGGER_ENABLED:-true} # 数据库配置 - DATABASE_DRIVER=postgres - DATABASE_HOST=postgres - DATABASE_PORT=5432 - DATABASE_USERNAME=carrotskin - DATABASE_PASSWORD=${DATABASE_PASSWORD:-carrotskin123} - DATABASE_NAME=carrotskin - DATABASE_SSL_MODE=disable - DATABASE_TIMEZONE=Asia/Shanghai # Redis 配置 - REDIS_HOST=redis - REDIS_PORT=6379 - REDIS_PASSWORD=${REDIS_PASSWORD:-} - REDIS_DATABASE=0 # JWT 配置 - JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production} - JWT_EXPIRE_HOURS=168 # 存储配置 (RustFS S3兼容) - RUSTFS_ENDPOINT=${RUSTFS_ENDPOINT:-rustfs:9000} - RUSTFS_PUBLIC_URL=${RUSTFS_PUBLIC_URL:-http://localhost:9000} - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY:-rustfsadmin} - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY:-rustfsadmin123} - RUSTFS_USE_SSL=${RUSTFS_USE_SSL:-false} - RUSTFS_BUCKET_TEXTURES=${RUSTFS_BUCKET_TEXTURES:-carrot-skin-textures} - RUSTFS_BUCKET_AVATARS=${RUSTFS_BUCKET_AVATARS:-carrot-skin-avatars} # 安全配置 - SECURITY_ALLOWED_ORIGINS=${SECURITY_ALLOWED_ORIGINS:-*} - SECURITY_ALLOWED_DOMAINS=${SECURITY_ALLOWED_DOMAINS:-localhost,127.0.0.1} # 邮件配置 - EMAIL_ENABLED=${EMAIL_ENABLED:-false} - EMAIL_SMTP_HOST=${EMAIL_SMTP_HOST:-} - EMAIL_SMTP_PORT=${EMAIL_SMTP_PORT:-587} - EMAIL_USERNAME=${EMAIL_USERNAME:-} - EMAIL_PASSWORD=${EMAIL_PASSWORD:-} - EMAIL_FROM_NAME=${EMAIL_FROM_NAME:-CarrotSkin} depends_on: postgres: condition: service_healthy redis: condition: service_healthy networks: - carrotskin-network healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/api/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s # ==================== PostgreSQL 数据库 ==================== postgres: image: postgres:16-alpine container_name: carrotskin-postgres restart: unless-stopped environment: - POSTGRES_USER=carrotskin - POSTGRES_PASSWORD=${DATABASE_PASSWORD:-carrotskin123} - POSTGRES_DB=carrotskin - PGDATA=/var/lib/postgresql/data/pgdata volumes: - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" networks: - carrotskin-network healthcheck: test: ["CMD-SHELL", "pg_isready -U carrotskin -d carrotskin"] interval: 10s timeout: 5s retries: 5 start_period: 10s # ==================== Redis 缓存 ==================== redis: image: redis:7-alpine container_name: carrotskin-redis restart: unless-stopped command: > redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru ${REDIS_PASSWORD:+--requirepass ${REDIS_PASSWORD}} volumes: - redis-data:/data ports: - "6379:6379" networks: - carrotskin-network healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 5s # ==================== RustFS 对象存储==================== rustfs: image: ghcr.io/rustfs/rustfs:latest container_name: carrotskin-rustfs restart: unless-stopped command: > server --address 0.0.0.0:9000 --console-address 0.0.0.0:9001 --access-key ${RUSTFS_ACCESS_KEY:-rustfsadmin} --secret-key ${RUSTFS_SECRET_KEY:-rustfsadmin123} --data /data volumes: - rustfs-data:/data ports: - "9000:9000" # S3 API 端口 - "9001:9001" # 控制台端口 networks: - carrotskin-network healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9000/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s profiles: - storage # 使用 --profile storage 启动 # RustFS 初始化服务 - 自动创建存储桶 rustfs-init: image: minio/mc:latest container_name: carrotskin-rustfs-init depends_on: rustfs: condition: service_healthy entrypoint: > /bin/sh -c " echo '等待 RustFS 启动...'; sleep 5; mc alias set myrustfs http://rustfs:9000 $${RUSTFS_ACCESS_KEY} $${RUSTFS_SECRET_KEY}; echo '创建材质存储桶...'; mc mb myrustfs/$${RUSTFS_BUCKET_TEXTURES} --ignore-existing; mc anonymous set download myrustfs/$${RUSTFS_BUCKET_TEXTURES}; echo '创建头像存储桶...'; mc mb myrustfs/$${RUSTFS_BUCKET_AVATARS} --ignore-existing; mc anonymous set download myrustfs/$${RUSTFS_BUCKET_AVATARS}; echo '存储桶创建完成: $${RUSTFS_BUCKET_TEXTURES}, $${RUSTFS_BUCKET_AVATARS}'; " environment: - RUSTFS_ACCESS_KEY=${RUSTFS_ACCESS_KEY:-rustfsadmin} - RUSTFS_SECRET_KEY=${RUSTFS_SECRET_KEY:-rustfsadmin123} - RUSTFS_BUCKET_TEXTURES=${RUSTFS_BUCKET_TEXTURES:-carrot-skin-textures} - RUSTFS_BUCKET_AVATARS=${RUSTFS_BUCKET_AVATARS:-carrot-skin-avatars} networks: - carrotskin-network profiles: - storage # ==================== 数据卷 ==================== volumes: postgres-data: driver: local redis-data: driver: local rustfs-data: driver: local # ==================== 网络 ==================== networks: carrotskin-network: driver: bridge