← Ansible
14 мин · средне · Урок 9 из 12

Безопасный прод-запуск

Dry-run через --check и --diff, точечный --limit, теги, и постепенный rolling update через serial. Как катить изменения, не уронив прод.

Прежде чем нажать Enter

Запустить playbook на 50 прод-серверах вслепую рискованно. Один неверный шаблон, одна лишняя задача — и сервис лежит у всех сразу.

Ansible даёт набор инструментов, чтобы смотреть перед прыжком и ограничивать радиус взрыва. В этом уроке разберём эти инструменты.

--check: dry-run

Флаг --check говорит Ansible: иди по всем задачам, но ничего не меняй. Вместо реальных действий — отчёт о том, что изменилось бы.

ansible-playbook -i inventory.ini site.yml --check

Это полезно для первичного "а что вообще поменяется?" перед реальным прогоном.

Важная оговорка: некоторые задачи в check-режиме дают неточный результат. Например, если первая задача должна была создать файл, а вторая читает из него - вторая в dry-run увидит, что файла нет, и может репортить неверно.

Управлять поведением конкретной задачи можно через check_mode. Ключ принудительно фиксирует режим для этой задачи и перебивает то, что пришло из командной строки:

- name: сбор данных, выполняется по-настоящему даже при --check
  command: /usr/local/bin/healthcheck.sh
  check_mode: false

- name: только отчёт, никогда ничего не меняет
  ansible.builtin.lineinfile:
    path: /etc/motd
    line: "managed by ansible"
  check_mode: true

Тут легко ошибиться в чтении. check_mode: true не значит «задача только для dry-run и в обычном прогоне пропускается». Задача выполняется всегда, но всегда в check-режиме: Ansible посчитает и покажет, что изменилось бы, и ничего не тронет. Обычный ansible-playbook site.yml её выполнит — просто вхолостую.

Обратный ключ check_mode: false нужен как раз для случая из абзаца выше: задача, результат которой читают следующие. Такой сбор данных пускают по-настоящему всегда, иначе весь остальной dry-run посчитает чушь. Ставить его на что-то, что реально меняет систему, нельзя — --check перестанет быть безопасным.

--diff: построчный diff

--diff показывает, как изменится содержимое файлов и шаблонов — до и после, в формате unified diff.

ansible-playbook -i inventory.ini site.yml --diff

Работает и без --check — тогда изменения реальные, но ты видишь их в выводе.

Стандартная связка перед деплоем:

ansible-playbook -i inventory.ini site.yml --check --diff

Сначала смотришь, что изменится, убеждаешься, что всё правильно — потом запускаешь без --check.

--limit: точечный запуск

По умолчанию play выполняется на всех хостах из hosts:. Флаг --limit (или -l) сужает до конкретного хоста или группы:

# только один хост
ansible-playbook -i inventory.ini site.yml --limit web-1

# только группа
ansible-playbook -i inventory.ini site.yml --limit webservers

# комбинация: сначала dry-run на одном
ansible-playbook -i inventory.ini site.yml --limit web-1 --check --diff

Удобный сценарий: прогнать --check --diff на одном хосте, убедиться, что шаблон рендерится правильно, и только потом запускать на всей группе.

Теги

Большой playbook часто не нужен целиком — нужна только часть. Теги позволяют помечать задачи и запускать только нужные.

Тег вешается на задачу, блок или роль:

- name: Deploy application
  copy:
    src: app.tar.gz
    dest: /opt/app/
  tags:
    - deploy

- name: Run DB migrations
  command: /opt/app/migrate.sh
  tags:
    - deploy
    - migrations

- name: Restart nginx
  service:
    name: nginx
    state: restarted
  tags:
    - nginx

Запуск только задач с тегом:

ansible-playbook -i inventory.ini site.yml --tags deploy
# или сокращённо
ansible-playbook -i inventory.ini site.yml -t deploy

Пропустить задачи с тегом:

ansible-playbook -i inventory.ini site.yml --skip-tags slow

Два специальных тега:

--start-at-task: продолжить с места падения

Если playbook упал на середине и ты уже починил проблему, можно не гнать всё с начала:

ansible-playbook -i inventory.ini site.yml --start-at-task "Deploy application"

Ansible пропустит задачи до указанной и начнёт с неё. Имя задачи — точное совпадение с полем name:.

serial: rolling update

По умолчанию Ansible работает со всеми хостами плея одновременно, ограничиваясь только количеством параллельных соединений (--forks, умолчание 5). То есть при 50 хостах он продвигает задачи через все 50 батчами по 5 за раз, но play "завершается", только когда все 50 прошли.

serial: меняет это: хосты разбиваются на пакеты, и play полностью завершается на одном пакете перед тем как начать следующий.

- name: Rolling deploy
  hosts: webservers
  serial: 2
  tasks:
    - name: deploy app
      # ...

С serial: 2 Ansible возьмёт 2 хоста, прогонит весь play, потом следующие 2, и так до конца. Пока обновляются двое — остальные продолжают принимать трафик.

serial принимает:

Компаньон к serial — max_fail_percentage: если в батче упало больше этого процента хостов, Ansible остановит раскатку не трогая остальные:

- name: Rolling deploy
  hosts: webservers
  serial: 2
  max_fail_percentage: 50
  tasks:
    - name: deploy app
      # ...

--forks vs serial

Частое смешение понятий:

Простая аналогия: serial: 10 с --forks 5 — берём 10 хостов в батч, но обрабатываем их параллельно по 5.

serial: 2 - rolling update (6 серверов, батч за батчем) load balancer web-1 live web-2 live web-3 live web-4 live web-5 live web-6 live batch 1 batch 2 batch 3
Пока батч обновляется, остальные серверы держат трафик. Поэтому раскатка не роняет сервис целиком.

Реальный сценарий

Типичный безопасный деплой выглядит так:

  1. Dry-run на одном хосте — проверяешь, что шаблон правильный:
ansible-playbook -i inventory.ini site.yml --limit web-1 --check --diff
  1. Если всё нормально — катишь rolling update на все:
ansible-playbook -i inventory.ini site.yml

Если playbook настроен с serial: 2 и max_fail_percentage: 50, то при падении двух хостов подряд раскатка остановится, не тронув оставшиеся.

Что важно запомнить

В следующем уроке — динамический inventory для облаков и коллекции Galaxy.

Самопроверка

Впишите команду / ключевую строку. Регистр и пробелы не важны.

1. Прогнать playbook site.yml вхолостую с показом построчного diff (инвентарь inventory.ini).
2. Запустить только задачи с тегом deploy (playbook site.yml, инвентарь inventory.ini).

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Playbook упал на хосте 47 из 200. Что должно произойти с остальными 153 и как настроить поведение явно (`any_errors_fatal`, `max_fail_percentage`, `serial`)?

ANS-028
02

Что делает параметр `serial` и как через Ansible организовать честный rolling update с health-чеками?

ANS-020
03

Performance: forks, pipelining, fact caching, async tasks — как выжать из Ansible на 1000+ хостов.

ANS-025
04

`--check` и `--diff`: что они реально гарантируют, а что — нет?

ANS-026

Прошли материал до конца? Отметьте урок пройденным.