Блог "Дети ОИТа"
/поиск

Роли Ansible: layout, defaults, handlers и production-ready шаблонизация

Как правильно структурировать роли Ansible. Разбираем layout, разницу между defaults и vars, работу handlers и безопасную шаблонизацию.


title: «Роли Ansible: layout, defaults, handlers и production-ready шаблонизация»
date: 2026-10-11T06:50:00Z
status: published
categories: [«Системное администрирование»]
tags: [«ansible», «roles», «layout», «defaults», «vars», «handlers», «templating», «dependencies», «testing»]
excerpt: «Как писать роли, которые легко переиспользовать и не страшно передавать команде. Полный гайд: layout, defaults vs vars, handlers, зависимости и тестирование.»
readingMinutes: 5
featuredImage: «/images/ansible-role-architecture.png»

Роли Ansible: production-ready layout и управление переменными

Роль — это атом инфраструктуры. Хорошо написанная роль переиспользуется годами, плохо написанная — приносит хаос. Разбираем, как структурировать роли для production.

1. Layout: стандартная структура

roles/nginx/
├── defaults/
│   └── main.yml          # 'Ручки', легко переопределить
├── vars/
│   └── main.yml          # Политики, переопределить сложно
├── tasks/
│   ├── main.yml
│   ├── setup.yml
│   └── config.yml
├── handlers/
│   └── main.yml
├── templates/
│   ├── nginx.conf.j2
│   └── vhost.conf.j2
├── files/
│   └── static-site.tar.gz
├── meta/
│   └── main.yml          # Зависимости
├── tests/
│   ├── inventory
│   ├── test.yml
│   └── verify.yml
└── README.md

Правило: Никаких задач в tasks/main.yml. Только импорты:

# roles/nginx/tasks/main.yml
- import_tasks: setup.yml
- import_tasks: config.yml

2. defaults vs vars: золотое правило

Файл Приоритет Что хранить
defaults/main.yml Самый низкий «Ручки» (tunable knobs): порты, версии, флаги
vars/main.yml Высокий Политики: пути, имена пакетов, жёсткие константы

Пример defaults/main.yml:

nginx_version: "1.24"
 nginx_worker_processes: auto
 nginx_client_max_body_size: 10m
 use_ssl: true

Пример vars/main.yml:

nginx_user: nginx
nginx_group: nginx
nginx_conf_dir: /etc/nginx
nginx_pid_file: /run/nginx.pid

Почему так?
Пользователь роли должен легко поменять версию (nginx_version: "1.26"), но не должен случайно сломать путь к конфигам.

3. Handlers: группировка и listen

# roles/nginx/tasks/config.yml
- name: Deploy main config
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf
  notify: Reload nginx

- name: Deploy vhost
  template:
    src: vhost.conf.j2
    dest: /etc/nginx/conf.d/app.conf
  notify: Reload nginx

# roles/nginx/handlers/main.yml
- name: Reload nginx
  listen: "web services"  # Группировка
  ansible.builtin.service:
    name: nginx
    state: reloaded

Группировка через listen:
Другие роли тоже могут уведомить web services:

# roles/app/handlers/main.yml
- name: Restart php-fpm
  listen: "web services"
  ansible.builtin.service:
    name: php-fpm
    state: restarted

Теперь один notify перезапустит и nginx, и php-fpm.

4. Шаблоны: Jinja2 best practices

Используйте значения по умолчанию в шаблонах:

worker_processes {{ nginx_worker_processes | default('auto') }};
pid {{ nginx_pid_file | default('/run/nginx.pid') }};

Для статики — copy, для конфигов — template:

# Статика (не рендерится)
- name: Deploy static assets
  copy:
    src: static-site.tar.gz
    dest: /var/www/

# Конфиг (рендерится Jinja2)
- name: Deploy nginx config
  template:
    src: nginx.conf.j2
    dest: /etc/nginx/nginx.conf

Lookup-помощники:

- name: Deploy from template string
  ansible.builtin.copy:
    content: "{{ lookup('template', 'templates/inline.conf.j2') }}"
    dest: /etc/app/inline.conf

5. Зависимости: meta/main.yml

Если вашей роли нужен postgresql:

# roles/nginx/meta/main.yml
dependencies:
  - role: postgresql
    vars:
      postgresql_version: "15"
      postgresql_shared_buffers: "256MB"

Галактика (requirements.yml):

# requirements.yml
roles:
  - name: geerlingguy.nginx
    version: "4.0.0"
  - name: geerlingguy.php
    version: "3.5.0"

Установка:

ansible-galaxy install -r requirements.yml

6. Тестирование роли (Molecule)

molecule.yml:

dependency:
  name: galaxy
driver:
  name: docker
platforms:
  - name: instance
    image: ubuntu:22.04
    pre_build_image: true
provisioner:
  name: ansible
verifier:
  name: ansible
lint: |
  yamllint .
  ansible-lint

verify.yml:

- name: Verify
  hosts: all
  tasks:
    - name: Check nginx is running
      ansible.builtin.service:
        name: nginx
        state: started
    - name: Check port 80
      ansible.builtin.wait_for:
        port: 80

7. Precedence (приоритеты) — памятка

От высшего к низшему:

  1. --extra-vars (CLI)
  2. Play vars / vars_prompt
  3. Block vars
  4. Role vars (vars/main.yml)
  5. Role defaults (defaults/main.yml)
  6. Inventory group_vars/host_vars
  7. Facts

Практика: Держите «ручки» в defaults, политики — в vars. Секреты — вне VCS (Vault/SOPS).

8. Production-ready чек-лист

  • Layout: defaults/, vars/, tasks/ (с импортами), handlers/, templates/, meta/.
  • В defaults/ только «ручки», в vars/ только политики.
  • Handlers сгруппированы через listen.
  • Зависимости прописаны в meta/main.yml.
  • Есть requirements.yml для galaxy-ролей.
  • Роль покрыта Molecule тестами (converge + verify).
  • Шаблоны используют | default().
  • Документация всех переменных в defaults/main.yml.
  • Нет command/shell без creates/removes.

См. также