Create Deployment wiki page for fractafrag

xpltd_admin 2026-04-03 22:52:34 -06:00
parent c640f13e15
commit 972797dcfc

200
Deployment.md Normal file

@ -0,0 +1,200 @@
# Deployment
| Meta | Value |
|------|-------|
| **Repo** | `xpltdco/fractafrag` |
| **Page** | `Deployment` |
| **Audience** | developers, agents, newcomers |
| **Last Updated** | 2026-04-04 |
| **Status** | current |
## Docker Compose Stack
Fractafrag runs as 8 Docker containers orchestrated by `docker-compose.yml`.
### Services
| Service | Image | Port | Health Check |
|---------|-------|------|-------------|
| **nginx** | nginx:alpine | 80 | — |
| **frontend** | node:20-alpine (custom) | 5173 | — |
| **api** | python:3.12-slim (custom) | 8000 | `curl -f http://localhost:8000/health` (10s interval) |
| **mcp** | python:3.12-slim (custom) | 3200 | — |
| **renderer** | node:20-slim + Chromium (custom) | 3100 | — |
| **worker** | reuses api image | — | — |
| **postgres** | pgvector/pgvector:pg16 | 5432 | `pg_isready -U fracta` (5s interval) |
| **redis** | redis:7-alpine | 6379 | `redis-cli ping` (5s interval) |
### Startup Dependencies
```
postgres (healthy) ─┐
├─→ api (healthy) ─┬─→ nginx
redis (healthy) ────┘ ├─→ mcp
└─→ frontend ─→ nginx
postgres (healthy) ─┐
├─→ worker
redis (healthy) ────┘
```
## Volume Mounts
| Volume | Container Path | Purpose | Backup Priority |
|--------|---------------|---------|-----------------|
| `pgdata` (named) | `/var/lib/postgresql/data` | PostgreSQL data | **Critical** — all application state |
| `redisdata` (named) | `/data` | Redis AOF persistence | **Low** — regeneratable cache |
| `renders` (named) | `/renders` | Shader thumbnails/previews | **Medium** — regeneratable but slow |
### Init Script Mount
```yaml
./db/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro
```
This SQL file runs on first PostgreSQL startup only. It creates all tables, indexes, extensions, and the system user account.
## Port Mappings
| Port | Service | Protocol | Purpose |
|------|---------|----------|---------|
| 80 | nginx | HTTP | Main entry point (proxy to all services) |
| 8000 | api | HTTP | FastAPI backend (dev direct access) |
| 5173 | frontend | HTTP | Vite dev server (dev direct access) |
| 3200 | mcp | HTTP+SSE | MCP server (dev direct access) |
| 3100 | renderer | HTTP | Headless renderer (internal) |
| 5432 | postgres | TCP | PostgreSQL (dev direct access) |
| 6379 | redis | TCP | Redis (dev direct access) |
> In production, only port 80 (nginx) should be exposed externally. Other ports are exposed in `docker-compose.override.yml` for development only.
## Nginx Routing
**Config file:** `services/nginx/conf/default.conf`
| Location | Target | Timeout | Notes |
|----------|--------|---------|-------|
| `/` | `frontend:5173` | — | WebSocket upgrade for Vite HMR |
| `/api/*` | `api:8000/api/` | 120s | 10M body limit |
| `/mcp/*` | `mcp:3200/` | 600s | SSE support, no buffering |
| `/renders/*` | `/renders/` (volume alias) | — | 30-day cache, immutable |
| `/health` | direct 200 | — | Logging disabled |
## xpltd Infrastructure Deployment
On the xpltd infrastructure:
### Traffic Flow
```
Client → Cloudflare (DNS: fractafrag.xpltd.co)
→ nginx01:443 (TLS termination)
→ ub01:80 (fractafrag nginx container)
→ internal service routing
```
### DNS
| Layer | Record | Value |
|-------|--------|-------|
| **Cloudflare** | `fractafrag.xpltd.co` CNAME | `dyndns.xpltd.co` |
| **AdGuard Home** | `*.xpltd.co` rewrite | `10.0.0.9` (nginx01) |
## Health Checks
### API Health
```yaml
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
```
### PostgreSQL Health
```yaml
healthcheck:
test: ["CMD-SHELL", "pg_isready -U fracta -d fractafrag"]
interval: 5s
timeout: 5s
retries: 5
```
### Redis Health
```yaml
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
```
## Renderer Configuration
The renderer service requires special Docker configuration:
```yaml
renderer:
shm_size: '512mb' # Required for Chromium shared memory
environment:
- MAX_RENDER_DURATION=8
- OUTPUT_DIR=/renders
```
Chromium runs in headless mode with software rendering (SwiftShader). No GPU passthrough required.
## Redis Configuration
```yaml
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
```
- **AOF persistence** enabled (append-only file)
- **256MB** max memory with LRU eviction
- Increase `--maxmemory` if running many concurrent Celery tasks
## Logging
All services write to stdout/stderr (captured by Docker logging driver).
```bash
# All services
make logs
# or: docker compose logs -f
# Specific service
docker compose logs -f api
docker compose logs -f worker
docker compose logs -f renderer
```
## Backup Considerations
### What to Back Up
| Data | Location | Strategy |
|------|----------|----------|
| **PostgreSQL** | `pgdata` volume | `pg_dump` for logical backup |
| **Render output** | `renders` volume | Optional — can be regenerated |
| **Redis** | `redisdata` volume | Optional — ephemeral cache |
### PostgreSQL Backup
```bash
# Logical backup (recommended)
docker compose exec postgres pg_dump -U fracta fractafrag > backup.sql
# Restore
docker compose exec -T postgres psql -U fracta fractafrag < backup.sql
```
### Recovery
1. `docker compose down`
2. Remove volumes if doing a clean restore: `docker volume rm fractafrag_pgdata`
3. `docker compose up -d postgres` (waits for healthy)
4. Restore: `docker compose exec -T postgres psql -U fracta fractafrag < backup.sql`
5. `docker compose up -d` (start remaining services)