frappe_docker/docs/02-setup/09-architecture.md
abounoone 28120aed21 docs: add architecture guide and Makefile reference, fix overrides table
- docs/02-setup/09-architecture.md: explain the one-image-many-containers
  pattern, configurator lifecycle, request flow, assets-volume requirement,
  and Redis durability split
- docs/04-operations/02-makefile.md: document all make targets, variables,
  first-run checklist, and update workflow
- docs/02-setup/05-overrides.md: fill in TBD entries for assets-volume,
  backup-cron, multi-bench, and custom-domain overrides
- Makefile: add missing mariadb/redis/noproxy/backup-cron overrides to
  COMPOSE_OVERRIDES so make up starts a working stack

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 14:23:34 +00:00

88 lines
3.2 KiB
Markdown

# Container Architecture
## One image, many containers
There is no single "bench container" in Frappe Docker. The classic `bench` CLI that manages everything in a bare-metal setup is **decomposed into separate processes**, each running in its own container — all from the same image.
```
frappe-custom:v16 (one image)
├── configurator bench set-config ... (runs once, then exits)
├── backend gunicorn :8000 (HTTP API / page rendering)
├── websocket node socketio.js :9000 (realtime / socket.io)
├── queue-short bench worker --queue short,default
├── queue-long bench worker --queue long,default,short
├── scheduler bench schedule (Frappe's internal cron)
└── frontend nginx-entrypoint.sh (nginx reverse proxy)
```
External services (not from the Frappe image):
| Service | Image | Role |
|---|---|---|
| `db` | `mariadb:11.8` | Persistent relational storage |
| `redis-cache` | `redis:6.2-alpine` | Page/session cache (no persistence) |
| `redis-queue` | `redis:6.2-alpine` | Background job queue (persistent volume) |
| `cron` | `mcuadros/ofelia` | Docker-native cron for scheduled backups |
## Request flow
```
Browser → :8090
└─► frontend (nginx)
├─► backend:8000 HTTP/REST, page rendering
└─► websocket:9000 realtime events (socket.io)
backend / workers
├─► MariaDB:3306 persistent data
├─► redis-cache:6379 caching
└─► redis-queue:6379 job queue
```
## The configurator
`configurator` is the most non-obvious piece. It runs **before all other services**, writes connection addresses into `common_site_config.json` (the shared `sites` volume), and then exits with code 0.
All other Frappe containers depend on it via:
```yaml
depends_on:
configurator:
condition: service_completed_successfully
```
This is how override files inject infrastructure addresses. For example:
```yaml
# overrides/compose.mariadb.yaml
services:
configurator:
environment:
DB_HOST: db # MariaDB container name
# overrides/compose.redis.yaml
services:
configurator:
environment:
REDIS_CACHE: redis-cache:6379
REDIS_QUEUE: redis-queue:6379
```
Without the mariadb/redis overrides the `.env` values `DB_HOST` and `REDIS_CACHE` remain empty — Frappe starts but immediately fails to connect.
## Why `compose.assets-volume.yaml` is mandatory for ERPNext
The base `compose.yaml` mounts only the `sites` volume. ERPNext requires compiled JS/CSS bundles to be accessible from **all** service containers at `/home/frappe/frappe-bench/sites/assets`.
`compose.assets-volume.yaml` adds a shared `assets` volume mounted to that path in every service. Without it nginx returns 404 for all static files.
> The `compose.yaml` source contains an explicit comment: `# ERPNext requires local assets access (Frappe does not)`.
## Redis: two instances, different durability
| Instance | Purpose | Persistence |
|---|---|---|
| `redis-cache` | Page/session/query cache | None — ephemeral |
| `redis-queue` | Background job queue | `redis-queue-data` volume |
Jobs in the queue must survive restarts, so only `redis-queue` uses a persistent volume.