Модули - кирпичики автоматизации
Урок 8 - знакомимся с модулями: готовыми кирпичиками для управления системой.
«Под каждую типовую задачу - свой модуль. Не пиши shell-команду там, где есть готовый идемпотентный модуль».
Модуль - это готовая единица работы: «управляй пакетом», «управляй файлом», «управляй сервисом», «управляй пользователем». Ansible поставляется с сотнями модулей. Большинство из них идемпотентны: сначала проверяют текущее состояние, и меняют что-то, только если нужно.
Ключевые модули
| Модуль | Назначение |
|---|---|
ansible.builtin.apt / yum / dnf | Управление пакетами |
ansible.builtin.copy | Скопировать файл на хост |
ansible.builtin.template | Сгенерировать файл из Jinja2-шаблона |
ansible.builtin.file | Создать каталог, задать права, симлинк |
ansible.builtin.service | Управление сервисами (start/stop/restart) |
ansible.builtin.user | Создание и удаление пользователей |
ansible.builtin.lineinfile | Точечная правка строки в файле |
FQCN - полные имена
Современная практика - использовать FQCN (Fully Qualified Collection Name): не apt, а ansible.builtin.apt. Это убирает двусмысленность, когда несколько коллекций содержат модули с одинаковыми короткими именами. Формат: пространство.коллекция.модуль.
- name: Создать каталог приложения
ansible.builtin.file:
path: /opt/myapp
state: directory
owner: deploy
mode: "0755"
- name: Завести пользователя deploy
ansible.builtin.user:
name: deploy
groups: sudo
shell: /bin/bash
Как работает под капотом
Каждый модуль - это маленькая программа на Python. Она принимает параметры (как name=nginx state=present), смотрит текущее состояние системы, сравнивает с желаемым и применяет минимально необходимое изменение. Возвращает JSON со статусом changed или нет. Именно поэтому модули идемпотентны «из коробки» - сравнение состояний встроено в них.
Смоделируем логику модуля file для каталога: создаём, только если его нет.
# Имитация модуля file (state=directory): идемпотентное создание
existing_dirs = {"/opt", "/etc/myapp"}
def ensure_directory(path, dirs):
if path in dirs:
return {"changed": False, "path": path}
dirs.add(path)
return {"changed": True, "path": path}
print(ensure_directory("/opt/myapp", existing_dirs)) # changed: True
print(ensure_directory("/opt/myapp", existing_dirs)) # changed: False
print(ensure_directory("/etc/myapp", existing_dirs)) # changed: False (уже есть)
Попробуй сам ▶ Модуль не «создаёт каталог», он «обеспечивает, чтобы каталог существовал». Разница тонкая, но именно она делает повторные запуски безопасными.
Частые ошибки
- Mode как число без кавычек.
mode: 0755YAML может прочитать как восьмеричное/десятичное число неожиданно. Пиши строкой:mode: "0755". - Сырой shell вместо модуля.
shell: "useradd deploy"не идемпотентен и упадёт при повторе. Есть модульuser. - Игнорировать документацию. У каждого модуля свои параметры;
ansible-doc ansible.builtin.fileпокажет их все.
Best practices
- Используй FQCN везде - это снимает конфликты имён и читается однозначно.
- Предпочитай специализированный модуль сырому command/shell - почти всегда он есть.
- Изучай
ansible-doc <модуль>- там примеры и все параметры.
В реальной работе
Перед тем как тянуться к shell, опытный инженер сначала ищет специализированный модуль - почти всегда он есть. Нужно поправить одну строку в конфиге? Есть lineinfile. Добавить блок? blockinfile. Управлять записью в crontab? cron. Смонтировать диск? mount. Каждый такой модуль идемпотентен и понимает контекст задачи, тогда как shell - это слепое выполнение без проверки состояния. Команда ansible-doc с именем модуля показывает все параметры и готовые примеры прямо в терминале - это быстрее, чем гуглить, и всегда соответствует установленной версии. Знание десятка ключевых модулей покрывает 90% повседневных задач настройки серверов.
Итоги
Модули - идемпотентные кирпичики для управления пакетами, файлами, сервисами и пользователями. Современная практика - вызывать их по FQCN. Каждый модуль сам сравнивает текущее и желаемое состояние. Дальше углубимся в саму идемпотентность.