- подписка в SYNCED_ROLES + копия из канона ansible-roles (inv roles-pull) - роль собирает образ приложения на control-хосте по контракту `task image` и везёт его на сервер через docker save/load, без реестра
150 lines
13 KiB
Markdown
150 lines
13 KiB
Markdown
# AGENTS GUIDE
|
||
|
||
## Обзор
|
||
|
||
Ansible-проект для автоматизации личного сервера. Плейбуки разворачивают докеризированные приложения (gitea, authelia, miniflux, wakapi, memos, outline, gramps, calibre, wanderer, remembos, transcriber и др.) через выделенных системных пользователей, Caddy-прокси и Yandex Docker Registry. Секреты управляются через Ansible Vault.
|
||
|
||
## Структура проекта
|
||
|
||
- `playbook-*.yml` — плейбуки по одному на сервис, `playbook-all-*.yml` для групповых запусков.
|
||
- `production.yml` — инвентарь с единственным хостом `server`.
|
||
- `group_vars/all/` — общие переменные для всех хостов: `main.yml` (открытые) и `secrets.yml` (зашифрованные vault). Подхватываются Ansible автоматически, `vars_files` в плейбуках не нужен. Имя `secrets.yml` обязательно: pre-commit-хук и `.crushignore` ищут слово `secret(s)` в имени файла.
|
||
- `vars/*.yml` — переменные отдельных приложений (homepage, transcriber), подключаются через `vars_files`.
|
||
- `roles/` — кастомные роли (`eget`, `owner`, `secrets`, `app_image`), галактические роли в `galaxy.roles/`.
|
||
- `files/<app>/` — docker-compose шаблоны, конфиги, скрипты бэкапов для каждого сервиса.
|
||
- `templates/` — общие шаблоны (например `env.template`).
|
||
- `scripts/` — вспомогательные Python-скрипты (SMTP-утилиты для Yandex Cloud Postbox).
|
||
- `.gitea/workflows/lint.yml` — CI: yamllint + ansible-lint.
|
||
- `lefthook.yml` — pre-commit хуки (ruff, mypy, yamllint, ansible-lint, gitleaks, проверка vault).
|
||
- `tasks.py` — задачи через invoke (`inv <task>`).
|
||
- `pyproject.toml` — зависимости Python, управляются через `uv`.
|
||
|
||
## Настройка окружения
|
||
|
||
```bash
|
||
uv sync
|
||
cp ansible-vault-password-file.dist ansible-vault-password-file
|
||
uv run ansible-galaxy install --role-file requirements.yml
|
||
```
|
||
|
||
Требуется: `uv`, `ansible`, `yq`.
|
||
|
||
## Задачи (invoke)
|
||
|
||
Таск-раннер — `invoke` (файл `tasks.py`), вызывается через `inv`:
|
||
|
||
- `inv pl -- <app> [app2 ...]` — запуск плейбука (`ansible-playbook -i production.yml --diff`).
|
||
- `inv install-roles` — установка галактических ролей.
|
||
- `inv ssh` — SSH на сервер.
|
||
- `inv zj` — zellij на удалённом сервере.
|
||
- `inv btop` — btop на удалённом сервере.
|
||
- `inv encrypt -- <file>` / `inv decrypt -- <file>` — шифрование/дешифрование через ansible-vault.
|
||
- `inv authelia-cli -- <args>` — запуск Authelia CLI в docker.
|
||
- `inv authelia-validate-config` — рендер и валидация конфига Authelia через docker.
|
||
- `inv authelia-gen-random-string LEN=10` — генерация случайной строки.
|
||
- `inv authelia-gen-secret-and-hash LEN=72` — генерация секрета и его хэша (pbkdf2-sha512).
|
||
- `inv format-py-files` — форматирование Python-файлов через Black (docker).
|
||
|
||
## Плейбуки
|
||
|
||
### Системные
|
||
|
||
- `playbook-system.yml` — базовая настройка системы (apt-пакеты, безопасность, fail2ban, монтирование хранилища).
|
||
- `playbook-docker.yml` — установка Docker CE, создание сетей (web_proxy_network, monitoring_network), cron очистки образов.
|
||
- `playbook-eget.yml` — установка eget и инструментов через него (rclone, restic, resticprofile, btop, gobackup, task, dust, zellij).
|
||
- `playbook-ufw.yml` — настройка файрвола UFW (SSH/22, Gitea SSH/2222, HTTP/80, HTTPS/443).
|
||
- `playbook-upgrade.yml` — обновление системных пакетов, очистка Docker.
|
||
- `playbook-backups.yml` — настройка restic-бэкапов и оркестратора backup-all.py с cron-расписанием.
|
||
- `playbook-caddyproxy.yml` — Caddy reverse proxy.
|
||
|
||
### Приложения
|
||
|
||
- `playbook-gitea.yml` — Git-сервер.
|
||
- `playbook-authelia.yml` — аутентификация/SSO.
|
||
- `playbook-miniflux.yml` — RSS-ридер.
|
||
- `playbook-wakapi.yml` — трекинг времени.
|
||
- `playbook-memos.yml` — заметки.
|
||
- `playbook-outline.yml` — вики/база знаний.
|
||
- `playbook-homepage.yml` — кастомная домашняя страничка на apex `vakhrushev.me` (образ из Yandex Registry).
|
||
- `playbook-dashboard.yml` — дашборд со списком сервисов (gethomepage.dev) на `start.vakhrushev.me`, закрыт за Authelia.
|
||
- `playbook-rssbridge.yml` — RSS-агрегатор.
|
||
- `playbook-netdata.yml` — мониторинг.
|
||
- `playbook-dozzle.yml` — просмотр Docker-логов.
|
||
- `playbook-goaccess.yml` — аналитика веб-логов Caddy в реальном времени.
|
||
- `playbook-gramps.yml` — генеалогия.
|
||
- `playbook-calibre.yml` — управление электронными книгами.
|
||
- `playbook-transcriber.yml` — транскрибация (образ из Yandex Registry).
|
||
- `playbook-wanderer.yml` — пешие маршруты.
|
||
- `playbook-remembos.yml` — интервальное повторение.
|
||
- `playbook-tuwunel.yml` — Matrix-сервер (Tuwunel) с federation-делегацией на apex-домен.
|
||
- `playbook-tududi.yml` — планировщик задач (SQLite, OIDC через Authelia, AI-фичи через Bifrost).
|
||
- `playbook-bifrost.yml` — LLM-шлюз (OpenAI-совместимый) для AI-фич других приложений, провайдер DeepSeek.
|
||
|
||
### Агрегатные и служебные
|
||
|
||
- `playbook-all-setup.yml` — системная настройка целиком (system + docker + eget + backups).
|
||
- `playbook-all-applications.yml` — деплой всех приложений.
|
||
- `playbook-homepage-registry.yml` / `playbook-transcriber-registry.yml` — загрузка образов в Yandex Registry.
|
||
- `playbook-remove-user-and-app.yml` — удаление пользователя и приложения (`--extra-vars user_name=<name>`).
|
||
|
||
## Роли
|
||
|
||
- `roles/owner` — создаёт системного пользователя/группу для приложения, настраивает SSH-ключи, переменные окружения (~/.env, ~/.bashrc).
|
||
- `roles/eget` — скачивает и устанавливает утилиту eget.
|
||
- `roles/secrets` — управляет vault-зашифрованными файлами секретов для приложений.
|
||
- `roles/app_image` — собирает docker-образ приложения на control-хосте (контракт приложения — `task image` с тегом из `$BUILD_ID`) и везёт его на сервер через `docker save`/`load`, без реестра; отдаёт факт `app_image_tag` для compose. Общая роль, синхронизируется с каноном `ansible-roles` (`inv roles-pull`).
|
||
|
||
Галактические роли (`galaxy.roles/`): `geerlingguy.security`, `geerlingguy.docker`, `yatesr.timezone`.
|
||
|
||
## Шаблоны и переменные
|
||
|
||
- Суффиксы шаблонов: `.template.yml`, `.template.sh`, `.template.cfg`, `.template.conf`, `.template.toml`, `.template` (для файлов без естественного расширения) — рендерятся Ansible модулем `template`. Расширение оригинального формата сохраняется после `.template.` ради подсветки синтаксиса в редакторе.
|
||
- Большинство приложений определяют переменные inline в плейбуке. Отдельные файлы переменных только у homepage и transcriber (`vars/homepage.yml`, `vars/transcriber.yml` + `vars/transcriber.images.yml`).
|
||
- Общие переменные из `group_vars/all/` (`main.yml` + vault-файл `secrets.yml`): `application_dir`, `bin_prefix`, `primary_user` и др. Загружаются автоматически для группы `all`, поэтому плейбуки их не перечисляют. Хост-специфичные значения переопределяются в инвентаре — теперь они имеют приоритет над `group_vars`.
|
||
- Каждое приложение: `app_name`, `app_user`, `app_owner_uid`, `app_owner_gid`, `base_dir`, `data_dir`.
|
||
- UID/GID сервисов: новое соглашение — диапазон `11xx`, причём `app_owner_uid == app_owner_gid` (одно число на сервис). Новому приложению берём следующий свободный номер по возрастанию. Старые сервисы ещё сидят на легаси-нумерации `10xx` (часто с разными uid/gid) — их не трогаем, но новые заводим только в `11xx`.
|
||
|
||
## Линтинг и CI
|
||
|
||
- CI (`.gitea/workflows/lint.yml`): два параллельных job — yamllint и ansible-lint.
|
||
- Конфиги: `.yamllint.yml` (макс. длина строки 120), `.ansible-lint.yml` (профиль production, offline).
|
||
- Pre-commit хуки через lefthook:
|
||
- `ruff format` + `ruff check` — форматирование и линтинг Python.
|
||
- `mypy` — проверка типов Python.
|
||
- `yamllint` — линтинг YAML.
|
||
- `ansible-lint` — линтинг Ansible (профиль production).
|
||
- `gitleaks` — поиск секретов в staged-файлах.
|
||
- Проверка что секретные файлы зашифрованы vault.
|
||
|
||
## Конвенции
|
||
|
||
Договорённости о том, как делать однотипные вещи, живут в [`docs/conventions/`](docs/conventions) — одна конвенция на файл, у каждой статус (рекомендуемая / обязательная) и честный список уже существующих отступлений. Это правила на будущее, в отличие от [`docs/adr/`](docs/adr) (однажды принятые решения, постфактум и неизменяемо) и [`docs/drafts/`](docs/drafts) (черновики и хроника). Перед тем как заводить новое приложение или директорию — заглянуть туда.
|
||
|
||
- [Категории директорий приложения](docs/conventions/app-directories.md) — содержимое `base_dir` делится на конфигурацию (восстанавливается плейбуком, бэкап не нужен), данные (создаёт приложение, бэкапить обязательно) и кеш (создаёт приложение, перегенерирует само). Из категорий механически выводится `backup-targets`.
|
||
|
||
## Соглашения по коду
|
||
|
||
- Отступы: 2 пробела для YAML/Jinja, 4 пробела в остальных файлах (`.editorconfig`).
|
||
- Окончания строк: LF, завершающий перевод строки обязателен.
|
||
- Не коммитить незашифрованные секреты; `.crushignore` исключает `ansible-vault-password-file` и `*secrets.yml`.
|
||
- Директории в `files/<app>/` содержат docker-compose и шаблоны бэкапов; пользователи и настройки реестра должны соответствовать `vars/*.yml`.
|
||
|
||
## Деплой
|
||
|
||
```bash
|
||
# Один сервис
|
||
inv pl -- gitea
|
||
|
||
# Несколько сервисов
|
||
inv pl -- gitea miniflux wakapi
|
||
|
||
# Напрямую через ansible-playbook
|
||
ansible-playbook -i production.yml --diff playbook-gitea.yml
|
||
```
|
||
|
||
## Бэкапы
|
||
|
||
- Шаблоны скриптов бэкапов в `files/<app>/` (backup.template.sh, gobackup.template.yml и др.).
|
||
- `files/backups/backup-all.py` — оркестратор, запускает все бэкапы через restic.
|
||
- Cron-расписание настраивается в `playbook-backups.yml`.
|