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:
parent
d936bc2f62
commit
23186b77e1
6 changed files with 468 additions and 2 deletions
51
.env.example
Normal file
51
.env.example
Normal 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
156
DEPLOYMENT.md
Normal 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.
|
||||
41
PROGRESS.md
41
PROGRESS.md
|
|
@ -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
51
cmd/acb-worker/Dockerfile
Normal 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
110
docker-compose.bots.yml
Normal 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
|
||||
61
docker-compose.workers.yml
Normal file
61
docker-compose.workers.yml
Normal 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:
|
||||
Loading…
Add table
Reference in a new issue