Docker
Containment Chamber publishes multi-arch Docker images to GitHub Container Registry. The image runs on a scratch base with no shell or OS — just the statically-linked binary.
Quick Run
Section titled “Quick Run”Start a signer with a local config file and keystores directory:
docker run -d \ -p 9000:9000 \ -p 3000:3000 \ -v ./config.yaml:/config.yaml \ -v ./keystores:/keystores \ ghcr.io/unforeseen-consequences/containment-chamber:latest \ -c /config.yamlPort 9000 serves the signing API, and port 3000 exposes Prometheus metrics.
Docker Compose
Section titled “Docker Compose”Create a docker-compose.yml alongside your config.yaml and keystores/ directory:
services: containment-chamber: image: ghcr.io/unforeseen-consequences/containment-chamber:latest command: -c /config.yaml ports: - "9000:9000" # signing API - "3000:3000" # metrics volumes: - ./config.yaml:/config.yaml:ro - ./keystores:/keystores:ro environment: CONTAINMENT_ANTISLASHING__URL: postgresql://cc:secret@postgres:5432/slashing restart: unless-stopped depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:9000/upcheck || exit 1"] interval: 10s timeout: 5s retries: 3 start_period: 10s
postgres: image: postgres:16-alpine environment: POSTGRES_USER: cc POSTGRES_PASSWORD: secret POSTGRES_DB: slashing volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U cc -d slashing"] interval: 5s timeout: 3s retries: 5
volumes: postgres-data:Configuration
Section titled “Configuration”Create a minimal config.yaml that works with the Compose setup above:
server: listen_address: "0.0.0.0" listen_port: 9000
metrics: listen_address: "0.0.0.0" listen_port: 3000
network: mainnet
key_sources: filesystem: paths: - /keystores
antislashing: backend: postgres # URL is injected via CONTAINMENT_ANTISLASHING__URL environment variableThe CONTAINMENT_ANTISLASHING__URL environment variable in the Compose file overrides the config file value, keeping the database credentials out of the config.
Environment Variables
Section titled “Environment Variables”All configuration options can be set via environment variables using the CONTAINMENT_ prefix. Use double underscores (__) to represent nesting in the YAML structure.
CONTAINMENT_SERVER__LISTEN_PORT=9001CONTAINMENT_ANTISLASHING__BACKEND=postgresCONTAINMENT_ANTISLASHING__URL="postgresql://cc:secret@postgres:5432/slashing"Operations
Section titled “Operations”# Start all servicesdocker compose up -d
# Watch signer logsdocker compose logs -f containment-chamber
# Check healthcurl http://localhost:9000/upcheck
# List loaded validator keyscurl http://localhost:9000/api/v1/eth2/publicKeys
# Stop all servicesdocker compose down
# Stop and remove volumes (deletes slashing protection database)docker compose down -vImage Tags
Section titled “Image Tags”| Tag | Description |
|---|---|
latest | Latest stable release |
vX.Y.Z | Pinned to a specific version |
For production, pin to a specific version tag to avoid unexpected upgrades:
docker pull ghcr.io/unforeseen-consequences/containment-chamber:v1.0.0Multi-Architecture
Section titled “Multi-Architecture”Images are built for both linux/amd64 and linux/arm64. Docker automatically pulls the correct architecture for your platform — this includes Apple Silicon Macs, AWS Graviton instances, and standard x86 servers.