Collect the facts about all 14 services -- VMID, node, address, ports,
domain, pinned images, resources, backup and monitoring participation --
into group_vars/all/services.yml. Values are taken from the existing
playbooks; gaps are marked null rather than invented.
Replace reverse-proxy-{gitea,vaultwarden,grimmory}.yml with a single
playbook iterating over registry entries that declare a domain. It keeps
every check the three had, preserves grimmory's richer Caddy block
byte-for-byte, and restarts Caddy once when any site changed instead of
up to three times. Verified with --check --diff against ru-vps: ok=6
changed=0, so it reproduces the current Caddyfile exactly.
Add two roles factoring out the skeleton duplicated across the pve-*
playbooks: lxc_docker_host (packages, /dev/fuse assertion, fuse-overlayfs
storage driver, UFW baseline) and compose_service (compose file, systemd
unit, config validation, health check). They are not wired into any
playbook yet -- migrating a live service is a separate, per-service step;
compose_service/README.md shows the Gitea example and spells out what
actually changes on the host.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTocXkGUUazHdKKd3r9k71
134 lines
6.8 KiB
Markdown
134 lines
6.8 KiB
Markdown
# compose_service
|
||
|
||
Раскладывает Docker Compose стек и systemd-юнит, который им управляет.
|
||
Обобщение того, что делает `playbooks/pve-grimmory.yml`; такой же по форме
|
||
код продублирован в `roles/monitoring_server` и `roles/uptime_kuma`
|
||
(`grep -rn "up -d --remove-orphans"` — четыре копии одного юнита).
|
||
|
||
## Что делает
|
||
|
||
1. Создаёт корневой каталог сервиса и, при необходимости, каталоги данных
|
||
с нужными owner/group/mode.
|
||
2. Генерирует `.env` **один раз** под `umask 077`: статические пары из
|
||
`compose_service_env_static` и случайные секреты
|
||
(`openssl rand -hex`) для имён из `compose_service_env_generated`.
|
||
Задача целиком под `no_log: true`; права форсируются в `0600`.
|
||
Повторный прогон существующий `.env` не перетирает — иначе поменялся бы
|
||
пароль работающей БД.
|
||
3. Кладёт `compose.yml` из inline-строки или из Jinja-шаблона.
|
||
4. Ставит systemd-юнит `Type=oneshot`, `RemainAfterExit=yes`,
|
||
`ExecStart=docker compose up -d --remove-orphans`,
|
||
`ExecStop=docker compose down`.
|
||
5. `daemon-reload` через handler + немедленный `meta: flush_handlers`
|
||
(перечитать юнит надо ДО `systemctl start`, а не в конце play).
|
||
6. Валидирует конфигурацию: `docker compose config --quiet`, `no_log: true`
|
||
— при ошибке вывод подставляет значения из `.env`.
|
||
7. Стартует сервис, перезапуская его только если изменился `compose.yml`,
|
||
юнит или сработал внешний триггер (`compose_service_restart_triggers`).
|
||
8. Ждёт health-endpoint через `uri` с `retries`/`until`.
|
||
|
||
## Переменные
|
||
|
||
Полный список — в `defaults/main.yml`. Обязательные: `compose_service_name`
|
||
и ровно один из `compose_service_compose_content` /
|
||
`compose_service_compose_template` (проверяется `assert` в начале роли).
|
||
|
||
| Переменная | По умолчанию | Назначение |
|
||
|---|---|---|
|
||
| `compose_service_name` | — | имя сервиса и systemd-юнита |
|
||
| `compose_service_root` | `/opt/<name>` | корень стека |
|
||
| `compose_service_compose_content` | `""` | inline `compose.yml` |
|
||
| `compose_service_compose_template` | `""` | путь к Jinja-шаблону |
|
||
| `compose_service_directories` | `[]` | каталоги данных |
|
||
| `compose_service_env_static` | `{}` | пары для `.env` |
|
||
| `compose_service_env_generated` | `[]` | имена случайных секретов |
|
||
| `compose_service_after` / `_requires` | `[]` | доп. юниты в `After=`/`Requires=` |
|
||
| `compose_service_restart_triggers` | `[]` | внешние причины рестарта |
|
||
| `compose_service_health_url` | `""` | URL health-check (пусто — пропустить) |
|
||
|
||
## Пример использования — как выглядел бы Gitea на новых ролях
|
||
|
||
`playbooks/pve-gitea.yml` сейчас 231 строка. На ролях `pve_lxc` +
|
||
`lxc_docker_host` + `compose_service` содержательная часть сводится
|
||
примерно к такому (сам стек Gitea пока НЕ мигрирован — это следующий этап):
|
||
|
||
```yaml
|
||
---
|
||
- name: Create the Gitea LXC on cloud-pc
|
||
hosts: localhost
|
||
connection: local
|
||
gather_facts: false
|
||
vars:
|
||
gitea: "{{ homelab_services.gitea }}"
|
||
roles:
|
||
- role: pve_lxc
|
||
pve_lxc_vmid: "{{ gitea.vmid }}"
|
||
pve_lxc_node: "{{ gitea.node }}"
|
||
pve_lxc_hostname: "{{ gitea.hostname }}"
|
||
pve_lxc_ip: "{{ gitea.ip }}/24"
|
||
pve_lxc_disk: "{{ gitea.lxc.disk }}"
|
||
pve_lxc_cores: "{{ gitea.lxc.cores }}"
|
||
pve_lxc_memory: "{{ gitea.lxc.memory }}"
|
||
pve_lxc_swap: "{{ gitea.lxc.swap }}"
|
||
pve_lxc_startup: "{{ gitea.lxc.startup }}"
|
||
pve_lxc_ostemplate: "{{ gitea.lxc.ostemplate }}"
|
||
|
||
- name: Configure the Gitea service
|
||
hosts: gitea
|
||
gather_facts: true
|
||
vars:
|
||
gitea: "{{ homelab_services.gitea }}"
|
||
roles:
|
||
- role: lxc_docker_host
|
||
lxc_docker_host_extra_packages: [sqlite3, rsync]
|
||
lxc_docker_host_ufw_service_rules:
|
||
- port: "3000"
|
||
sources: ["{{ homelab_lan_cidr }}", "{{ openvpn_network_cidr }}"]
|
||
- port: "2222"
|
||
sources: ["{{ homelab_lan_cidr }}", "{{ openvpn_network_cidr }}"]
|
||
|
||
- role: compose_service
|
||
compose_service_name: gitea
|
||
compose_service_root: /opt/gitea
|
||
compose_service_description: Gitea Compose stack
|
||
compose_service_directories:
|
||
- {path: /opt/gitea/data, owner: "1000", group: "1000", mode: "0750"}
|
||
compose_service_env_static:
|
||
USER_UID: "1000"
|
||
USER_GID: "1000"
|
||
compose_service_compose_content: |
|
||
services:
|
||
gitea:
|
||
image: {{ gitea.images[0] }}
|
||
container_name: gitea
|
||
environment:
|
||
USER_UID: "${USER_UID}"
|
||
USER_GID: "${USER_GID}"
|
||
ports:
|
||
- "3000:3000"
|
||
- "2222:22"
|
||
volumes:
|
||
- /opt/gitea/data:/data
|
||
restart: unless-stopped
|
||
compose_service_health_url: http://127.0.0.1:3000/api/healthz
|
||
compose_service_health_retries: 24
|
||
compose_service_health_delay: 5
|
||
```
|
||
|
||
Около 30 строк `vars` вместо 231 строки процедурного кода, и все факты
|
||
(vmid, узел, адрес, ресурсы, digest образа) берутся из реестра
|
||
`homelab_services`, а не дублируются в плейбуке.
|
||
|
||
### Что при такой миграции меняется на живом хосте
|
||
|
||
Это не чистый рефакторинг, поэтому мигрировать нужно осознанно:
|
||
|
||
* `docker run` в `ExecStart=` заменяется на compose-стек — контейнер
|
||
пересоздаётся, юнит `gitea.service` меняет тип на `oneshot`.
|
||
* появляется `/opt/gitea/.env`, которого раньше не было;
|
||
* `--pull never` и явный `docker pull` по digest заменяются на `image:`
|
||
в compose — политику закрепления образов надо перенести отдельно.
|
||
|
||
Поэтому перевод существующих сервисов вынесен в отдельный этап и делается
|
||
по одному сервису, с бэкапом и `--check --diff` перед реальным прогоном.
|