Start Phase 6: Add deployment configuration and containers

- Add Dockerfile for acb-worker match execution container
- Add docker-compose.bots.yml for orchestrating all 6 strategy bots
- Add docker-compose.workers.yml for worker and indexer deployment
- Add .env.example documenting all required environment variables
- Add DEPLOYMENT.md with deployment guide and troubleshooting
- Update PROGRESS.md with Phase 6 progress

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jedarden 2026-03-24 09:41:14 -04:00
parent d936bc2f62
commit 23186b77e1
6 changed files with 468 additions and 2 deletions

51
.env.example Normal file
View file

@ -0,0 +1,51 @@
# AI Code Battle Environment Configuration
# Copy this file to .env and fill in the values
# ===========================================
# Worker API Configuration
# ===========================================
# The Cloudflare Worker API endpoint
ACB_API_ENDPOINT=https://api.aicodebattle.com
# Worker API key for authentication (required for workers and indexer)
ACB_API_KEY=your-worker-api-key-here
# ===========================================
# R2 Storage Configuration
# ===========================================
# R2 endpoint URL (Cloudflare R2 S3-compatible endpoint)
ACB_R2_ENDPOINT=https://your-account-id.r2.cloudflarestorage.com
# R2 bucket name for replays and match data
ACB_R2_BUCKET=acb-data
# R2 access credentials (from Cloudflare dashboard)
ACB_R2_ACCESS_KEY=your-r2-access-key-id
ACB_R2_SECRET_KEY=your-r2-secret-access-key
# ===========================================
# Bot Secrets (for local development)
# ===========================================
# Each bot needs a secret for HMAC authentication
BOT_SECRET_RANDOM=dev-secret-random
BOT_SECRET_GATHERER=dev-secret-gatherer
BOT_SECRET_RUSHER=dev-secret-rusher
BOT_SECRET_GUARDIAN=dev-secret-guardian
BOT_SECRET_SWARM=dev-secret-swarm
BOT_SECRET_HUNTER=dev-secret-hunter
# ===========================================
# Worker Configuration
# ===========================================
# Optional: unique worker identifier (auto-generated if not set)
ACB_WORKER_ID=
# Enable verbose logging (true/false)
ACB_VERBOSE=false
# ===========================================
# Index Builder Configuration
# ===========================================
# Optional: command to deploy generated files to Cloudflare Pages
# Example: wrangler pages deploy /app/data --project-name=aicodebattle
DEPLOY_COMMAND=

156
DEPLOYMENT.md Normal file
View file

@ -0,0 +1,156 @@
# AI Code Battle - Deployment Guide
This document describes how to deploy AI Code Battle to production.
## Architecture Overview
The platform is split across two tiers:
1. **Cloudflare (free tier)** - Web-facing infrastructure
- Pages: SPA shell + pre-computed JSON index files
- Worker: API endpoints for registration, job coordination
- D1: SQLite database for bots, matches, ratings
- R2: Replays, match metadata, maps, thumbnails
2. **Rackspace Spot** - Compute tier
- Match workers: Execute matches, upload replays to R2
- Bot containers: Run strategy bot HTTP servers
- Index builder: Generates JSON indexes, deploys to Pages
## Prerequisites
- Cloudflare account with:
- Pages project created
- Worker deployed
- D1 database created
- R2 bucket with custom domain configured
- Rackspace Spot account or equivalent container hosting
- Docker and docker-compose installed
## Environment Setup
1. Copy the example environment file:
```bash
cp .env.example .env
```
2. Edit `.env` and fill in your values:
- `ACB_API_ENDPOINT`: Your Cloudflare Worker URL
- `ACB_API_KEY`: Worker API key
- `ACB_R2_*`: R2 credentials from Cloudflare dashboard
- `BOT_SECRET_*`: Generate unique secrets for each bot
## Deploying Strategy Bots
The strategy bots run as HTTP servers that the match workers call during games.
```bash
# Build and start all 6 strategy bots
docker-compose -f docker-compose.bots.yml up -d
# Check status
docker-compose -f docker-compose.bots.yml ps
# View logs
docker-compose -f docker-compose.bots.yml logs -f
```
Bot endpoints will be available at:
- RandomBot: http://localhost:8081/turn
- GathererBot: http://localhost:8082/turn
- RusherBot: http://localhost:8083/turn
- GuardianBot: http://localhost:8084/turn
- SwarmBot: http://localhost:8085/turn
- HunterBot: http://localhost:8086/turn
## Deploying Match Workers
Match workers poll the Worker API for pending jobs and execute matches.
```bash
# Build and start match workers
docker-compose -f docker-compose.workers.yml up -d
# Scale workers based on load
docker-compose -f docker-compose.workers.yml up -d --scale worker=3
```
## Running the Index Builder
The index builder generates static JSON files for the web platform.
```bash
# Run once to generate index files
docker-compose -f docker-compose.workers.yml run indexer
# For automatic deployment, set DEPLOY_COMMAND in .env:
# DEPLOY_COMMAND=wrangler pages deploy /app/data --project-name=aicodebattle
```
## Cloudflare Configuration
### Worker API
Deploy the worker:
```bash
cd worker-api
npm install
wrangler deploy
```
### D1 Database
Create the database:
```bash
wrangler d1 create acb-db
```
Apply migrations (if any):
```bash
wrangler d1 execute acb-db --file=./schema.sql
```
### R2 Bucket
Create the bucket:
```bash
wrangler r2 bucket create acb-data
```
Configure custom domain in Cloudflare dashboard:
- Domain: `data.aicodebattle.com`
- Bucket: `acb-data`
### Pages
Deploy the web SPA:
```bash
cd web
npm install
npm run build
wrangler pages deploy dist --project-name=aicodebattle
```
## Monitoring
- Cloudflare Analytics: Available in Cloudflare dashboard
- Worker Logs: `wrangler tail`
- Container Logs: `docker-compose logs -f`
## Troubleshooting
### Worker can't connect to API
Check that `ACB_API_ENDPOINT` is correct and accessible from the worker container.
### Bot authentication failures
Verify `BOT_SECRET_*` values match what's registered in the Worker API.
### R2 upload failures
Check R2 credentials and bucket permissions.
### Index builder not deploying
Ensure `DEPLOY_COMMAND` is set correctly and Cloudflare API token has Pages deploy permissions.

View file

@ -2,7 +2,38 @@
## Current Phase: Phase 6 - Deployment & Production
**Status: 🔄 Ready to Start**
**Status: 🔄 In Progress**
### Phase 6 Progress
- [x] Match worker container (`cmd/acb-worker/Dockerfile`)
- Multi-stage Go build
- Non-root user for security
- Environment variable configuration
- [x] Bot-host deployment (`docker-compose.bots.yml`)
- Orchestrates all 6 strategy bots
- Health checks for each bot
- Environment-based secret configuration
- [x] Worker deployment (`docker-compose.workers.yml`)
- Match worker with scaling support
- Index builder for periodic runs
- R2 and API configuration
- [x] Environment configuration (`.env.example`)
- Documented all required environment variables
- [x] Deployment documentation (`DEPLOYMENT.md`)
- Architecture overview
- Cloudflare setup instructions
- Container deployment commands
- Troubleshooting guide
### Remaining Phase 6 Work
- [ ] Cloudflare Pages project creation and deployment
- [ ] D1 database schema and migrations
- [ ] R2 bucket creation and custom domain
- [ ] Worker API deployment via Wrangler
- [ ] DNS configuration
- [ ] Monitoring setup
### Phase 5 Completed ✅
@ -64,6 +95,11 @@
```
ai-code-battle/
├── go.mod
├── go.sum
├── .env.example # Environment configuration template
├── DEPLOYMENT.md # Deployment guide
├── docker-compose.bots.yml # Bot-host orchestration
├── docker-compose.workers.yml # Worker orchestration
├── engine/
│ ├── types.go # Core data types
│ ├── grid.go # Toroidal grid implementation
@ -82,7 +118,8 @@ ai-code-battle/
│ │ ├── main.go # Worker entry point
│ │ ├── api.go # Worker API client
│ │ ├── api_test.go # API client tests
│ │ └── r2.go # R2 upload client
│ │ ├── r2.go # R2 upload client
│ │ └── Dockerfile # Worker container
│ └── acb-indexer/ # Index builder
│ ├── package.json
│ ├── Dockerfile

51
cmd/acb-worker/Dockerfile Normal file
View file

@ -0,0 +1,51 @@
# AI Code Battle Match Worker Container
# Polls for match jobs from the Worker API, executes matches, uploads replays to R2
# Build stage
FROM golang:1.24-alpine AS builder
WORKDIR /build
# Copy go.mod and go.sum first for caching
COPY go.mod go.sum ./
RUN go mod download
# Copy engine package
COPY engine/ ./engine/
# Copy worker source
COPY cmd/acb-worker/ ./cmd/acb-worker/
# Build the binary
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /acb-worker ./cmd/acb-worker
# Runtime stage
FROM alpine:3.19
WORKDIR /app
# Install ca-certificates for HTTPS
RUN apk --no-cache add ca-certificates tzdata
# Copy binary from builder
COPY --from=builder /acb-worker /app/acb-worker
# Create non-root user
RUN adduser -D -u 1000 acb
USER acb
# Environment variables (set at runtime)
# ACB_API_ENDPOINT - Worker API URL (e.g., https://api.aicodebattle.com)
# ACB_API_KEY - Worker API key for authentication
# ACB_R2_ENDPOINT - R2 endpoint URL
# ACB_R2_BUCKET - R2 bucket name (default: acb-data)
# ACB_R2_ACCESS_KEY - R2 access key ID
# ACB_R2_SECRET_KEY - R2 secret access key
# ACB_WORKER_ID - Unique worker identifier (auto-generated if not set)
# ACB_VERBOSE - Enable verbose logging (true/false)
# Default values
ENV ACB_R2_BUCKET=acb-data
ENTRYPOINT ["/app/acb-worker"]
CMD ["-poll=5s", "-heartbeat=30s", "-timeout=3s"]

110
docker-compose.bots.yml Normal file
View file

@ -0,0 +1,110 @@
# AI Code Battle - Bot Host Deployment
# Runs all 6 strategy bots as a single deployable unit
#
# Usage:
# docker-compose -f docker-compose.bots.yml up -d
#
# Environment variables (set in .env or pass directly):
# BOT_SECRET_RANDOM - Secret for RandomBot
# BOT_SECRET_GATHERER - Secret for GathererBot
# BOT_SECRET_RUSHER - Secret for RusherBot
# BOT_SECRET_GUARDIAN - Secret for GuardianBot
# BOT_SECRET_SWARM - Secret for SwarmBot
# BOT_SECRET_HUNTER - Secret for HunterBot
services:
random:
build:
context: ./bots/random
dockerfile: Dockerfile
ports:
- "8081:8080"
environment:
- BOT_PORT=8080
- BOT_SECRET=${BOT_SECRET_RANDOM:-dev-secret-random}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
gatherer:
build:
context: ./bots/gatherer
dockerfile: Dockerfile
ports:
- "8082:8080"
environment:
- BOT_PORT=8080
- BOT_SECRET=${BOT_SECRET_GATHERER:-dev-secret-gatherer}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
rusher:
build:
context: ./bots/rusher
dockerfile: Dockerfile
ports:
- "8083:8082"
environment:
- BOT_PORT=8082
- BOT_SECRET=${BOT_SECRET_RUSHER:-dev-secret-rusher}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8082/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
guardian:
build:
context: ./bots/guardian
dockerfile: Dockerfile
ports:
- "8084:8083"
environment:
- BOT_PORT=8083
- BOT_SECRET=${BOT_SECRET_GUARDIAN:-dev-secret-guardian}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8083/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
swarm:
build:
context: ./bots/swarm
dockerfile: Dockerfile
ports:
- "8085:8084"
environment:
- BOT_PORT=8084
- BOT_SECRET=${BOT_SECRET_SWARM:-dev-secret-swarm}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8084/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped
hunter:
build:
context: ./bots/hunter
dockerfile: Dockerfile
ports:
- "8086:8085"
environment:
- BOT_PORT=8085
- BOT_SECRET=${BOT_SECRET_HUNTER:-dev-secret-hunter}
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:8085/health"]
interval: 30s
timeout: 5s
retries: 3
restart: unless-stopped

View file

@ -0,0 +1,61 @@
# AI Code Battle - Rackspace Worker Deployment
# Runs match workers and index builder on Rackspace Spot
#
# Usage:
# docker-compose -f docker-compose.workers.yml up -d
#
# Environment variables (set in .env or pass directly):
# ACB_API_ENDPOINT - Worker API URL (e.g., https://api.aicodebattle.com)
# ACB_API_KEY - Worker API key for authentication
# ACB_R2_ENDPOINT - R2 endpoint URL
# ACB_R2_BUCKET - R2 bucket name
# ACB_R2_ACCESS_KEY - R2 access key ID
# ACB_R2_SECRET_KEY - R2 secret access key
services:
# Match execution worker
worker:
build:
context: .
dockerfile: cmd/acb-worker/Dockerfile
environment:
- ACB_API_ENDPOINT=${ACB_API_ENDPOINT:-http://host.docker.internal:8787}
- ACB_API_KEY=${ACB_API_KEY:?ACB_API_KEY is required}
- ACB_R2_ENDPOINT=${ACB_R2_ENDPOINT}
- ACB_R2_BUCKET=${ACB_R2_BUCKET:-acb-data}
- ACB_R2_ACCESS_KEY=${ACB_R2_ACCESS_KEY}
- ACB_R2_SECRET_KEY=${ACB_R2_SECRET_KEY}
- ACB_WORKER_ID=${ACB_WORKER_ID:-}
- ACB_VERBOSE=${ACB_VERBOSE:-false}
command: ["-poll=5s", "-heartbeat=30s", "-timeout=3s"]
extra_hosts:
- "host.docker.internal:host-gateway"
restart: unless-stopped
deploy:
replicas: 1
resources:
limits:
memory: 512M
reservations:
memory: 256M
# Index builder - runs periodically to rebuild static JSON files
# Run manually: docker-compose -f docker-compose.workers.yml run indexer
indexer:
build:
context: ./cmd/acb-indexer
dockerfile: Dockerfile
environment:
- API_URL=${ACB_API_ENDPOINT:-http://host.docker.internal:8787}
- API_KEY=${ACB_API_KEY:?ACB_API_KEY is required}
- OUTPUT_DIR=/app/data
- DEPLOY_COMMAND=${DEPLOY_COMMAND:-}
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- indexer-data:/app/data
profiles:
- manual
volumes:
indexer-data: