docker-compose.yml
Rama main · réplica de lectura del repositorio original.
# Open ACE - AI Computing Explorer - Docker Compose Configuration
# For production deployment with PostgreSQL database
#
# ============================================================================
# DEPLOYMENT MODES
# ============================================================================
#
# 🚀 Single-User Mode (DEFAULT):
# This is the default mode. Container runs as non-root (uid 1000).
# No additional configuration needed.
#
# Quick start:
# docker compose up -d
# # Access http://localhost:19888
#
# 👥 Multi-User Workspace Mode:
# Enables per-user workspace isolation. Container MUST run as root to create
# system users (useradd, chown, sudo -u operations).
#
# ⚠️ IMPORTANT: Do NOT modify this file to enable multi-user mode!
# Use the dedicated overlay file instead:
#
# Option 1 - One-click script (RECOMMENDED):
# ./scripts/start-multi-user.sh
#
# Option 2 - Docker Compose overlay:
# docker compose -f docker-compose.yml -f docker-compose.multi-user.yml up -d
#
# Why not modify this file?
# - Security: Default config follows least-privilege principle (non-root)
# - Safety: Entrypoint validates config consistency and fails fast on errors
# - Best practice: Overlay pattern is the official Docker Compose recommendation
#
# 📦 Pull pre-built image from Docker Hub:
# docker compose up -d
#
# 🔒 HTTPS reverse proxy:
# Follow docs/guide/NGINX.md
#
# 🔧 Developer build (for local testing):
# docker build -t open-ace:dev --target production .
# IMAGE_NAME=open-ace:dev docker compose up -d
#
# ============================================================================
# MULTI-USER MODE DETAILS
# ============================================================================
#
# The docker-compose.multi-user.yml overlay adds:
# - user: "0" # Run container as root
# - WORKSPACE_ISOLATION_BACKEND=plain # One OS account per user (#3446)
# - OPENACE_ALLOW_ROOT_MULTI_USER=1 # Explicit root authorization
# - OPENACE_CONFIG_DIR=/home/open-ace/.open-ace # Config persistence
#
# For multi-user deployment guide, see:
# docs/guide/MULTI_USER_WORKSPACE.md
#
# ============================================================================
services:
# ===========================================================================
# Main Application
# ===========================================================================
open-ace:
# One-click deploy: docker compose up -d --build
# Pull pre-built image: docker compose up -d (without --build)
build:
context: .
dockerfile: Dockerfile
target: production
args:
# Base image registry. Override for networks where Docker Hub is
# unreachable (e.g. mainland China): BASE_REGISTRY=docker.m.daocloud.io
BASE_REGISTRY: ${BASE_REGISTRY:-docker.io}
image: ${IMAGE_NAME:-ghcr.io/open-ace/open-ace:latest}
container_name: open-ace
restart: unless-stopped
ports:
- "${PORT:-19888}:19888"
# Multi-user workspace: expose port range for qwen-code-webui instances
- "${WORKSPACE_PORT_RANGE_START:-3100}-${WORKSPACE_PORT_RANGE_END:-3200}:${WORKSPACE_PORT_RANGE_START:-3100}-${WORKSPACE_PORT_RANGE_END:-3200}"
environment:
- PYTHONUNBUFFERED=1
# Secrets: empty by default — docker-entrypoint.sh auto-generates strong
# random values on first start if unset (see ensure_secret_env). For
# production, set them explicitly in .env (see .env.example).
- SECRET_KEY=${SECRET_KEY:-}
- OPENACE_ENCRYPTION_KEY=${OPENACE_ENCRYPTION_KEY:-}
- UPLOAD_AUTH_KEY=${UPLOAD_AUTH_KEY:-}
# Security mode (Issue #2331): Explicit configuration required for production
# For one-click local dev: defaults to development
# For production: set explicitly in .env: OPENACE_SECURITY_MODE=production
# Valid values: production (strict), pilot (trial), development (local dev)
- OPENACE_SECURITY_MODE=${OPENACE_SECURITY_MODE:-development}
# Database (Issue #1893): Development mode uses dev-password-change-in-production.
# Production mode requires explicit strong password via DB_PASSWORD env var.
- DATABASE_URL=postgresql://${DB_USER:-ace}:${DB_PASSWORD:-dev-password-change-in-production}@postgres:5432/${DB_NAME:-ace}
# Issue #3095: Pass DB_PASSWORD as standalone env var for security baseline check.
# The entrypoint check_security_baseline() reads DB_PASSWORD directly, not from DATABASE_URL.
- DB_PASSWORD=${DB_PASSWORD:-}
# Multi-user Workspace
- WORKSPACE_ISOLATION_BACKEND=${WORKSPACE_ISOLATION_BACKEND:-shared}
# Workspace base directory (users' projects stored under /workspace/<username>/)
- WORKSPACE_BASE_DIR=/workspace
# Data fetch: container runs as root, use venv Python (Issue #1121)
- FETCH_USE_SUDO=false
# Server IP for URL configuration (Issue #1306)
# Auto-detected from hostname -I if not set
# Override via .env file if needed (e.g., SERVER_IP=192.168.1.169)
- SERVER_IP=${SERVER_IP:-}
# Pass CI environment variable for entrypoint CI detection (Issue #3109)
- CI=${CI:-}
# #3237: must match the scheduler service exactly.
- OPENACE_AGENT_STATE_ROOT=/var/lib/openace/agent-state
# Allow container to access host network (Issue #1260)
# Required for host.docker.internal on Linux Docker 20.10+
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
# Config: Use named volume for persistence (Issue #1260)
# Entrypoint will auto-generate config.json if not exists.
# Mount under the non-root open-ace user's home (/home/open-ace) so uid
# 1000 (the image default, Dockerfile `USER 1000`) can write to it. The
# directory is pre-created and chowned in the Dockerfile so Docker's named
# volume init copies uid-1000 ownership into the volume on first run.
# Users can mount custom config: - ./my-config.json:/home/open-ace/.open-ace/config.json:ro
- config-data:/home/open-ace/.open-ace
- ./logs:/app/logs
# Workspace data: per-user project directories, persisted across restarts
- workspace-data:/workspace
# #3237: carried CLI transcripts. SHARED with the scheduler service on
# purpose — the scheduler writes them, but the stop/delete/override
# routes that purge them run here. Two separate volumes meant those
# purges deleted an unrelated empty directory while the real transcripts
# were retained forever.
- agent-state:/var/lib/openace
# SSH credentials for remote host access (optional, uncomment if needed)
# SECURITY WARNING: Mounting SSH keys exposes private keys to container processes
# Recommend using dedicated SSH keys with restricted commands in authorized_keys
# - ~/.ssh:/root/.ssh:ro
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:19888/readyz')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- open-ace-network
depends_on:
postgres:
condition: service_healthy
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ===========================================================================
# Scheduler Worker (Issue #2187)
# ===========================================================================
# Independent scheduler process for background tasks.
# Uses leader election to ensure only one active scheduler.
# For single-instance development, omit this service.
scheduler:
image: ${IMAGE_NAME:-ghcr.io/open-ace/open-ace:latest}
container_name: open-ace-scheduler
restart: unless-stopped
profiles:
- scheduler
environment:
- FLASK_ENV=production
- PYTHONUNBUFFERED=1
- SCHEDULER_MODE=scheduler
# Issue #3133: the entrypoint treats SCHEDULER_MODE=scheduler as a
# production-capable path and requires an explicit OPENACE_SECURITY_MODE,
# so starting the scheduler from this base file alone crashed on boot.
# Default to development, matching the app service above; production
# deployments must set OPENACE_SECURITY_MODE explicitly in .env (the
# multi-user overlay already defaults it to production).
- OPENACE_SECURITY_MODE=${OPENACE_SECURITY_MODE:-development}
- SECRET_KEY=${SECRET_KEY:-}
- OPENACE_ENCRYPTION_KEY=${OPENACE_ENCRYPTION_KEY:-}
- UPLOAD_AUTH_KEY=${UPLOAD_AUTH_KEY:-}
- DATABASE_URL=postgresql://${DB_USER:-ace}:${DB_PASSWORD:-dev-password-change-in-production}@postgres:5432/${DB_NAME:-ace}
# Issue #3095: Pass DB_PASSWORD as standalone env var for security baseline check.
- DB_PASSWORD=${DB_PASSWORD:-}
- SCHEDULER_HEARTBEAT_INTERVAL=${SCHEDULER_HEARTBEAT_INTERVAL:-10}
- SCHEDULER_HEARTBEAT_TIMEOUT=${SCHEDULER_HEARTBEAT_TIMEOUT:-60}
- SCHEDULER_LOCK_TIMEOUT=${SCHEDULER_LOCK_TIMEOUT:-1800}
- SCHEDULER_METRICS_PORT=9090
# #3237: must match the app service exactly.
- OPENACE_AGENT_STATE_ROOT=/var/lib/openace/agent-state
volumes:
- config-data:/home/open-ace/.open-ace
- ./logs:/app/logs
- workspace-data:/workspace
# #3237: the same volume the app service mounts, at the same path.
- agent-state:/var/lib/openace
# Issue #3455: under compose this service runs the same web entrypoint as
# the app service (SCHEDULER_MODE=scheduler starts the scheduler services
# in-process); only the standalone app/scheduler_worker.py used by the k8s
# deployment serves :9090/metrics. Probe /readyz on the port this
# container actually serves, like the open-ace service above.
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:19888/readyz')"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
- open-ace-network
depends_on:
postgres:
condition: service_healthy
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ===========================================================================
# PostgreSQL Database (required for production)
# ===========================================================================
postgres:
# Same registry override as the app build (BASE_REGISTRY). When unset this
# resolves to docker.io's postgres:15-alpine via the library/ auto-prefix.
image: ${BASE_REGISTRY:-docker.io}/postgres:15-alpine
container_name: open-ace-postgres
restart: unless-stopped
environment:
- POSTGRES_USER=${DB_USER:-ace}
# Issue #1893: Development mode uses a fixed dev password for convenience.
# Production mode requires explicit strong password via DB_PASSWORD env var.
# The entrypoint will warn on dev password and reject in production mode.
- POSTGRES_PASSWORD=${DB_PASSWORD:-dev-password-change-in-production}
- POSTGRES_DB=${DB_NAME:-ace}
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- open-ace-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-ace} -d ${DB_NAME:-ace}"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# =============================================================================
# Networks
# =============================================================================
networks:
open-ace-network:
driver: bridge
# =============================================================================
# Volumes
# =============================================================================
volumes:
# #3237: carried CLI transcripts, shared by the app and scheduler services.
agent-state:
driver: local
config-data:
driver: local
postgres-data:
driver: local
workspace-data:
driver: local