diff --git a/README.md b/README.md index 71237c9..673c5ed 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ HA-режим (embedded etcd): при отказе **любой одной** н | [Операции](docs/operations.md) | Управление нодами, etcd backup/restore, K3S upgrade | | [Make команды](docs/make-reference.md) | Полный справочник make | | [Molecule тесты](docs/molecule-testing.md) | Тестирование ролей, написание тестов | +| [Свои аддоны](docs/custom-addons.md) | Как добавить и подключить собственный аддон (роль, плейбук, make, Molecule) | | [Решение проблем](docs/troubleshooting.md) | Таблица проблем, диагностика | ## Структура проекта diff --git a/docs/addons.md b/docs/addons.md index df94002..08b86af 100644 --- a/docs/addons.md +++ b/docs/addons.md @@ -2,6 +2,8 @@ Все аддоны управляются через флаги в `group_vars/all/addons.yml`. Порядок установки в `playbooks/addons.yml` фиксирован (NFS → CSI → Ingress → cert-manager → остальные). +**Свой аддон (структура каталога, плейбук, `group_vars`, `Makefile`, Molecule):** подробно в отдельном руководстве — [Свои аддоны для k3s-ansible](custom-addons.md). + ## Установка аддонов ```bash diff --git a/docs/custom-addons.md b/docs/custom-addons.md new file mode 100644 index 0000000..b124d6d --- /dev/null +++ b/docs/custom-addons.md @@ -0,0 +1,213 @@ +# Свои аддоны для k3s-ansible + +Этот документ описывает, как **добавить собственный аддон** в проект: структуру каталога, плейбуки, переменные, интеграцию в `make`, и тесты Molecule. Предполагается, что вы уже читали [Аддоны](addons.md) и понимаете, как включать готовые компоненты через `group_vars/all/addons.yml`. + +--- + +## 1. Что считается «аддоном» + +Аддон — это **отдельная Ansible-роль** с **тонким плейбуком** в каталоге `addons/<имя>/`. Установка с хоста делается так: + +```bash +make addon-<имя> # прямой запуск +make install-addons # все аддоны с `addon_<имя>: true` в addons.yml +``` + +Внутри Docker runner вызывается `addon <имя>` (см. `docker/entrypoint.sh`): исполняется файл `addons/<имя>/playbook.yml`. Имя каталога **должно** совпадать с аргументом `addon` (например `addons/my-app/playbook.yml` → `make addon-my-app`). + +--- + +## 2. Минимальная структура каталога + +``` +addons// +├── README.md # обязательно: назначение, переменные, примеры +├── playbook.yml # точка входа для make addon- +└── role/ + ├── tasks/main.yml + ├── defaults/main.yml # все пользовательские переменные с разумными default + ├── meta/main.yml # опционально: dependencies, role_name + ├── templates/ # Jinja2 (.j2) — манифесты, values для Helm + ├── files/ # статические файлы + └── molecule/ + └── default/ + ├── molecule.yml # драйвер docker, платформа master01 + ├── converge.yml # «собрать» артефакты для проверки + └── verify.yml # assert +``` + +- **Роль** лежит **внутри** `addons//role/`, путь в плейбуке — относительно `playbook.yml` (см. ниже). +- Для **Helm-чарта** часто добавляют `role/chart/` или скачивание chart в `tasks` — ориентируйтесь на существующие аддоны (`gitea`, `loki`, `technitium-dns`). + +--- + +## 3. Плейбук `playbook.yml` + +### 3.1. Вариант «только аддон» (как у большинства поставляемых аддонов) + +```yaml +--- +- name: Install My Application + hosts: k3s_master[0] + gather_facts: false + become: true + roles: + - role: "{{ playbook_dir }}/role" +``` + +- `playbook_dir` — каталог, где лежит этот `playbook.yml` (т.е. `addons//`). +- `hosts` выбирайте по смыслу (см. [раздел 5](#5-выбор-группы-hosts-и-порядок-в-addonsyml) ниже). + +### 3.2. Плейбук в общем списке `playbooks/addons.yml` + +Для участия в `make install-addons` / `make install-full` добавьте **отдельный play** в `playbooks/addons.yml` **в правильном месте по зависимостям** (сначала NFS/CSI, ingress, cert-manager, затем остальные): + +```yaml +- name: Install My Application + hosts: k3s_master[0] + gather_facts: false + become: true + when: addon_my_app | default(false) | bool + roles: + - role: "{{ playbook_dir }}/../addons/my-app/role" +``` + +Имя флага в `when` и в `group_vars` должно быть согласовано: `addon_my_app` → `addon_my_app: true/false`. + +--- + +## 4. Переменные: `group_vars/all/addons.yml` + +1. **Флаг включения** (в начале файла, рядом с остальными `addon_*`): + + ```yaml + addon_my_app: false + ``` + +2. **Переменные по умолчанию** для аддона (префикс лучше делать уникальным, например `my_app_*`): + + ```yaml + # ─── My Application ───────────────────────────────────── + my_app_namespace: "my-app" + my_app_ingress_host: "myapp.example.com" + ``` + +3. **Секреты** — только через Ansible Vault, в `group_vars/all/vault.yml` (и пример в `vault.yml.example`): + + ```yaml + vault_my_app_password: "..." + ``` + +См. существующие комментарии в `addons.yml`: там же лежат примеры для похожих сервисов. + +--- + +## 5. Выбор группы hosts и порядок в addons.yml + +| Группа / паттерн | Когда использовать | +|------------------|------------------| +| `k3s_master[0]` | Почти все компоненты, которые ставятся через `kubectl`/`helm` с одной control-plane ноды | +| `k3s_cluster` | DaemonSet / агенты на всех нодах (пример: ingress-nginx, часть CSI) | +| `nfs_server` | NFS-сервер не на K8s (отдельная группа в inventory) | +| `hysteria2_server` | Удалённый VPS (см. `hysteria2-server`) | +| `splitgw` | Хосты split-gateway вне K8s или вместе с k8s в зависимости от роли | + +**Порядок play в `playbooks/addons.yml` важен:** не ставьте приложение, требующее Ingress, раньше play с `ingress-nginx`, не ставьте TLS-зависимое раньше `cert-manager`, если оно ожидает готовые `ClusterIssuer`. Новый аддон обычно добавляют **в конец** или сразу после логического предка. + +--- + +## 6. Цель `Makefile` + +Чтобы `make addon-` существовал, в `Makefile` в секции аддонов должен быть таргет вида: + +```makefile +addon-my-app: _check_env _check_image + @printf "$(CYAN)Устанавливаю My Application...$(NC)\n" + $(DOCKER_RUN) addon my-app $(ARGS) +``` + +Имя после `addon` — **каталог** `addons/my-app/`. См. комментарий в Makefile: *«Добавить новый аддон: создай addons//playbook.yml + addons//role/»*. + +`ARGS` передаётся в `ansible-playbook` как extra vars (кастомизация без правки `addons.yml`). + +--- + +## 7. Тесты Molecule + +Без Molecule легко сломать шаблоны при рефакторинге. Рекомендуемый минимум — сценарий `role/molecule/default/`. + +### 7.1. Как запускается + +```bash +make build +make molecule-addon-my-app +``` + +Runner (`docker/entrypoint.sh`, команда `molecule-addon`) заходит в каталог **`addons//role`** и выполняет `molecule test` (см. `JUNIT_OUTPUT_DIR` для отчётов в составе `make molecule-all`). + +### 7.2. `molecule.yml` + +Обычно одна тестовая нода `master01` (образ `geerlingguy/docker-ubuntu2204-ansible`), без privileged, если не нужен K3S в контейнере. Шаблон — любой существующий аддон рядом с вашим по сложности. + +### 7.3. `converge.yml` + +Типовые варианты: + +1. **Рендер Jinja2 + проверка файла** (простой аддон). +2. **Helm: `template` + `dest` в `/tmp/...` + `helm lint` / `helm template`** + - Команды `helm` выполняйте с **`delegate_to: localhost` и `run_once: true`**, иначе бинарник не найдётся в ноде Molecule. + - То же для `ansible.builtin.copy` / `template`, если пишете файлы, которые читает `helm` с localhost: пишите **на localhost** (иначе «файл не найден» при `delegate_to: localhost` у helm). +3. **Переменные** — задайте в `vars:` все, что **обязаны** знать шаблоны роли (в т.ч. пустые строки для optional полей), иначе `AnsibleUndefinedVariable` в тесте. + +### 7.4. `verify.yml` + +- Assert по содержимому сгенерированных YAML/манифестов. +- Булевы из `slurp`+`from_yaml` часто приходят **строками** — сравнивайте так: `(v.flag | string | lower) == 'true'`. +- Если проверяете **multi-doc YAML** (`---`), используйте `from_yaml_all` / разбор по документам. +- `hosts: localhost` удобен, если артефакты гарантированно на runner (файлы в `/tmp` после `delegate_to: localhost`). + +Подробности и типовые ошибки: [Тестирование через Molecule](molecule-testing.md#частые-причины-падений-addon-molecule). + +### 7.5. Включение в общий прогон + +После готового сценария добавьте в `Makefile` цель **`molecule-addon-`** (по аналогии с соседними аддонами) и вызов из **`molecule-addon-all`**, иначе CI/ручной `make molecule-addon-all` **не** увидит аддон. + +--- + +## 8. Документация в репозитории + +- **`addons//README.md`**: назначение, требования (ingress, БД, storage), переменные, пример `make`, ссылки на апстрим. +- **Корневой** [Аддоны](addons.md): добавьте строку в таблицу «Каталог аддонов» (флаг, краткое описание, ссылка на README), если аддон попал в **основной** репозиторий. +- **Секреты** — перечислить в `group_vars/all/vault.yml.example`, если введены новые `vault_*` ключи. + +--- + +## 9. Чеклист нового аддона + +- [ ] `addons//playbook.yml` + `role/` с осмысленными `defaults` и идемпотентными `tasks` +- [ ] `addons//README.md` +- [ ] `addon_: false` и переменные в `group_vars/all/addons.yml` (и секреты в `vault` при необходимости) +- [ ] Play в `playbooks/addons.yml` с `when: addon_ | default(false) | bool` и корректным `hosts` +- [ ] Таргет `addon-` в `Makefile` +- [ ] Molecule: `role/molecule/default/*`, `make molecule-addon-` зелёный +- [ ] Добавить `molecule-addon-` в `molecule-addon-all` в `Makefile` (если аддон в основной ветке репо) +- [ ] Строка в таблице [docs/addons.md](addons.md) + +--- + +## 10. Кастомизация без форка (альтернатива «своему» аддону) + +Если нужно **один раз** переопределить поведение существующей роли: + +- `make addon- ARGS="-e var=value"` +- `host_vars/<хост>.yml` / `group_vars` для тонкой настройки +- Для постоянного форка лучше **скопировать** роль в `addons//` и следовать чеклисту выше, явно называя сущности, чтобы не пересекаться с апстримом. + +--- + +## См. также + +- [Аддоны: установка, каталог, зависимости](addons.md) +- [Molecule: сценарии, отладка, шаблоны тестов](molecule-testing.md) +- [Справочник make](make-reference.md) +- [Конфигурация](configuration.md) diff --git a/docs/getting-started.md b/docs/getting-started.md index 8ba4592..f019777 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -185,7 +185,7 @@ make addon-cert-manager make addon-nfs # nfs-server + csi-nfs ``` -Полный каталог аддонов — [addons.md](addons.md). +Полный каталог аддонов — [addons.md](addons.md). Как **добавить собственный** аддон (каталог, плейбук, интеграция в `make` и Molecule) — [custom-addons.md](custom-addons.md). --- diff --git a/docs/make-reference.md b/docs/make-reference.md index 6ed3c50..b64e198 100644 --- a/docs/make-reference.md +++ b/docs/make-reference.md @@ -39,6 +39,7 @@ make install-etcd # Внешний etcd (если k3s_etcd_type=external ```bash make install-addons # Установить все включённые аддоны make addon- # Установить конкретный аддон + # (см. docs/custom-addons.md — как добавить свой) # Примеры: make addon-prometheus-stack diff --git a/docs/molecule-testing.md b/docs/molecule-testing.md index 166a0bd..55360e7 100644 --- a/docs/molecule-testing.md +++ b/docs/molecule-testing.md @@ -18,10 +18,10 @@ make molecule-k3s # запустить тест роли k3s ## Все доступные тесты ```bash -# ─── Роли ────────────────────────────────────────────────────────────────── +# ─── Роли (и legacy-алиасы) ──────────────────────────────────────────────── make molecule-k3s # роль k3s — 3 ноды (master + worker + Debian), ~8-12 мин -make molecule-prometheus # роль prometheus-stack (Helm values шаблоны), ~2-3 мин -make molecule-istio # роль istio + kiali (4 шаблона), ~2-3 мин +make molecule-prometheus # тест аддона prometheus-stack (molecule-addon prometheus-stack), ~2-3 мин +make molecule-istio # тест аддона istio (molecule-addon istio), ~2-3 мин # ─── Кластер (3 master + 2 worker, embedded etcd HA) ─────────────────────── make molecule-cluster # topology тест, ~15-20 мин @@ -95,7 +95,7 @@ make molecule-all Что включает: -- Роли (`k3s`, `prometheus-stack`, `istio`) +- Роль `k3s` и аддонные сценарии `prometheus-stack`, `istio` (через `molecule-addon`, см. [Makefile](../Makefile) `molecule-prometheus` / `molecule-istio`) - Cluster scenario - Все addon-сценарии - Генерацию HTML отчёта @@ -208,9 +208,9 @@ destroy → удалить контейнер(ы) | VIP `192.168.1.100` | kube-vip manifest | Правильный IP в аннотации | -### Роль `prometheus-stack` (~2-3 мин) +### Аддон `prometheus-stack` (~2-3 мин) -Тестирует рендеринг Jinja2-шаблона без privileged режима. +Сценарий: `addons/prometheus-stack/role/molecule/`. Проверяет рендеринг Jinja2-шаблона Helm values без privileged режима. | Проверка | Что именно | @@ -222,9 +222,9 @@ destroy → удалить контейнер(ы) | `nodeExporter.enabled` | `true` | -### Роль `istio` (~2-3 мин) +### Аддон `istio` (~2-3 мин) -Тестирует рендеринг всех четырёх шаблонов роли. +Сценарий: `addons/istio/role/molecule/`. Проверяет рендеринг шаблонов (istiod, Kiali, mesh policy и т.д.). | Файл | Проверка | @@ -433,6 +433,10 @@ molecule destroy -s cluster ## Написание новых тестов для аддонов +Полный сценарий **добавления нового аддона** (не только Molecule, но и `playbook.yml`, `addons.yml`, `Makefile`): [Свои аддоны для k3s-ansible](custom-addons.md). + +Ниже — краткие шаблоны `molecule.yml` / `converge` / `verify`. + ### molecule.yml (шаблон) ```yaml diff --git a/group_vars/all/addons.yml b/group_vars/all/addons.yml index 57a9c32..dfd9bd4 100644 --- a/group_vars/all/addons.yml +++ b/group_vars/all/addons.yml @@ -1,9 +1,7 @@ --- -# ═══════════════════════════════════════════════════════════════════════════════ # Аддоны кластера — выбери что устанавливать # make install-full → core + все аддоны у которых true # make addon- → конкретный аддон напрямую (флаг игнорируется) -# ═══════════════════════════════════════════════════════════════════════════════ addon_nfs_server: false # NFS сервер addon_csi_nfs: false # CSI NFS Driver + StorageClass diff --git a/group_vars/all/main.yml b/group_vars/all/main.yml index cecc99d..28f6f6e 100644 --- a/group_vars/all/main.yml +++ b/group_vars/all/main.yml @@ -1,5 +1,5 @@ --- -# ─── K3S ────────────────────────────────────────────────────────────────────── +# K3S — глобальные переменные play (см. также group_vars/all/addons.yml, vault.yml) k3s_version: "v1.29.3+k3s1" # Тип хранилища etcd: diff --git a/inventory/hosts.ini b/inventory/hosts.ini index fea9ae3..f4e13b0 100644 --- a/inventory/hosts.ini +++ b/inventory/hosts.ini @@ -7,6 +7,8 @@ # k3s_admin_user: devops → ansible_user: "{{ k3s_admin_user }}" # Bootstrap подключается с паролем из host_vars//vault.yml # ───────────────────────────────────────────────────────────────────────────── +# +# Секции ниже (k3s_master, k3s_workers) и ansible_host в inventory. [k3s_master] master01 ansible_host=192.168.1.10