services: postgres: image: postgres:17-alpine environment: POSTGRES_DB: ${POSTGRES_DB:-open_ai_canvas} POSTGRES_USER: ${POSTGRES_USER:-open_ai_canvas} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?请先运行一键部署脚本生成数据库密码} volumes: - ${CANVAS_POSTGRES_DATA_PATH:-postgres-data}:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped redis: image: redis:7.4-alpine command: ["redis-server", "--appendonly", "yes", "--appendfsync", "everysec"] volumes: - ${CANVAS_REDIS_DATA_PATH:-redis-data}:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 restart: unless-stopped migrate: image: ${CANVAS_BACKEND_IMAGE:?请先配置 CANVAS_BACKEND_IMAGE(必须包含镜像 digest)} entrypoint: ["migrate-schema"] command: ["up"] environment: CANVAS_BACKEND_DATA_DIR: /data CANVAS_DATABASE_DRIVER: postgres DATABASE_URL: ${DATABASE_URL:?请先运行一键部署脚本生成数据库连接} depends_on: postgres: condition: service_healthy yingce-agent: # 让旧更新器也能完成本次升级;新版更新器在后续更新中会固定为镜像 digest。 image: ${CANVAS_YINGCE_AGENT_IMAGE:-ghcr.io/ddcat-ai/open-ai-canvas-yingce-agent:${CANVAS_IMAGE_TAG:?请先配置 CANVAS_IMAGE_TAG}} environment: YINGCE_AGENT_TOKEN: ${YINGCE_AGENT_TOKEN:-${CANVAS_UPDATER_TOKEN:?请先配置 YINGCE_AGENT_TOKEN}} MAX_CONCURRENT_SESSIONS: ${YINGCE_AGENT_MAX_SESSIONS:-30} NODE_MAX_OLD_SPACE_SIZE: ${YINGCE_AGENT_NODE_MEMORY_MB:-512} healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8081/healthz"] interval: 10s timeout: 3s retries: 10 start_period: 10s restart: unless-stopped backend: image: ${CANVAS_BACKEND_IMAGE:?请先配置 CANVAS_BACKEND_IMAGE(必须包含镜像 digest)} environment: CANVAS_BACKEND_ADDR: ":8080" CANVAS_BACKEND_DATA_DIR: /data CANVAS_AUTO_MIGRATE: "false" CANVAS_SHUTDOWN_TIMEOUT: ${CANVAS_SHUTDOWN_TIMEOUT:-10m} CANVAS_DATABASE_DRIVER: postgres DATABASE_URL: ${DATABASE_URL:?请先运行一键部署脚本生成数据库连接} REDIS_URL: redis://redis:6379/0 CANVAS_WORKER_CONCURRENCY: ${CANVAS_WORKER_CONCURRENCY:-3} CANVAS_CHANNEL_CONCURRENCY: ${CANVAS_CHANNEL_CONCURRENCY:-3} CANVAS_REGISTRATION_ENABLED: ${CANVAS_REGISTRATION_ENABLED:-false} CANVAS_ALLOW_PRIVATE_UPSTREAMS: ${CANVAS_ALLOW_PRIVATE_UPSTREAMS:-false} CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS: ${CANVAS_ALLOWED_PRIVATE_UPSTREAM_HOSTS:-} CANVAS_CORS_ORIGINS: ${CANVAS_CORS_ORIGINS:-} CANVAS_PUBLIC_BASE_URL: ${CANVAS_PUBLIC_BASE_URL:-} CANVAS_UPDATER_SOCKET: /run/open-ai-canvas-updater/updater.sock CANVAS_UPDATER_TOKEN: ${CANVAS_UPDATER_TOKEN:-} YINGCE_AGENT_URL: http://yingce-agent:8081 YINGCE_AGENT_TOKEN: ${YINGCE_AGENT_TOKEN:-${CANVAS_UPDATER_TOKEN:?请先配置 YINGCE_AGENT_TOKEN}} YINGCE_AGENT_BRIDGE_HOST: backend CANVAS_LOG_LEVEL: ${CANVAS_LOG_LEVEL:-info} CANVAS_LOG_FORMAT: ${CANVAS_LOG_FORMAT:-text} GIN_MODE: release volumes: - ${CANVAS_DATA_PATH:-backend-data}:/data - ${CANVAS_UPDATER_SOCKET_DIR:-/run/open-ai-canvas-updater}:/run/open-ai-canvas-updater depends_on: postgres: condition: service_healthy redis: condition: service_healthy migrate: condition: service_completed_successfully yingce-agent: condition: service_healthy restart: unless-stopped stop_grace_period: ${CANVAS_SHUTDOWN_TIMEOUT:-10m} web: image: ${CANVAS_WEB_IMAGE:?请先配置 CANVAS_WEB_IMAGE(必须包含镜像 digest)} ports: - "${CANVAS_HTTP_PORT:-3000}:3000" volumes: # Keep hashed chunks from the current and previous web releases for old tabs. - ${CANVAS_WEB_DATA_PATH:-web-data}:/usr/share/nginx/html depends_on: backend: condition: service_healthy restart: unless-stopped volumes: backend-data: postgres-data: redis-data: web-data: