Ansible Best Practices
Справочник: Правила написания поддерживаемого, идемпотентного и безопасного кода. Каждый пункт — конкретный пример «плохо → хорошо».
1. Структура и организация
Используйте роли
# ✗ Плохо: site.yml на 500 строк
- hosts: all
tasks:
- name: Install nginx ...
- name: Configure nginx ...
# ... 200 задач ...
# ✓ Хорошо: site.yml вызывает роли
- hosts: webservers
roles:
- common
- nginx
- appИменование переменных с префиксом роли
Ansible имеет плоское пространство имён. Переменная port в одной роли перезапишет port в другой.
# ✗ Плохо
port: 80
user: deploy
# ✓ Хорошо
nginx_port: 80
app_deploy_user: deploy
postgres_port: 5432FQCN для модулей
# ✗ Устаревший стиль
- apt: name=nginx
# ✓ Рекомендуется (с Ansible 2.10+)
- ansible.builtin.apt:
name: nginx
state: presentВсегда указывайте name
# ✗ Плохо — нечитаемые логи
- apt: name=nginx state=present
# ✓ Хорошо
- name: Install Nginx
ansible.builtin.apt:
name: nginx
state: present2. Идемпотентность
Playbook должен быть безопасен для повторного запуска.
Shell/command → модули
# ✗ Плохо: НЕ идемпотентно (каждый запуск добавляет строку)
- shell: echo "export FOO=bar" >> ~/.bashrc
# ✓ Хорошо: идемпотентно
- ansible.builtin.lineinfile:
path: ~/.bashrc
line: "export FOO=bar"
state: present
# ✗ Плохо: shell вместо модуля
- shell: git clone https://github.com/org/app.git /opt/app
# ✓ Хорошо: модуль идемпотентен
- ansible.builtin.git:
repo: https://github.com/org/app.git
dest: /opt/app
version: mainЕсли shell неизбежен — используйте guards
# ✓ creates — не выполнять если файл уже есть
- ansible.builtin.command: /opt/app/install.sh
args:
creates: /opt/app/.installed
# ✓ changed_when — для read-only команд
- ansible.builtin.command: python3 --version
register: py_version
changed_when: false3. Безопасность
Секреты — только через Vault
# ✗ Плохо: пароль в открытом виде
vars:
db_password: "SuperSecret123"
# ✓ Хорошо: ссылка на vault
vars:
db_password: "{{ vault_db_password }}"no_log для чувствительных задач
- name: Set database password
ansible.builtin.command: >
psql -c "ALTER USER app PASSWORD '{{ db_password }}'"
no_log: true # пароль не попадёт в логHost key checking в production
# ansible.cfg
# ✗ Удобно для dev, ОПАСНО для prod
host_key_checking = False
# ✓ В production: управлять known_hosts явно
# ssh-keyscan host >> ~/.ssh/known_hosts4. Производительность
Отключить gather_facts если не нужны
- hosts: webservers
gather_facts: no # экономит ~2 сек на хост
tasks:
- name: Restart app
ansible.builtin.systemd:
name: myapp
state: restartedPipelining
# ansible.cfg — ускорение в 3-5 раз
[ssh_connection]
pipelining = TrueForks
# ansible.cfg — параллельные подключения (по умолчанию 5)
[defaults]
forks = 20Передавать список в модуль вместо loop
# ✗ Медленно: N SSH-операций
- ansible.builtin.apt:
name: "{{ item }}"
state: present
loop:
- git
- curl
- vim
# ✓ Быстро: 1 SSH-операция
- ansible.builtin.apt:
name:
- git
- curl
- vim
state: present5. Отладка и CI
Линтер
pip install ansible-lint
ansible-lint playbooks/ roles/Тестирование ролей
pip install molecule molecule-plugins[docker]
molecule testПроверка перед деплоем
ansible-playbook site.yml --syntax-check # синтаксис
ansible-playbook site.yml --check --diff # dry run + diff
ansible-playbook site.yml --list-tasks # список задачЧек-лист
- Каждая задача имеет
name - Модули вместо shell/command где возможно
- FQCN для модулей (
ansible.builtin.aptвместоapt) - Переменные с префиксом роли (
nginx_port, неport) - Секреты в Vault,
no_log: trueдля чувствительных задач -
changed_when: falseдля read-only команд -
pipelining = Trueв ansible.cfg -
ansible-lintв CI pipeline - Molecule-тесты для ролей
-
--check --diffперед production-деплоем