# ================================================== # OCDP Docker Compose (complete local stack) # ================================================== # 使用方式: # docker compose up --build # # 说明: # - 本文件是本地部署主入口,包含 PostgreSQL、Backend、前端构建和 Nginx。 # - 默认使用高位宿主端口,避免和本机其他项目冲突。 # - Nginx 统一监听容器内 80/443(默认映射 WEB_HTTP_PORT=18080、WEB_HTTPS_PORT=18443), # 根据路径转发:/api/* → backend,其他路径 → 前端静态文件。 # ================================================== services: # -------------------------------------------------- # PostgreSQL 数据库 # -------------------------------------------------- postgres: image: postgres:17-alpine container_name: ocdp-postgres restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB:-ocdp} POSTGRES_USER: ${POSTGRES_USER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C" ports: - "${POSTGRES_PORT:-15432}:5432" volumes: - postgres_data:/var/lib/postgresql/data - ./backend/scripts/init-db.sql:/docker-entrypoint-initdb.d/01-init.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-ocdp}"] interval: 10s timeout: 5s retries: 30 start_period: 60s networks: - ocdp-network # -------------------------------------------------- # Backend API # -------------------------------------------------- backend: build: context: ./backend dockerfile: Dockerfile args: GOPROXY: ${GOPROXY:-https://goproxy.cn,direct} GOSUMDB: ${GOSUMDB:-sum.golang.google.cn} image: ocdp-backend:latest container_name: ocdp-backend restart: unless-stopped env_file: - path: ./.env required: false format: raw environment: ADAPTER_MODE: ${ADAPTER_MODE:-production} PORT: 8080 JWT_SECRET: ${JWT_SECRET:-change-me-in-production} ENCRYPTION_KEY: ${ENCRYPTION_KEY:-change-me-32-bytes-long-key-here} DATABASE_URL: postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@postgres:5432/${POSTGRES_DB:-ocdp}?sslmode=disable ports: - "${BACKEND_PORT:-18081}:8080" volumes: - ./config:/app/config:ro - ./data:/app/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 5 start_period: 30s depends_on: postgres: condition: service_healthy networks: - ocdp-network # -------------------------------------------------- # 构建前端静态资源 (一次性 Job) # -------------------------------------------------- frontend-build: image: node:20-alpine container_name: ocdp-frontend-build init: true working_dir: /app restart: "no" environment: NODE_ENV: production NPM_CONFIG_PRODUCTION: "false" # ensure devDependencies (tsc, vite) are installed for build # 默认通过 Nginx 代理到 backend -> /api/v1 VITE_API_BASE_URL: ${VITE_API_BASE_URL:-/api/v1} FILE_OWNER_UID: ${FILE_OWNER_UID:-1000} FILE_OWNER_GID: ${FILE_OWNER_GID:-1000} command: > sh -c " set -eux; npm ci; rm -rf node_modules/.tmp; npm run build; mkdir -p /build; rm -rf /build/*; cp -R dist/. /build/; if [ -d dist ]; then chown -R "$$FILE_OWNER_UID:$$FILE_OWNER_GID" dist; fi; if [ -d /build ]; then chown -R "$$FILE_OWNER_UID:$$FILE_OWNER_GID" /build; fi " volumes: - ./frontend:/app - frontend_node_modules:/app/node_modules - frontend_dist:/build networks: - ocdp-network # -------------------------------------------------- # Nginx - 静态文件 + /api 反向代理统一入口 # -------------------------------------------------- nginx: image: nginx:1.27-alpine container_name: ocdp-nginx restart: unless-stopped depends_on: frontend-build: condition: service_completed_successfully backend: condition: service_healthy ports: - "${WEB_HTTP_PORT:-18080}:80" - "${WEB_HTTPS_PORT:-18443}:443" volumes: - frontend_dist:/usr/share/nginx/html:ro - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro - ./infra/nginx/certs:/etc/nginx/certs:ro healthcheck: test: ["CMD-SHELL", "wget -qO- http://127.0.0.1/healthz || exit 1"] interval: 30s timeout: 5s retries: 5 networks: - ocdp-network # ================================================== # Networks # ================================================== networks: ocdp-network: driver: bridge name: ocdp-network # ================================================== # Volumes # ================================================== volumes: postgres_data: name: ocdp-postgres-data frontend_dist: driver: local frontend_node_modules: driver: local