Ответ
Идемпотентность — одно из ключевых преимуществ Ansible, но не все модули ей обладают по своей природе. Основные неидемпотентные модули, с которыми нужно работать аккуратно:
-
commandиshell: Выполняют произвольную команду в shell. Ansible не может проверить состояние системы до и после, поэтому таск будет выполняться при каждом запуске плейбука. Это основная причина неожиданных изменений.# НЕИДЕМПОТЕНТНО: выполнится всегда - name: Restart service crudely command: systemctl restart myservice -
raw: Аналогиченcommand, но работает даже на системах без Python (используется для bootstrap). Также неидемпотентен. -
setup/gather_facts: Собирает факты о хостах. Хотя сам по себе сбор фактов идемпотентен (информация просто обновляется), этот таск всегда выполняется, если не отключен явно.
Как обеспечить идемпотентность с этими модулями?
-
Использовать параметры
createsилиremoves: Ansible проверит существование файла и выполнит команду, только если его нет (или есть).- name: Run database migration script only once command: /opt/app/migrate.sh args: creates: /opt/app/.migration_done # Команда выполнится, только если этот файл не существует -
Использовать параметр
changed_when: Позволяет вручную указать, привел ли таск к изменениям. Например, можно парсить вывод команды.- name: Check if a process is running shell: ps aux | grep myapp | grep -v grep register: process_status changed_when: false # Помечаем, что таск никогда не вносит изменений failed_when: process_status.rc != 0 # Но может упасть, если процесс не найден -
Заменить специализированным идемпотентным модулем: Всегда это предпочтительный путь.
- Вместо
command: systemctl restart X→ использовать модульservice(state: restarted). - Вместо
shell: apt-get install nginx→ использовать модульapt(state: present).
- Вместо
-
Использовать
check_mode(--check): Перед запуском на production всегда полезно проверить плейбук в режиме симуляции, чтобы увидеть, какие неидемпотентные таски были бы выполнены.