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>
This commit is contained in:
abounoone 2026-03-19 14:23:34 +00:00
parent d44c0258e0
commit 28120aed21
4 changed files with 192 additions and 7 deletions

View file

@ -9,7 +9,11 @@ TAG ?= v16
COMPOSE_OVERRIDES := \
-f compose.yaml \
-f overrides/compose.assets-volume.yaml
-f overrides/compose.mariadb.yaml \
-f overrides/compose.redis.yaml \
-f overrides/compose.assets-volume.yaml \
-f overrides/compose.noproxy.yaml \
-f overrides/compose.backup-cron.yaml
APPS_JSON_B64 := $(shell base64 -w 0 apps.json)

View file

@ -21,9 +21,12 @@ docker compose -f compose.yaml -f overrides/compose.mariadb.yaml -f overrides/co
| compose.nginxproxy-ssl.yaml | Adds acme-companion for HTTPS on port `:443` with automatic certificates | Requires `compose.nginxproxy.yaml`. Set `NGINX_PROXY_HOSTS` and `LETSENCRYPT_EMAIL`. `HTTP_PUBLISH_PORT` and `HTTPS_PUBLISH_PORT` can be set. |
| **Redis** | | |
| compose.redis.yaml | Adds Redis service for caching and background job queuing |
| **TBD** | **The following overrides are available but lack documentation. If you use them and understand their purpose, please consider contributing to this documentation.** |
| compose.backup-cron.yaml | | |
| compose.custom-domain-ssl.yaml | | |
| compose.custom-domain.yaml | | |
| compose.multi-bench-ssl.yaml | | |
| compose.multi-bench.yaml | | |
| **Assets / ERPNext** | | |
| compose.assets-volume.yaml | Adds a shared `assets` volume mounted to all service containers. **Required for ERPNext** — without it nginx returns 404 for all static files | Must be included whenever ERPNext or any app with compiled frontend assets is installed |
| **Backups** | | |
| compose.backup-cron.yaml | Adds [Ofelia](https://github.com/mcuadros/ofelia) cron container that runs `bench --site all backup` on a schedule | Set `BACKUP_CRONSTRING` in `.env` (default `@every 6h`). Uses Docker label-based job config on the `scheduler` container |
| **Multi-bench / Custom domain**| | |
| compose.multi-bench.yaml | Connects all services to a named `bench-network` and shared `mariadb-network`, exposes `frontend` to Traefik via `ROUTER` and `SITES_RULE` | For running multiple Frappe stacks behind a single Traefik instance. Requires `ROUTER`, `SITES_RULE`. Use with `compose.traefik.yaml` |
| compose.multi-bench-ssl.yaml | Adds HTTPS routing rules to the multi-bench setup | Use together with `compose.multi-bench.yaml` and `compose.traefik-ssl.yaml` |
| compose.custom-domain.yaml | Adds a Caddy sidecar that reverse-proxies a custom domain to `frontend:8080` and registers it with Traefik | Requires `ROUTER`, `SITES_RULE`, `BASE_SITE`. For mapping an additional hostname to a site in a multi-bench setup |
| compose.custom-domain-ssl.yaml | Adds HTTPS to the custom-domain Caddy sidecar | Use together with `compose.custom-domain.yaml` |

View file

@ -0,0 +1,88 @@
# 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.

View file

@ -0,0 +1,90 @@
# Stack management with Makefile
The `Makefile` in the project root provides a single entry point for all common operations. It always uses the full set of override files required to run ERPNext locally.
## Included overrides
Every `make` command runs `docker compose` with:
```
compose.yaml
overrides/compose.mariadb.yaml
overrides/compose.redis.yaml
overrides/compose.assets-volume.yaml
overrides/compose.noproxy.yaml
overrides/compose.backup-cron.yaml
```
## Commands
| Command | What it does |
|---|---|
| `make help` | Print all available commands with descriptions |
| `make up` | Start the full stack in detached mode |
| `make down` | Stop and remove all containers |
| `make restart` | Restart `backend`, `frontend`, `websocket` |
| `make ps` | Show container status |
| `make logs` | Stream `backend` logs live |
| `make shell` | Open `bash` in the backend container |
| `make backup` | Create a manual backup of the site |
| `make migrate` | Run `bench migrate` on the site (after app updates) |
| `make assets` | Rebuild JS/CSS bundles and restart frontend |
| `make build` | Build the `frappe-custom:v16` image from `apps.json` |
| `make update` | Full update cycle: build → recreate containers → migrate → assets |
## Variables
The Makefile exposes two overridable variables:
```bash
SITE ?= erp.local # site name used in bench commands
TAG ?= v16 # image tag used in build
```
Override on the command line:
```bash
make migrate SITE=mycompany.local
make build TAG=v17
```
## First-run checklist
```bash
# 1. Start the stack (MariaDB, Redis and all Frappe services)
make up
# 2. Wait ~10 seconds for MariaDB to become healthy, then create the site
make shell
bench new-site \
--mariadb-user-host-login-scope=% \
--db-root-password <DB_PASSWORD from .env> \
--admin-password <your-admin-password> \
erp.local
# 3. Install apps on the site
bench --site erp.local install-app erpnext
bench --site erp.local install-app crm
# ... other apps as needed
exit # leave the shell
# 4. Open http://localhost:8090 in your browser
```
> `DB_PASSWORD` is set in `.env`. The default value is a random string generated during project setup.
## Updating the stack
When `apps.json` changes (new app version or added app):
```bash
make update
# equivalent to: make build && docker compose up -d (backend services) && make migrate && make assets
```
For a config-only change that doesn't require a new image:
```bash
make down && make up
```