Рекомендованные практики
Ниже приведены некоторые советы по эффективному использованию Ansible и Ansible playbooks.
Примеры playbooks, демонстрирующие эти лучшие практики, можно найти в нашем репозитории ansible-examples. (ПРИМЕЧАНИЕ: эти примеры могут не использовать все функции последней версии, но все равно являются отличной справочной информацией!).
-
Организация контента
- Структура каталогов
- Альтернативная структура каталогов
- Использование динамической инвентаризации с облаками
- Различия между этапами разработки (staging) и производства (production)
- Переменные групп и хостов
- Разделение playbooks верхнего уровня по ролям
- Организация задач и обработчиков для роли
- Возможности данной организации (примеры)
- Организация развертывания и конфигурации
- Различия между этапами разработки (staging) и производства (production)
- Постепенные обновления
- Всегда указывайте состояние
- Группировка по ролям
- Отличия в операционных системах и дистрибутивах
- Использование модулей Ansible в playbooks
- Отступы и комментарии
- Всегда присваивайте имена задачам
- Делайте всё просто
- Система управления версиями
- Переменные и хранилища
Организация контента
В следующем разделе показан один из многих возможных способов организации содержимого playbook.
Ваше использование Ansible должно соответствовать вашим потребностям, а не нашим, поэтому не стесняйтесь изменять этот подход и организовывать его так, как вам удобно.
Один из ключевых способов организации содержимого playbook — это функция организации «ролей» Ansible, которая документирована на странице основных playbooks. Вы должны потратить время на чтение и понимание документации по ролям, которая доступна здесь: Роли.
Структура каталогов
Верхний уровень каталога будет содержать файлы и каталоги следующим образом:
production # inventory file for production servers
staging # inventory file for staging environment
group_vars/
group1.yml # here we assign variables to particular groups
group2.yml
host_vars/
hostname1.yml # here we assign variables to particular systems
hostname2.yml
library/ # if any custom modules, put them here (optional)
module_utils/ # if any custom module_utils to support modules, put them here (optional)
filter_plugins/ # if any custom filter plugins, put them here (optional)
site.yml # master playbook
webservers.yml # playbook for webserver tier
dbservers.yml # playbook for dbserver tier
roles/
common/ # this hierarchy represents a "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies
library/ # roles can also include custom modules
module_utils/ # roles can also include custom module_utils
lookup_plugins/ # or other types of plugins, like lookup in this case
webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""
Альтернативная структура каталогов
Альтернативно, вы можете поместить каждый файл инвентаризации со своими group_vars/host_vars в отдельный каталог. Это особенно полезно, если ваши group_vars/host_vars не имеют много общего в разных средах. Структура может выглядеть примерно так:
inventories/
production/
hosts # inventory file for production servers
group_vars/
group1.yml # here we assign variables to particular groups
group2.yml
host_vars/
hostname1.yml # here we assign variables to particular systems
hostname2.yml
staging/
hosts # inventory file for staging environment
group_vars/
group1.yml # here we assign variables to particular groups
group2.yml
host_vars/
stagehost1.yml # here we assign variables to particular systems
stagehost2.yml
library/
module_utils/
filter_plugins/
site.yml
webservers.yml
dbservers.yml
roles/
common/
webtier/
monitoring/
fooapp/
Эта структура предоставляет большую гибкость для больших сред, а также полное разделение переменных инвентаризации между различными средами. Недостатком является то, что ее сложнее поддерживать, потому что файлов больше.
Использование динамической инвентаризации с облаками
Если вы используете облачного провайдера, вам не следует управлять своей инвентаризацией в статическом файле. См. Работа с динамической инвентаризацией.
Это относится не только к облакам. Если у вас есть другая система, которая поддерживает канонический список систем в вашей инфраструктуре, использование динамической инвентаризации — хорошая идея в целом.
Различия между этапами разработки (staging) и производства (production)
Если вы управляете статической инвентаризацией, часто возникает вопрос о том, как различать различные типы сред. Следующий пример показывает хороший способ сделать это. Аналогичные методы группировки могут быть адаптированы к динамической инвентаризации (например, рассмотрите применение тега AWS «environment:production», и вы получите группу систем с автоматически обнаруженным именем «ec2_tag_environment_production»).
Давайте рассмотрим пример статической инвентаризации. Ниже в файле production содержится инвентаризация всех ваших хостов производства.
Рекомендуется определять группы на основе назначения хоста (роли) и также географического положения или местоположения дата-центра (если применимо):
# file: production [atlanta_webservers] www-atl-1.example.com www-atl-2.example.com [boston_webservers] www-bos-1.example.com www-bos-2.example.com [atlanta_dbservers] db-atl-1.example.com db-atl-2.example.com [boston_dbservers] db-bos-1.example.com # webservers in all geos [webservers:children] atlanta_webservers boston_webservers # dbservers in all geos [dbservers:children] atlanta_dbservers boston_dbservers # everything in the atlanta geo [atlanta:children] atlanta_webservers atlanta_dbservers # everything in the boston geo [boston:children] boston_webservers boston_dbservers
Переменные групп и хостов
Этот раздел дополняет предыдущий пример.
Группы удобны для организации, но это не все, для чего они пригодны. Вы также можете назначать переменные группам! Например, у Атланты есть свои собственные NTP-серверы, поэтому при настройке ntp.conf мы должны использовать их. Давайте настроим их сейчас:
--- # file: group_vars/atlanta ntp: ntp-atlanta.example.com backup: backup-atlanta.example.com
Переменные предназначены не только для географической информации! Возможно, у веб-серверов есть какая-то конфигурация, которая не имеет смысла для серверов базы данных:
--- # file: group_vars/webservers apacheMaxRequestsPerChild: 3000 apacheMaxClients: 900
Если у нас есть какие-либо значения по умолчанию или значения, которые являются универсальными, мы поместим их в файл group_vars/all:
--- # file: group_vars/all ntp: ntp-boston.example.com backup: backup-boston.example.com
Мы можем определить конкретные различия в оборудовании систем в файле host_vars, но старайтесь этого избегать, если это не нужно:
--- # file: host_vars/db-bos-1.example.com foo_agent_port: 86 bar_agent_port: 99
Опять же, если мы используем динамические источники инвентаризации, многие динамические группы создаются автоматически. Таким образом, метка «class:webserver» автоматически загрузит переменные из файла «group_vars/ec2_tag_class_webserver».
Разделение playbooks верхнего уровня по ролям
В файле site.yml мы импортируем playbook, который определяет всю нашу инфраструктуру. Это очень короткий пример, поскольку он просто импортирует другие playbooks:
--- # file: site.yml - import_playbook: webservers.yml - import_playbook: dbservers.yml
В файле webservers.yml (также на верхнем уровне) мы сопоставляем конфигурацию группы webservers с ролями, выполняемыми группой webservers:
---
# file: webservers.yml
- hosts: webservers
roles:
- common
- webtier
Здесь идея в том, что мы можем выбрать конфигурацию всей инфраструктуры, «запустив» site.yml, или мы можем выбрать подмножество, запустив webservers.yml. Это аналогично параметру «–limit» в Ansible, но немного более явно:
ansible-playbook site.yml --limit webservers ansible-playbook webservers.yml
Организация задач и обработчиков для роли
Ниже приведен пример файла задач, объясняющий, как работает роль. Здесь наша общая роль просто настраивает NTP, но она могла бы делать больше, если бы мы этого хотели:
---
# file: roles/common/tasks/main.yml
- name: be sure ntp is installed
yum:
name: ntp
state: present
tags: ntp
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
tags: ntp
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
tags: ntp
Вот пример файла обработчиков. Как напоминание, обработчики запускаются только тогда, когда определенные задачи сообщают о изменениях, и выполняются в конце каждого прогона:
---
# file: roles/common/handlers/main.yml
- name: restart ntpd
service:
name: ntpd
state: restarted
См. Роли для получения дополнительной информации.
Возможности данной организации (примеры)
Выше мы поделились нашей базовой структурой организации.
Какие практические применения предоставляет такая структура? Много! Если я хочу переконфигурировать всю свою инфраструктуру, достаточно:
ansible-playbook -i production site.yml
Чтобы переконфигурировать NTP для всего:
ansible-playbook -i production site.yml --tags ntp
Чтобы переконфигурировать только веб-серверы:
ansible-playbook -i production webservers.yml
Только для моих веб-серверов в Бостоне:
ansible-playbook -i production webservers.yml --limit boston
Только для первых 10 и затем для следующих 10:
ansible-playbook -i production webservers.yml --limit boston[0:9] ansible-playbook -i production webservers.yml --limit boston[10:19]
Конечно, также возможны простые одноразовые задачи:
ansible boston -i production -m ping ansible boston -i production -m command -a '/sbin/reboot'
И есть несколько полезных команд, которые стоит знать:
# confirm what task names would be run if I ran this command and said "just ntp tasks" ansible-playbook -i production webservers.yml --tags ntp --list-tasks # confirm what hostnames might be communicated with if I said "limit to boston" ansible-playbook -i production webservers.yml --limit boston --list-hosts
Организация развертывания и конфигурации
Вышеприведённая настройка моделирует типичную топологию конфигурации. При выполнении многоуровневых развертываний будут добавлены дополнительные playbooks, которые будут переходить между уровнями, чтобы развернуть приложение. В этом случае «site.yml» может быть дополнен playbooks, такими как «deploy_exampledotcom.yml», но общие концепции всё ещё могут применяться.
Рассматривайте «playbooks» как метафору спорта — вам не нужно использовать только один набор игр для вашей инфраструктуры всегда — вы можете иметь ситуационные игры, которые вы используете в разное время и для разных целей.
Ansible позволяет развертывать и настраивать с помощью одного инструмента, поэтому вы, вероятно, будете повторно использовать группы и просто держать конфигурацию ОС в отдельных playbooks от развертывания приложения.
Различия между этапами разработки (staging) и производства (production)
Как уже упоминалось выше, хороший способ сохранить разделение ваших этапов разработки (staging) и производства (production) — использовать отдельный файл инвентаризации для staging и production. Таким образом, вы выбираете, на что нацеливаться с помощью параметра -i. Сохранение всего в одном файле может привести к неожиданностям!
Тестирование в среде разработки (staging) перед тестированием в производственной среде (production) всегда является хорошей идеей. Ваши среды не обязательно должны быть одинакового размера, и вы можете использовать переменные групп для управления различиями между этими средами.
Постепенные обновления
Поймите ключевое слово «serial». При обновлении фермы веб-серверов вам действительно нужно использовать его для управления количеством машин, которые обновляются одновременно в группе.
См. Делегирование, постепенные обновления и локальные действия.
Всегда указывайте состояние
Параметр «state» является необязательным для многих модулей. Будь то «state=present» или «state=absent», лучше всего оставить этот параметр в playbooks, чтобы сделать его понятным, особенно поскольку некоторые модули поддерживают дополнительные состояния.
Группировка по ролям
Мы несколько повторяемся с этим советом, но повторение того стоит. Одна система может принадлежать к нескольким группам. См. Работа с инвентаризацией и Работа с шаблонами. Наличие групп с именами, такими как webservers и dbservers, повторяется в примерах, потому что это очень мощная концепция.
Это позволяет playbooks нацеливаться на машины на основе роли, а также назначать роль-специфические переменные с использованием системы переменных групп.
См. Роли.
Отличия в операционных системах и дистрибутивах
При работе с параметром, отличающимся в разных операционных системах, отличным способом решения этой проблемы является использование модуля group_by.
Это создаёт динамическую группу хостов, соответствующих определённым критериям, даже если эта группа не определена в файле инвентаризации:
---
- name: talk to all hosts just so we can learn about them
hosts: all
tasks:
- name: Classify hosts depending on their OS distribution
group_by:
key: os_{{ ansible_facts['distribution'] }}
# now just on the CentOS hosts...
- hosts: os_CentOS
gather_facts: False
tasks:
- # tasks that only happen on CentOS go here
Это поместит все системы в динамическую группу на основе имени операционной системы.
Если необходимы настройки, специфичные для группы, это также можно сделать. Например:
--- # file: group_vars/all asdf: 10 --- # file: group_vars/os_CentOS asdf: 42
В приведённом примере машины CentOS получают значение «42» для asdf, а другие машины — «10». Это можно использовать не только для установки переменных, но и для применения определённых ролей только к определённым системам.
В качестве альтернативы, если нужны только переменные:
- hosts: all
tasks:
- name: Set OS distribution dependant variables
include_vars: "os_{{ ansible_facts['distribution'] }}.yml"
- debug:
var: asdf
Это позволит получить переменные на основе имени ОС.
Связывание модулей Ansible с playbook
Если playbook имеет каталог ./library относительно своего YAML-файла, этот каталог можно использовать для добавления модулей ansible, которые автоматически будут присутствовать в пути к модулям ansible. Это отличный способ хранения модулей, связанных с playbook, вместе. Это показано в примере структуры каталога в начале этого раздела.
Пробелы и комментарии
Рекомендуется использовать достаточное количество пробелов для разделения элементов и комментарии (начинающиеся с символа «#»).
Всегда присваивайте имена задачам
Можно опустить «name» для заданной задачи, хотя рекомендуется предоставить описание того, почему что-то делается. Это имя отображается при запуске playbook.
Держите всё просто
Когда вы можете сделать что-то просто, делайте это просто. Не пытайтесь использовать все возможности Ansible одновременно. Используйте то, что работает для вас. Например, вам, вероятно, не понадобятся vars, vars_files, vars_prompt и --extra-vars одновременно, используя при этом внешний файл инвентаризации.
Если что-то кажется сложным, это, вероятно, так, и это может быть хорошей возможностью для упрощения.
Система управления версиями
Используйте систему управления версиями. Храните ваши playbook и файл инвентаризации в git (или другой системе управления версиями) и коммитите изменения, когда вы их вносите. Таким образом, у вас будет журнал аудита, описывающий, когда и почему вы изменили правила автоматизации вашей инфраструктуры.
Переменные и хранилища
Для общего обслуживания часто проще использовать grep, или подобные инструменты, для поиска переменных в вашей настройке Ansible. Поскольку хранилища скрывают эти переменные, лучше работать с уровнем косвенности. При запуске playbook Ansible находит переменные в незашифрованном файле, а все конфиденциальные переменные берутся из зашифрованного файла.
Подход, основанный на лучших практиках, заключается в том, чтобы начать с подкаталога group_vars/, названного в соответствии с группой. Внутри этого подкаталога создайте два файла, названные vars и vault. В файле vars определите все необходимые переменные, включая любые конфиденциальные. Затем скопируйте все конфиденциальные переменные в файл vault и добавьте к этим переменным префикс vault_. Вы должны настроить переменные в файле vars таким образом, чтобы они указывали на соответствующие переменные vault_ с использованием синтаксиса jinja2, и убедитесь, что файл vault зашифрован с помощью vault.
Эта лучшая практика не ограничивает количество файлов переменных и хранилищ или их имена.
См. также
- YAML-синтаксис
- Изучите YAML-синтаксис
- Работа с playbook
- Просмотрите основные возможности playbook
- Все модули
- Узнайте о доступных модулях
- Разработка модуля?
- Узнайте, как расширить Ansible, написав свои собственные модули
- Работа с шаблонами
- Узнайте, как выбирать хосты
- Каталог примеров GitHub
- Полные файлы playbook из исходного кода проекта GitHub
- Список рассылки
- Вопросы? Помощь? Идеи? Задайте их на списке рассылки Google Groups
© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.8/user_guide/playbooks_best_practices.html