diff --git a/PRINCIPLES/dockerization-and-deployment.md b/PRINCIPLES/dockerization-and-deployment.md index 5e1244e..cfa79d3 100644 --- a/PRINCIPLES/dockerization-and-deployment.md +++ b/PRINCIPLES/dockerization-and-deployment.md @@ -393,30 +393,64 @@ that's why each one starts with the app's slug. --- -## 6. Persistent data: `./docker-data/` in the repo, gitignored +## 6. Persistent data: `./docker-data/` bind mounts, never named volumes -Bind-mount mysql and redis storage to a `docker-data/` folder right next -to the source: +**Rule: any service that needs to keep state between container restarts +gets a bind mount under `./docker-data//`. Never a named docker +volume.** This applies to mysql, redis, ssh host keys, app uploads, +queue state, every "this dir needs to survive" case — same shape, same +location, no exceptions. ``` docker-data/ mysql/ # mysql:8.0 datadir redis/ # redis dump.rdb + … # whatever else needs persistence ``` -The folder is gitignored (`docker-data/` in `.gitignore`). It survives -`docker compose down`. The deploy script `mkdir -p`s it on first run so -fresh boxes Just Work. +The folder is gitignored (`docker-data/` in `.gitignore`). The deploy +script `mkdir -p`s it on first run so fresh boxes Just Work. -### Why not named docker volumes? +### Why bind mounts, not named volumes + +The headline reason: **`docker compose down -v` wipes named volumes**. +That command is in too many people's muscle memory ("nuke the stack and +start clean") for the production datastore to be one accidental keystroke +away from gone. Bind mounts under the repo are immune — `down -v` +doesn't touch them. + +The rest of the rationale: - Trivially backed up — `tar -caf data.tar.xz docker-data/` from the repo root is the entire prod state. - Survives container/image churn including accidental - `docker volume prune -af`. + `docker volume prune -af` and `docker system prune --volumes`. - Discoverable — anyone with the repo can see where the data lives. - The repo path identifies which app owns the data when you have ten apps on one host. +- Restoring on a new host is `git clone && rsync docker-data/` — no + per-volume `docker volume create && docker run --rm -v ... tar` dance. + +### Counter-pattern (do not do this) + +```yaml +# WRONG — named volume; `docker compose down -v` deletes the data. +services: + mysql: + volumes: + - mysql-data:/var/lib/mysql + +volumes: + mysql-data: +``` + +```yaml +# RIGHT — bind mount; survives `down -v`. +services: + mysql: + volumes: + - ./docker-data/mysql:/var/lib/mysql +``` ---