Как я раскладываю сервисы по docker compose

Когда сервисов на коробке становится больше трёх, наступает момент истины: либо у тебя есть система, либо у тебя бардак, в котором ты через полгода не вспомнишь, где чьи данные. У меня бардак уже был, поэтому в этот раз я завёл правило и держусь за него зубами.

Правило ровно одно: один docker compose стек = одна папка в /app/<сервис>. Всё, что относится к сервису, живёт внутри этой папки и нигде больше.

Как выглядит на диске

/app
├── writefreely/
│   ├── compose.yml
│   ├── .env
│   └── data/
├── nextcloud/
│   ├── compose.yml
│   ├── .env
│   └── data/
└── gitea/
    ├── compose.yml
    ├── .env
    └── data/

Никаких именованных докер-томов, разбросанных в недрах /var/lib/docker, которые потом фиг найдёшь. Все данные я монтирую относительными путями внутрь папки сервиса — в подкаталог data/. Хочу посмотреть, что сервис нажил — иду в его папку, и там всё.

Из чего состоит стек

Типичный compose.yml у меня выглядит так:

services:
  writefreely:
    image: writeas/writefreely:latest
    container_name: writefreely
    restart: unless-stopped
    env_file: .env
    ports:
      - "127.0.0.1:8080:8080"
    volumes:
      - ./data:/data

Несколько вещей, которые я делаю всегда и осознанно:

.env рядом, и в нём примерно вот это:

# /app/writefreely/.env
DOMAIN=blog.local
DATABASE_PASSWORD=...

Восстанавливаемость — ради неё всё и затевалось

Главная мысль всей этой раскладки: коробку я должен уметь собрать заново с нуля за вечер. Не «вспомнить, как было», а буквально развернуть.

Для этого мне нужны две вещи: сами compose.yml с .env (это рецепт) и data/ (это содержимое). Рецепты весят копейки и меняются редко, поэтому я их версионирую и складываю отдельно. Грубо — собрать все compose-файлы в одно место:

mkdir -p ~/server-config/app
rsync -av --include='*/' \
  --include='compose.yml' --include='.env' \
  --exclude='*' \
  /app/ ~/server-config/app/

Эту папку ~/server-config я кладу в git и в бэкап. Получается, что вся конфигурация сервера — это десяток текстовых файлов, которые читаются глазами и восстанавливаются за минуты.

Данные из data/ — отдельная история, они большие и про них будет отдельный разговор про бэкапы. Но рецепт от содержимого я держу раздельно сознательно: потерять конфиг и потерять данные — это две очень разные катастрофы, и готовиться к ним надо по-разному.

Скучно? Скучно. Но именно скучные системы переживают переезд на новое железо без седых волос.