Ansible: рестарт контейнеров переведён на handlers
- caddyproxy, netdata, authelia, bifrost, remembos: конфиг-задачи нотифаят handler "Restart application" вместо безусловного или условного рестарта - ansible.cfg: force_handlers, иначе упавший прогон теряет notify и рестарт, применяющий правку конфига, не случится уже никогда - authelia рестартит только authelia_app, чтобы не сбрасывать сессии в redis
This commit is contained in:
@@ -2,3 +2,8 @@
|
||||
host_key_checking = True
|
||||
vault_password_file = ./ansible-vault-password-file
|
||||
roles_path = ./galaxy.roles
|
||||
|
||||
# Выполнять handlers даже если play упал: иначе упавший прогон теряет
|
||||
# накопленные notify, а на следующем конфиг уже не changed — и рестарт,
|
||||
# применяющий правку, не случится никогда.
|
||||
force_handlers = True
|
||||
|
||||
@@ -21,7 +21,6 @@ _(sec-ревью)_ — три независимых security-ревью на м
|
||||
- [Убрать группу `docker` у сервисных пользователей](service-users-docker-group.md) — `docker` = root на хосте; ~все app-аккаунты фактически root, изоляция «юзер на сервис» обнуляется _(sec-ревью)_
|
||||
- [Изолировать/запаролить сессионный redis Authelia](authelia-redis-isolation.md) — стор сессий SSO в общей сети без пароля; запись в него = hijack SSO всех сервисов _(sec-ревью)_
|
||||
- [Алерты на проблемные контейнеры](container-alerts.md) — wakapi крутился в restart-loop несколько дней незамеченным; healthcheck в compose + алерты Netdata
|
||||
- [Рестарт контейнеров через handlers](ansible-handlers-restart.md) — `state: restarted` выполняется безусловно на каждом прогоне (лишний downtime), нет ни одного handler _(ансибл-ревью)_
|
||||
|
||||
## Средний
|
||||
|
||||
@@ -36,6 +35,7 @@ _(sec-ревью)_ — три независимых security-ревью на м
|
||||
- [Gitea runner on-demand в Yandex Cloud](gitea-runner-on-demand.md) — раннер активен только во время сборки; webhook→Cloud Function стартует ВМ, probe/decide гасят по idle; экономия ~95%
|
||||
- [Синхронизация общих Ansible-ролей](shared-roles-sync.md) — `owner`/`eget`/`secrets` дублируются между репозиториями и дрейфуют; канон в ansible-shared + rsync-таски invoke
|
||||
- [Уведомления о размере приложений и диске](disk-usage-alerts.md) — алерты на заполнение диска и аномальный рост data-томов; сервер ресурсно ограничен _(tududi)_
|
||||
- [Handlers рестарта для оставшихся приложений](handlers-remaining-apps.md) — apprise/dashboard/transcriber/miniflux монтируют конфиг в контейнер, но рестарта нет вовсе; правка конфига не подхватывается
|
||||
- [Composable-роль `backup`](ansible-backup-role.md) — бэкап — самый чистый шов для extraction (одинаков у всех, различается только список targets) _(ансибл-ревью)_
|
||||
- [Точечные фиксы идемпотентности и баг имени play](ansible-quick-fixes.md) — быстрые правки: имя play в wanderer, `changed_when` в netdata/eget, backup-targets через template _(ансибл-ревью)_
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Рестарт контейнеров через handlers, а не безусловно
|
||||
|
||||
**Приоритет:** высокий
|
||||
|
||||
Ни в одном плейбуке нет `handlers:`. Вместо этого задача `state: restarted`
|
||||
выполняется **всегда** — рестартит контейнер на каждом прогоне даже без
|
||||
изменений (`playbook-caddyproxy.yml:106`, `playbook-netdata.yml:143`,
|
||||
`playbook-authelia.yml:92`): не идемпотентно, лишний downtime. В
|
||||
`playbook-gitea.yml` рестарта нет вовсе — несогласованность. Канонический
|
||||
паттерн: шаблон конфига `notify`-ит handler, который делает
|
||||
`docker_compose_v2: state: restarted` только при реальном изменении. Внедряется
|
||||
инкрементально, по одному сервису. Заодно убрать мёртвый
|
||||
`docker_compose_file_result` в `playbook-memos.yml:76` (регистрируется, нигде не
|
||||
используется — задумывался под `when`/`notify`).
|
||||
|
||||
Топ-приоритет ансибл-ревью. Полный контекст:
|
||||
[docs/drafts/ansible-review.md](../drafts/ansible-review.md) §3.
|
||||
|
||||
Связано: playbook-caddyproxy.yml, playbook-netdata.yml, playbook-authelia.yml,
|
||||
playbook-gitea.yml, playbook-memos.yml.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Handlers рестарта для оставшихся приложений
|
||||
|
||||
**Приоритет:** средний
|
||||
|
||||
Паттерн `handlers` + `notify` внедрён в caddyproxy, netdata, authelia, bifrost,
|
||||
remembos (см. задачу `ansible-handlers-restart`, закрыта). Остались плейбуки, где
|
||||
конфиг bind-моунтится в контейнер, но рестарта нет **вообще** — правка конфига без
|
||||
изменения docker-compose.yml не подхватывается до следующего пересоздания
|
||||
контейнера:
|
||||
|
||||
- `playbook-apprise.yml` — `server.cfg` → `config_dir:/config`.
|
||||
- `playbook-dashboard.yml` — `config/*.yaml` → `config_dir:/app/config`.
|
||||
- `playbook-transcriber.yml` — `config.toml` bind-моунтится **отдельным файлом**
|
||||
(`{{ config_file }}:/config/config.toml:ro`). Худший случай: `template`
|
||||
перезаписывает файл с новым inode, и контейнер продолжает видеть старый до
|
||||
рестарта.
|
||||
- `playbook-miniflux.yml` — файлы секретов роли `secrets` → `secrets_dir:/secrets:ro`,
|
||||
читаются через `*_FILE` при старте.
|
||||
|
||||
Заодно проверить `playbook-goaccess.yml`: конфиг там не монтируется, но
|
||||
`Dockerfile`/`entrypoint.sh` меняются без изменения compose-файла — надо
|
||||
убедиться, что `build: always` действительно пересоздаёт контейнер.
|
||||
|
||||
Отдельный кандидат: caddy сейчас перезапускается целиком, хотя умеет
|
||||
`caddy reload` — применение Caddyfile без разрыва соединений на реверс-прокси,
|
||||
через который идёт весь трафик. В `playbook-caddyproxy.yml` для этого уже лежит
|
||||
закомментированный блок с `docker_compose_v2_exec`.
|
||||
|
||||
Связано: playbook-apprise.yml, playbook-dashboard.yml, playbook-transcriber.yml,
|
||||
playbook-miniflux.yml, playbook-goaccess.yml, playbook-caddyproxy.yml.
|
||||
+10
-1
@@ -46,6 +46,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy configuration file"
|
||||
ansible.builtin.template:
|
||||
@@ -54,6 +55,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy gobackup config"
|
||||
ansible.builtin.template:
|
||||
@@ -87,9 +89,16 @@
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
- name: "Restart application with docker compose"
|
||||
handlers:
|
||||
# Приложение читает конфиги только при старте, а `state: present` не
|
||||
# пересоздаёт контейнер, если docker-compose.yml не изменился, — поэтому
|
||||
# правку конфига применяет только явный рестарт.
|
||||
- name: "Restart application"
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
# Только сам authelia: рестарт redis сбросил бы сессии всех сервисов.
|
||||
services:
|
||||
- "authelia_app"
|
||||
state: "restarted"
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
register: config_file_result
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
@@ -51,7 +51,6 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
register: docker_compose_file_result
|
||||
|
||||
- name: "Run application with docker compose"
|
||||
community.docker.docker_compose_v2:
|
||||
@@ -61,15 +60,13 @@
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
# Bifrost читает config.json только при старте. Если изменился лишь конфиг
|
||||
# (а compose — нет), `state: present` не пересоздаёт контейнер, и правки
|
||||
# (ротация ключа, смена модели/правил) не подхватятся — нужен явный рестарт.
|
||||
- name: "Restart docker compose services if config changed but not docker-compose.yml"
|
||||
handlers:
|
||||
# Приложение читает конфиги только при старте, а `state: present` не
|
||||
# пересоздаёт контейнер, если docker-compose.yml не изменился, — поэтому
|
||||
# правку конфига применяет только явный рестарт.
|
||||
- name: "Restart application"
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
state: "restarted"
|
||||
when:
|
||||
- config_file_result.changed
|
||||
- not docker_compose_file_result.changed
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
@@ -99,7 +100,11 @@
|
||||
# tags:
|
||||
# - run-app
|
||||
|
||||
- name: "Restart application with docker compose"
|
||||
handlers:
|
||||
# Приложение читает конфиги только при старте, а `state: present` не
|
||||
# пересоздаёт контейнер, если docker-compose.yml не изменился, — поэтому
|
||||
# правку конфига применяет только явный рестарт.
|
||||
- name: "Restart application"
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
state: "restarted"
|
||||
|
||||
@@ -69,7 +69,6 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
register: docker_compose_file_result
|
||||
|
||||
- name: "Run application with docker compose"
|
||||
community.docker.docker_compose_v2:
|
||||
|
||||
+11
-1
@@ -44,6 +44,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Find all go.d plugin config files"
|
||||
ansible.builtin.find:
|
||||
@@ -60,6 +61,7 @@
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
loop: "{{ go_d_source_files.files }}"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Find existing go.d config files on server"
|
||||
ansible.builtin.find:
|
||||
@@ -73,6 +75,7 @@
|
||||
state: absent
|
||||
loop: "{{ go_d_existing_files.files }}"
|
||||
when: (item.path | basename) not in (go_d_source_files.files | map(attribute='path') | map('basename') | list)
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Find all health.d config files"
|
||||
ansible.builtin.find:
|
||||
@@ -89,6 +92,7 @@
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
loop: "{{ health_d_source_files.files }}"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Find existing health.d config files on server"
|
||||
ansible.builtin.find:
|
||||
@@ -102,6 +106,7 @@
|
||||
state: absent
|
||||
loop: "{{ health_d_existing_files.files }}"
|
||||
when: (item.path | basename) not in (health_d_source_files.files | map(attribute='path') | map('basename') | list)
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy health alarm notify config"
|
||||
ansible.builtin.template:
|
||||
@@ -110,6 +115,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Grab docker group id."
|
||||
ansible.builtin.shell:
|
||||
@@ -136,7 +142,11 @@
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
- name: "Restart application with docker compose"
|
||||
handlers:
|
||||
# Приложение читает конфиги только при старте, а `state: present` не
|
||||
# пересоздаёт контейнер, если docker-compose.yml не изменился, — поэтому
|
||||
# правку конфига применяет только явный рестарт.
|
||||
- name: "Restart application"
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
state: "restarted"
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
register: config_file_result
|
||||
notify: "Restart application"
|
||||
|
||||
- name: "Copy docker compose file"
|
||||
ansible.builtin.template:
|
||||
@@ -50,7 +50,6 @@
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0640"
|
||||
register: docker_compose_file_result
|
||||
|
||||
- name: 'Login to Yandex Container Registry'
|
||||
community.docker.docker_login:
|
||||
@@ -66,12 +65,13 @@
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
- name: "Restart docker compose services if config changed but not docker-compose.yml"
|
||||
handlers:
|
||||
# Приложение читает конфиги только при старте, а `state: present` не
|
||||
# пересоздаёт контейнер, если docker-compose.yml не изменился, — поэтому
|
||||
# правку конфига применяет только явный рестарт.
|
||||
- name: "Restart application"
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ base_dir }}"
|
||||
state: "restarted"
|
||||
when:
|
||||
- config_file_result.changed
|
||||
- not docker_compose_file_result.changed
|
||||
tags:
|
||||
- run-app
|
||||
|
||||
Reference in New Issue
Block a user