Docker Deployment Guide
Run DINOForge and related tools in isolated Docker containers for consistent, reproducible deployments across development, testing, and production environments.
Overview
Docker provides several advantages for DINOForge deployment:
- Consistency: Same environment across all machines (dev, CI, production)
- Isolation: No conflicts with system dependencies
- Scalability: Easy horizontal scaling for multi-pack compilation
- Reproducibility: Version-locked .NET runtime and dependencies
- Easy Setup: Single
docker-compose upcommand
This guide covers containerizing:
- DINOForge SDK and PackCompiler tooling
- MCP Bridge server
- Optional: Game instance (Wine container for testing)
Prerequisites
- Docker 20.10+ or Docker Desktop
- Docker Compose 2.0+ (included with Docker Desktop)
- 4 GB+ RAM allocated to Docker
- 10 GB+ free disk space
Check Docker Installation
bash
docker --version
docker-compose --versionDockerfile (Build DINOForge Runtime & Tools)
Create: Dockerfile.dinoforge
dockerfile
# Multi-stage build: .NET 11 SDK → Runtime
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:11.0-preview-bookworm as builder
WORKDIR /src
# Copy solution and projects
COPY DINOForge.sln ./
COPY src/ ./src/
COPY schemas/ ./schemas/
COPY packs/ ./packs/
# Restore dependencies
RUN dotnet restore src/DINOForge.sln
# Build release configuration
RUN dotnet build src/DINOForge.sln -c Release -o /app/build
# Publish stage
FROM mcr.microsoft.com/dotnet/runtime:11.0-preview-bookworm
LABEL maintainer="DINOForge Developers"
LABEL description="DINOForge Runtime & SDK Container"
LABEL version="0.14.0"
# Install additional runtime dependencies
RUN apt-get update && apt-get install -y \
curl \
jq \
wget \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy built artifacts from builder
COPY --from=builder /app/build .
# Create directories for mods, data, logs
RUN mkdir -p /app/mods /app/data /app/logs
# Environment variables
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
ENV DOTNET_EnableDiagnostics=0
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8765/health || exit 1
# Expose MCP server port
EXPOSE 8765
# Default: run MCP server
CMD ["dotnet", "DINOForge.Tools.DinoforgeMcp.dll"]Docker Compose Configuration
Create: docker-compose.yml
yaml
version: '3.9'
services:
# DINOForge MCP Server
dinoforge-mcp:
build:
context: .
dockerfile: Dockerfile.dinoforge
container_name: dinoforge-mcp
ports:
- "8765:8765"
volumes:
# Mod packs
- ./packs:/app/packs:ro
# Persistent data (configs, logs)
- dinoforge-data:/app/data
# Logs for inspection
- dinoforge-logs:/app/logs
environment:
# .NET configuration
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: "1"
DOTNET_EnableDiagnostics: "0"
# DINOForge configuration
LOG_LEVEL: "Info"
MCP_HOST: "0.0.0.0"
MCP_PORT: "8765"
restart: unless-stopped
networks:
- dinoforge-network
depends_on:
- dinoforge-cache
# Redis cache (optional: for distributed pack compilation)
dinoforge-cache:
image: redis:7-alpine
container_name: dinoforge-cache
ports:
- "6379:6379"
volumes:
- redis-data:/data
restart: unless-stopped
networks:
- dinoforge-network
# PostgreSQL database (optional: for game state tracking)
dinoforge-db:
image: postgres:15-alpine
container_name: dinoforge-db
environment:
POSTGRES_USER: dinoforge
POSTGRES_PASSWORD: changeme # CHANGE THIS!
POSTGRES_DB: dinoforge_data
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
restart: unless-stopped
networks:
- dinoforge-network
# (Optional) Wine container for game testing
dinoforge-game-test:
image: lutris/lutris:latest
container_name: dinoforge-game-test
volumes:
# Game installation
- game-install:/home/user/.steam/steamapps/common/Diplomacy\ is\ Not\ an\ Option
# Mods
- ./packs:/mods:ro
# Shared data
- dinoforge-data:/shared-data
environment:
DISPLAY: ":1"
# Uncomment for X11 forwarding on Linux
# ports:
# - "6000:6000"
restart: "no"
networks:
- dinoforge-network
profiles:
- "with-game" # Only enable with: docker-compose --profile with-game up
networks:
dinoforge-network:
driver: bridge
volumes:
dinoforge-data:
driver: local
dinoforge-logs:
driver: local
redis-data:
driver: local
postgres-data:
driver: local
game-install:
driver: localBuilding and Running
Build the Docker Image
bash
# From the DINOForge repository root
docker build -f Dockerfile.dinoforge -t dinoforge:latest .
# Or use docker-compose (builds automatically)
docker-compose buildStart Services
bash
# Start core services (MCP, Redis)
docker-compose up -d
# Or start with game testing container
docker-compose --profile with-game up -d
# View logs
docker-compose logs -f dinoforge-mcp
# Stop services
docker-compose downVerify Containers Are Running
bash
docker-compose ps
# Expected output:
# NAME STATUS
# dinoforge-mcp Up
# dinoforge-cache Up
# dinoforge-db UpConfiguration via Environment Variables
Override settings without rebuilding:
bash
docker-compose run --rm dinoforge-mcp env -i \
LOG_LEVEL=Debug \
MCP_HOST=127.0.0.1 \
RUST_BACKTRACE=1 \
dotnet DINOForge.Tools.DinoforgeMcp.dllOr set in .env file:
env
# .env
LOG_LEVEL=Info
MCP_HOST=0.0.0.0
MCP_PORT=8765
POSTGRES_PASSWORD=mysecurepassword
REDIS_HOST=dinoforge-cache
REDIS_PORT=6379Then:
bash
docker-compose --env-file .env up -dVolume Mounting for Development
Mount Local Directories
bash
# Mount source code for live development
docker-compose run --rm \
-v $(pwd)/src:/app/src:ro \
-v $(pwd)/schemas:/app/schemas:ro \
dinoforge-mcp bash
# Inside container:
cd /app
dotnet run --project src/Tools/PackCompiler -- validate packs/Accessing Logs
bash
# View container logs
docker-compose logs dinoforge-mcp
# Follow logs in real-time
docker-compose logs -f dinoforge-mcp
# Extract logs to file
docker-compose logs dinoforge-mcp > logs/mcp.log
# Access mounted logs directory
ls -la dinoforge-logs/Networking
Accessing Services from Host
bash
# MCP Server (from host)
curl http://localhost:8765/rpc \
-d '{"jsonrpc":"2.0","id":1,"method":"game_status","params":{}}'
# Redis (from host)
redis-cli -h 127.0.0.1 -p 6379
# PostgreSQL (from host)
psql -h 127.0.0.1 -U dinoforge -d dinoforge_dataInter-container Communication
Containers can reach each other via service names:
bash
# From dinoforge-mcp to Redis
redis://dinoforge-cache:6379
# From dinoforge-mcp to PostgreSQL
postgresql://dinoforge:password@dinoforge-db:5432/dinoforge_dataAdvanced: Multi-Stage Compilation
Scale pack compilation across multiple containers:
yaml
services:
pack-compiler:
image: dinoforge:latest
command: dotnet DINOForge.Tools.PackCompiler build ${PACK_NAME}
volumes:
- ./packs:/app/packs
- ./dist:/app/dist
environment:
PACK_NAME: ${PACK_NAME:-example-balance}
networks:
- dinoforge-network
pack-compiler-2:
image: dinoforge:latest
command: dotnet DINOForge.Tools.PackCompiler build ${PACK_NAME_2}
volumes:
- ./packs:/app/packs
- ./dist:/app/dist
networks:
- dinoforge-networkRun parallel compilations:
bash
PACK_NAME=warfare-modern PACK_NAME_2=example-balance \
docker-compose up pack-compiler pack-compiler-2Testing Connectivity
Test MCP Server Health
bash
# Inside container
docker-compose exec dinoforge-mcp curl -s http://localhost:8765/health | jq
# From host
curl -s http://localhost:8765/rpc \
-d '{"jsonrpc":"2.0","id":1,"method":"game_status","params":{}}' | jqTest Redis Connection
bash
docker-compose exec dinoforge-cache redis-cli ping
# Expected: PONGTest PostgreSQL Connection
bash
docker-compose exec dinoforge-db psql -U dinoforge -d dinoforge_data -c "SELECT 1"
# Expected: 1Troubleshooting
Container Fails to Start
Solution:
bash
# Check logs
docker-compose logs dinoforge-mcp
# Rebuild image
docker-compose build --no-cache
# Restart
docker-compose up -dPort Already in Use
Solution:
bash
# Find what's using the port
lsof -i :8765
# Change port in docker-compose.yml
# Or stop the conflicting service and restart
docker-compose downVolume Permission Issues
Solution:
bash
# Fix permissions on host directories
chmod -R u+rwX packs/
chmod -R u+rwX dinoforge-logs/
# Or run container with user ID
docker-compose run --user $(id -u):$(id -g) dinoforge-mcp bashContainer Out of Memory
Solution:
bash
# Increase Docker memory limit
# Docker Desktop: Preferences → Resources → Memory: 8GB+ recommended
# Or limit specific container
# In docker-compose.yml, add:
# deploy:
# resources:
# limits:
# memory: 2GProduction Deployment
Push to Docker Registry
bash
# Tag image
docker tag dinoforge:latest myregistry.azurecr.io/dinoforge:v0.14.0
# Push to registry
docker push myregistry.azurecr.io/dinoforge:v0.14.0
# Deploy using helm, kubernetes, or ComposeSecurity Best Practices
dockerfile
# Use multi-stage builds (done above)
# Don't run as root
FROM mcr.microsoft.com/dotnet/runtime:11.0-preview-bookworm
RUN useradd -m -u 1000 dinoforge
USER dinoforge
# Set resource limits in docker-compose.yml
# Use environment variables for secrets (use .env.prod)
# Enable read-only root filesystem where possibleDocker CLI Commands Reference
bash
# Build
docker-compose build
# Start (detached)
docker-compose up -d
# Stop
docker-compose down
# View logs
docker-compose logs -f dinoforge-mcp
# Execute command in running container
docker-compose exec dinoforge-mcp bash
# Run one-off command
docker-compose run --rm dinoforge-mcp dotnet --version
# Remove volumes
docker-compose down -v
# Rebuild and restart
docker-compose down && docker-compose build && docker-compose up -d