Files
storkit/docker/docker-compose.yml

146 lines
5.8 KiB
YAML
Raw Normal View History

# Story Kit single-container deployment
#
# Usage:
# # Set your API key and project path, then:
# ANTHROPIC_API_KEY=sk-ant-... PROJECT_PATH=/path/to/your/repo \
# docker compose -f docker/docker-compose.yml up
#
# OrbStack users: just install OrbStack and use `docker compose` normally.
# OrbStack's VirtioFS bind mount driver is significantly faster than
# Docker Desktop's default (see spike findings).
#
# ── gVisor (runsc) host setup ────────────────────────────────────────────
# This compose file uses `runtime: runsc` (gVisor) for syscall-level
# sandboxing. gVisor intercepts all container syscalls in userspace so
# that even if a malicious workload escapes the container's process
# namespace it cannot make raw syscalls to the host kernel.
#
# Prerequisites on the Docker host:
# 1. Install gVisor:
# curl -fsSL https://gvisor.dev/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
# echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main" | sudo tee /etc/apt/sources.list.d/gvisor.list
# sudo apt-get update && sudo apt-get install -y runsc
# 2. Register runsc with Docker (/etc/docker/daemon.json):
# {
# "runtimes": {
# "runsc": { "path": "/usr/bin/runsc" }
# }
# }
# 3. Restart Docker: sudo systemctl restart docker
# 4. Verify: docker run --runtime=runsc hello-world
#
# Note: On macOS (OrbStack / Docker Desktop) gVisor is Linux-only and
# not supported. Remove `runtime: runsc` for local development on macOS.
services:
storkit:
build:
context: ..
dockerfile: docker/Dockerfile
# Run under gVisor for syscall-level sandboxing.
# Requires runsc installed and registered in /etc/docker/daemon.json.
# See host setup instructions in the header comment above.
runtime: runsc
container_name: storkit
ports:
# Bind to localhost only — not exposed on all interfaces.
- "127.0.0.1:3001:3001"
environment:
# Optional: Anthropic API key. If unset, Claude Code falls back to
# OAuth credentials from `claude login` (e.g. Max subscription).
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
# Required: git identity for agent commits
- GIT_USER_NAME=${GIT_USER_NAME:?Set GIT_USER_NAME}
- GIT_USER_EMAIL=${GIT_USER_EMAIL:?Set GIT_USER_EMAIL}
# Optional: override the server port (default 3001)
- STORKIT_PORT=3001
# Optional: Matrix bot credentials (if using Matrix integration)
- MATRIX_HOMESERVER=${MATRIX_HOMESERVER:-}
- MATRIX_USER=${MATRIX_USER:-}
- MATRIX_PASSWORD=${MATRIX_PASSWORD:-}
# Optional: Slack webhook (if using Slack integration)
- SLACK_BOT_TOKEN=${SLACK_BOT_TOKEN:-}
- SLACK_APP_TOKEN=${SLACK_APP_TOKEN:-}
volumes:
# The target project repo bind-mounted from host.
# Changes made by agents inside the container are immediately
# visible on the host (and vice versa).
- ${PROJECT_PATH:?Set PROJECT_PATH}:/workspace
# Cargo registry cache persists downloaded crates across
# container restarts so `cargo build` doesn't re-download.
- cargo-registry:/usr/local/cargo/registry
# Cargo git checkouts persists git-based dependencies.
- cargo-git:/usr/local/cargo/git
# Claude Code state persists session history, projects config,
# and conversation transcripts so --resume works across restarts.
- claude-state:/home/storkit/.claude
# Storkit source tree for rebuild_and_restart.
# The binary has CARGO_MANIFEST_DIR baked in at compile time
# pointing to /app/server, so the source must be at /app.
# This is COPY'd in the Dockerfile; mounting over it allows
# live source updates without rebuilding the image.
# Mount host source so rebuild_and_restart picks up live changes:
- ./..:/app
# Keep cargo build artifacts off the bind mount.
# Bind-mount directory traversal is ~23x slower than Docker volumes
# (confirmed in spike 329). Cargo stat-checks every file in target/
# on incremental builds — leaving it on the bind mount makes builds
# catastrophically slow (~12s just to traverse the tree).
- workspace-target:/workspace/target
- storkit-target:/app/target
# ── Security hardening ──────────────────────────────────────────
# Read-only root filesystem. Only explicitly mounted volumes and
# tmpfs paths are writable.
read_only: true
tmpfs:
- /tmp:size=512M,exec
- /home/storkit:size=512M,uid=999,gid=999,exec
# Drop all Linux capabilities, then add back only what's needed.
# SETUID/SETGID needed by Claude Code's PTY allocation (openpty).
cap_drop:
- ALL
cap_add:
- SETUID
- SETGID
# Prevent child processes from gaining new privileges via setuid,
# setgid, or other mechanisms.
security_opt:
- no-new-privileges:true
# Resource limits cap the whole system.
# Adjust based on your machine. These are conservative defaults.
deploy:
resources:
limits:
cpus: "8"
memory: 24G
reservations:
cpus: "2"
memory: 4G
# Health check verify the MCP endpoint responds
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:3001/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
# Restart policy restart on crash but not on manual stop
restart: unless-stopped
volumes:
cargo-registry:
cargo-git:
claude-state:
workspace-target:
storkit-target: