mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 23:35:43 +00:00
- Add io.sentry:sentry dependency - Initialize Sentry from SENTRY_DSN environment variable - Report uncaught exceptions via ExceptionInterceptor - Add SENTRY_DSN to docker-compose and CI workflow When SENTRY_DSN is configured, uncaught exceptions in gRPC handlers will be reported to Sentry for email/Slack alerts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
210 lines
6.6 KiB
YAML
210 lines
6.6 KiB
YAML
# Docker Compose for production deployment
|
|
#
|
|
# Local testing:
|
|
# Build images: bazel run //ci:eagle_server_load && bazel run //ci:shardok_server_load && bazel run //ci:auth_server_load
|
|
# Run: docker compose -f docker-compose.prod.yml up
|
|
#
|
|
# Production deployment:
|
|
# Run: docker compose -f docker-compose.prod.yml up -d
|
|
|
|
services:
|
|
eagle:
|
|
image: ${EAGLE_IMAGE:-registry.digitalocean.com/eagle0/eagle-server:latest}
|
|
container_name: eagle-server
|
|
command:
|
|
- "--gpt-model-name"
|
|
- "${GPT_MODEL_NAME:-gpt-5.1}"
|
|
- "--shardok-interface-remote-address"
|
|
- "shardok:40042"
|
|
- "--auth-service-url"
|
|
- "auth:40033"
|
|
ports:
|
|
- "40032:40032"
|
|
environment:
|
|
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
|
|
EAGLE_ENABLE_S3: "${EAGLE_ENABLE_S3:-false}"
|
|
DO_SPACES_ENDPOINT: "${DO_SPACES_ENDPOINT:-https://sfo3.digitaloceanspaces.com}"
|
|
DO_SPACES_ACCESS_KEY: "${DO_SPACES_ACCESS_KEY:-}"
|
|
DO_SPACES_SECRET_KEY: "${DO_SPACES_SECRET_KEY:-}"
|
|
JWT_PRIVATE_KEY: "${JWT_PRIVATE_KEY:-}"
|
|
DISCORD_CLIENT_ID: "${DISCORD_CLIENT_ID:-}"
|
|
DISCORD_CLIENT_SECRET: "${DISCORD_CLIENT_SECRET:-}"
|
|
# Auth token for remote Shardok on Hetzner (only used when shardok address contains .eagle0.net)
|
|
SHARDOK_AUTH_TOKEN: "${SHARDOK_AUTH_TOKEN:-}"
|
|
# Use persistent volume for save data (users, games, etc.)
|
|
EAGLE_SAVE_DIR: "/app/saves"
|
|
EAGLE_ARCHIVE_DIR: "/app/archived"
|
|
SENTRY_DSN: "${SENTRY_DSN:-}"
|
|
SENTRY_ENVIRONMENT: "production"
|
|
volumes:
|
|
- ./saves:/app/saves # Game saves and user database
|
|
- ./archived:/app/archived # Archived completed games
|
|
- ./jfr:/app/jfr # JFR recordings - dump with: docker exec eagle-server jcmd 1 JFR.dump filename=/app/jfr/profile.jfr
|
|
- jvm-tmp:/tmp # Shared with jfr-sidecar for JVM attach socket files
|
|
- jwt-keys:/etc/eagle0/keys # Shared JWT keys with auth service
|
|
depends_on:
|
|
- shardok
|
|
- auth
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "100m"
|
|
max-file: "5"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "nc -z localhost 40032 || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 30s
|
|
|
|
auth:
|
|
image: ${AUTH_IMAGE:-registry.digitalocean.com/eagle0/auth-server:latest}
|
|
container_name: auth-server
|
|
environment:
|
|
# gRPC port for Auth service
|
|
AUTH_GRPC_PORT: "40033"
|
|
# HTTP port for OAuth callbacks
|
|
AUTH_HTTP_PORT: "8080"
|
|
# User data persistence directory
|
|
AUTH_DATA_DIR: "/app/data"
|
|
# Legacy path for migrating users from Eagle (Phase 1 migration)
|
|
AUTH_LEGACY_DATA_DIR: "/app/saves/auth"
|
|
# OAuth provider credentials
|
|
DISCORD_CLIENT_ID: "${DISCORD_CLIENT_ID:-}"
|
|
DISCORD_CLIENT_SECRET: "${DISCORD_CLIENT_SECRET:-}"
|
|
GOOGLE_CLIENT_ID: "${GOOGLE_CLIENT_ID:-}"
|
|
GOOGLE_CLIENT_SECRET: "${GOOGLE_CLIENT_SECRET:-}"
|
|
# Server base URL for OAuth callbacks
|
|
SERVER_BASE_URL: "${SERVER_BASE_URL:-https://prod.eagle0.net}"
|
|
# JWT keys - PEM files in volume, bootstrapped from JWK on first run
|
|
JWT_KEYS_PATH: "/etc/eagle0/keys"
|
|
JWT_PRIVATE_KEY: "${JWT_PRIVATE_KEY:-}"
|
|
# Note: port 40033 is exposed via nginx, not directly
|
|
volumes:
|
|
- jwt-keys:/etc/eagle0/keys # Shared JWT keys with Eagle
|
|
- ./auth-data:/app/data # User database persistence
|
|
- ./saves:/app/saves:ro # Read-only access to Eagle's saves for migration
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "50m"
|
|
max-file: "3"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "nc -z localhost 40033 || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
shardok:
|
|
image: ${SHARDOK_IMAGE:-registry.digitalocean.com/eagle0/shardok-server:latest}
|
|
container_name: shardok-server
|
|
mem_limit: 1g
|
|
memswap_limit: 1g # Prevent swap, OOM-kill cleanly instead
|
|
ports:
|
|
- "40042:40042"
|
|
- "40052:40052"
|
|
environment:
|
|
SHARDOK_RESOURCES_PATH: "/app/resources"
|
|
SHARDOK_MAPS_PATH: "/app/resources/maps"
|
|
SHARDOK_EAGLE_INTERFACE_ADDRESS: "0.0.0.0:40042"
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "100m"
|
|
max-file: "5"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "nc -z localhost 40042 || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
nginx:
|
|
image: nginx:alpine
|
|
container_name: nginx
|
|
ports:
|
|
- "443:443"
|
|
- "80:80"
|
|
- "40033:40033" # Go Auth service gRPC (Phase 2 direct client connections)
|
|
volumes:
|
|
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
|
- ./certbot/conf:/etc/letsencrypt:ro
|
|
- ./certbot/www:/var/www/certbot:ro
|
|
- ./auth:/etc/nginx/auth:ro
|
|
depends_on:
|
|
- eagle
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "50m"
|
|
max-file: "3"
|
|
|
|
admin:
|
|
image: ${ADMIN_IMAGE:-registry.digitalocean.com/eagle0/admin-server:latest}
|
|
container_name: admin-server
|
|
command:
|
|
- "--eagle-addr"
|
|
- "eagle:40032"
|
|
- "--jfr-sidecar-addr"
|
|
- "jfr-sidecar:8081"
|
|
- "--http-port"
|
|
- "8080"
|
|
ports:
|
|
- "8080:8080"
|
|
depends_on:
|
|
- eagle
|
|
- jfr-sidecar
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "50m"
|
|
max-file: "3"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -q --spider http://localhost:8080/health || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
jfr-sidecar:
|
|
image: ${JFR_SIDECAR_IMAGE:-registry.digitalocean.com/eagle0/jfr-sidecar:latest}
|
|
container_name: jfr-sidecar
|
|
# Share PID namespace with Eagle to access its JVM via jcmd
|
|
pid: "service:eagle"
|
|
volumes:
|
|
- jvm-tmp:/tmp # Shared with Eagle for JVM attach socket files
|
|
depends_on:
|
|
- eagle
|
|
restart: unless-stopped
|
|
logging:
|
|
driver: "json-file"
|
|
options:
|
|
max-size: "10m"
|
|
max-file: "2"
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "wget -q --spider http://localhost:8081/health || exit 1"]
|
|
interval: 30s
|
|
timeout: 10s
|
|
retries: 3
|
|
start_period: 10s
|
|
|
|
certbot:
|
|
image: certbot/certbot
|
|
container_name: certbot
|
|
volumes:
|
|
- ./certbot/conf:/etc/letsencrypt
|
|
- ./certbot/www:/var/www/certbot
|
|
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
|
|
|
|
volumes:
|
|
jvm-tmp:
|
|
# Shared /tmp for JVM attach socket files between Eagle and jfr-sidecar
|
|
jwt-keys:
|
|
# Shared JWT RSA keys between Eagle and auth service
|