penpot/docker/devenv/docker-compose.main.yml
Codex 6fc03f633a 🐳 Run parallel devenv instances against shared infra
Add support for running N parallel devenv instances under separate compose
projects sharing Postgres, MinIO, mailer, and LDAP. Each instance has its
own main container, Valkey, source checkout, tmux session, and host port
range offset by 10000 (3449 -> 13449 -> 23449, etc.).

./manage.sh run-devenv-agentic --n-instances N reconciles the running set
to exactly {ws0..ws(N-1)}: missing instances are created (workspace sync
from the live repo via git ls-files + per-instance env-file generation
under docker/devenv/instances/ + detached tmux startup), surplus instances
are stopped highest-first via compose down (never -v), already-running
instances are left untouched. ws0 binds the live repo at PWD; ws1+ are
scratch clones under ~/.penpot/penpot_workspaces/.

Backend workers (enable-backend-worker) are gated on PENPOT_BACKEND_WORKER
in backend/scripts/_env; ws1+ overlays disable them so async-task
notifications stay bound to a single Valkey Pub/Sub instance.

Compose helpers wrap docker compose with env -i so per-instance overlay
--env-file actually overrides defaults.env -- without the strip, the shell
env from sourcing defaults.env at startup would shadow the overlay (Compose
gives shell precedence over --env-file).

Other:
- Drop network aliases (- main, - redis); use container_name for
  cross-container DNS so multiple instances on the shared network don't
  fight over the same DNS name.
- Pin volume names via name: (PENPOT_*_VOLUME) so volumes survive project
  renames; ws0 keeps the pre-existing physical names (penpotdev_*).
- Remove cross-project depends_on from main.yml (postgres/minio-setup now
  live in penpotdev-infra); manage.sh ensure-infra-up docker-waits on the
  minio-setup one-shot.
- Strict arg parsing in run-devenv / run-devenv-agentic; --n-instances 0
  rejected.
- Remove unused Host-matched server block from the Caddyfile.

Memory mem:devenv/core and developer docs updated.

Co-authored-by: Codex <codex@openai.com>
2026-06-02 13:10:42 +03:00

107 lines
3.5 KiB
YAML

networks:
default:
name: penpot_shared
external: true
volumes:
user_data:
name: ${PENPOT_USER_DATA_VOLUME}
valkey_data:
name: ${PENPOT_VALKEY_DATA_VOLUME}
services:
main:
privileged: true
image: "penpotapp/devenv:latest"
build:
context: "."
container_name: "${PENPOT_MAIN_CONTAINER_NAME}"
stop_signal: SIGINT
# postgres / minio / minio-setup live in the penpotdev-infra compose
# project and cannot be referenced via depends_on across projects.
# manage.sh waits for infra readiness before bringing main up.
depends_on:
redis:
condition: service_started
volumes:
- "user_data:/home/penpot/"
- "${PENPOT_SOURCE_PATH}:/home/penpot/penpot:z"
ports:
# Host ports are instance-specific; container ports stay fixed.
- ${PENPOT_PUBLIC_HTTP_PORT}:3449
- ${PENPOT_PUBLIC_HTTP_PORT}:3449/udp
# MCP
- ${PENPOT_MCP_SERVER_PORT}:4401
- ${PENPOT_MCP_REPL_PORT}:4403
# Serena MCP server (agentic mode only). Internal ports fixed by Serena.
- ${SERENA_EXTERNAL_PORT}:14281
- ${SERENA_DASHBOARD_EXTERNAL_PORT}:24282
environment:
- EXTERNAL_UID=${CURRENT_USER_ID}
# SMTP setup (shared infra service; identical across instances)
- PENPOT_SMTP_ENABLED=true
- PENPOT_SMTP_DEFAULT_FROM=no-reply@example.com
- PENPOT_SMTP_DEFAULT_REPLY_TO=no-reply@example.com
- PENPOT_SMTP_HOST=mailer
- PENPOT_SMTP_PORT=1025
- PENPOT_SMTP_USERNAME=
- PENPOT_SMTP_PASSWORD=
- PENPOT_SMTP_SSL=false
- PENPOT_SMTP_TLS=false
# LDAP setup (shared infra service; identical across instances)
- PENPOT_LDAP_HOST=ldap
- PENPOT_LDAP_PORT=10389
- PENPOT_LDAP_SSL=false
- PENPOT_LDAP_STARTTLS=false
- PENPOT_LDAP_BASE_DN=ou=people,dc=planetexpress,dc=com
- PENPOT_LDAP_BIND_DN=cn=admin,dc=planetexpress,dc=com
- PENPOT_LDAP_BIND_PASSWORD=GoodNewsEveryone
- PENPOT_LDAP_ATTRS_USERNAME=uid
- PENPOT_LDAP_ATTRS_EMAIL=mail
- PENPOT_LDAP_ATTRS_FULLNAME=cn
- PENPOT_LDAP_ATTRS_PHOTO=jpegPhoto
# Per-instance runtime config. Defaults live in defaults.env.
- PENPOT_HOST=${PENPOT_HOST}
- PENPOT_PUBLIC_URI=${PENPOT_PUBLIC_URI}
- PENPOT_DATABASE_URI=${PENPOT_DATABASE_URI}
- PENPOT_DATABASE_USERNAME=${PENPOT_DATABASE_USERNAME}
- PENPOT_DATABASE_PASSWORD=${PENPOT_DATABASE_PASSWORD}
- PENPOT_DATABASE_MAX_POOL_SIZE=${PENPOT_DATABASE_MAX_POOL_SIZE}
- PENPOT_REDIS_URI=${PENPOT_REDIS_URI}
- PENPOT_OBJECTS_STORAGE_BACKEND=${PENPOT_OBJECTS_STORAGE_BACKEND}
- PENPOT_OBJECTS_STORAGE_S3_ENDPOINT=${PENPOT_OBJECTS_STORAGE_S3_ENDPOINT}
- PENPOT_OBJECTS_STORAGE_S3_BUCKET=${PENPOT_OBJECTS_STORAGE_S3_BUCKET}
- AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}
- AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}
- PENPOT_BACKEND_WORKER=${PENPOT_BACKEND_WORKER}
- PENPOT_TMUX_SESSION=${PENPOT_TMUX_SESSION}
- PENPOT_TMUX_ATTACH=${PENPOT_TMUX_ATTACH}
# Agentic devenv: set to a commit/tag to update Serena on startup,
# leave empty to skip update and use the version baked into the image.
- SERENA_UPDATE_VERSION=1.5.0
networks:
- default
redis:
image: valkey/valkey:8.1
hostname: "${PENPOT_VALKEY_HOSTNAME}"
container_name: "${PENPOT_VALKEY_CONTAINER_NAME}"
restart: always
command: valkey-server --save 120 1 --loglevel warning
volumes:
- "valkey_data:/data"
networks:
- default