Система управления Ansible

Представьте себе, что вам нужно управлять парком серверов, расположенных к тому же в разных географических точках. Каждый из этих серверов требует настройки, регулярного обновления и мониторинга. Конечно, для решения этих задач можно воспользоваться самым простым способом: подключиться к каждому серверу по ssh и внести необходимые изменения. При всей своей простоте этот способ сопряжен с некоторыми трудностями: он чрезвычайно трудоемок, а на выполнение однообразных операций уходит очень много времени.

Чтобы упростить процессы настройки и конфигурирования серверов, можно также писать shell-скрипты. Но и этот способ вряд ли можно назвать совершенным. Скрипты нужно постоянно изменять, подстраивая их под каждую новую задачу. При их написании необходимо учитывать различие операционных систем и версий. Не будем забывать и о том, что отладка скриптов отнимает много усилий и забирает немало времени.

Оптимальным вариантом решения описанных проблем является внедрение системы удаленного управления конфигурацией. В таких системах достаточно лишь описать нужное состояние управляемого узла. Система должна сама определить, что нужно сделать для достижения этого состояния, и осуществит все необходимые действия.

Со всеми сложностями, о которых идет речь выше, мы хорошо знакомы на собственном опыте: у нас имеется 10 точек присутствия с NS-серверами, расположенные в разных точках планеты. На них необходимо регулярно вносить различные изменения: обновлять операционную систему, устанавливать и обновлять различное ПО, изменять конфигурцию и т.п. Мы решили все эти операции автоматизировать и внедрить систему удаленного управления конфигурациями. Изучив имеющиеся решения, мы остановили свой выбор на Ansible.

В этой статье мы бы хотели подробно рассказать о его возможностях этого инструмента управления конфигурациями и поделиться собственным опытом его использования.

Что такое Ansible?

Ansible — опенсорсное программное решение для удаленного управления конфигурациями, разработанное Майклом Де Хаанном в 2012 году. Название продукта взято из научно-фантастической литературы: в романах американской писательницы Урсулы Ле Гуин ансиблом называется устройство для оперативной космической связи.

Ansible берет на себя всю работу по приведению удаленных серверов в необходимое состояние. Администратору необходимо лишь описать, как достичь этого состояния с помощью так называемых сценариев (playbooks; это аналог рецептов в Chef). Такая технология позволяет очень быстро осуществлять переконфигурирование системы: достаточно всего лишь добавить несколько новых строк в сценарий.

Почему Ansible?

Преимущества Ansible по сравнению с другими аналогичными решениями (здесь в первую очередь следует назвать такие продукты, как Puppet, Chef и Salt) заключаются в следующем:

• на управляемые узлы не нужно устанавливать никакого дополнительного ПО, всё работает через SSH (в случае необходимости дополнительные модули можно взять из официального репозитория);

• код программы, написанный на Python, очень прост; при необходимости написание дополнительных модулей не составляет особого труда;

• язык, на котором пишутся сценарии, также предельно прост;

• низкий порог вхождения: обучиться работе с Ansible можно за очень короткое время;

• документация к продукту написана очень подробно и вместе с тем — просто и понятно; она регулярно обновляется;

• Ansible работает не только в режиме push, но и pull, как это делают большинство систем управления (Puppet, Chef);

• имеется возможность последовательного обновления состояния узлов (rolling update).

Установка

Требования для установки Ansible минимальны. На машине с которой производится управление должен быть установлен Python 2.6 или выше. На управляемых узлах должен быть установлен только Python версии не ниже 2.4, но он, как правило, по умолчанию включен в состав большинства дистрибутивов linux-систем. MS Windows не поддерживается.

Вам также могут потребоваться следующие модули Python, устанавливаемые через pip или пакетный менеджер вашей операционной системы:

• paramiko;

• PyYAML;

• jinja2.

В Ubuntu установка самого Ansible и зависимостей осуществляется добавлением репозитория и установкой пакета:

$ sudo add-apt-repository -y ppa:rquillo/ansible
$ sudo apt-get update
$ sudo apt-get install ansible -y

О процедуре установки в других ОС можно прочитать в официальной документации.

Группы серверов

Список групп серверов, которыми нужно управлять, Ansible может получать двумя основными способами:

• из специального текстового файла (далее этот вариант будет рассмотрен более подробно);

• с помощью внешнего скрипта, возвращающего нужный нам список серверов, например из MongoDB. В официальном github-репозитории есть готовые скрипты для получения списка из Cobbler, Digital Ocean, EC2, Linode, OpenStack Nova, Openshift, Spacewalk, Vagrant, Zabbix.

Файл hosts

Дефолтное расположение файла — /etc/ansible/hosts, но оно может также быть задано параметром окружения $ANSIBLE_HOSTS или параметром -i при запуске ansible и ansible-playbook. Содержимое этого файла может выглядеть, например, так (в квадратных скобках указаны имена групп управляемых узлов, ниже перечисляются входящие в эти группы серверы):

[dbservers]
one.example.com

two.example.com
three.example.com
[dnsservers]
rs1.example.com ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
rs2.example.com
ns[01:50].example.com

 

Помимо списка управляемых узлов, в файле hosts могут быть указаны и другие сведения, необходимые для работы: номера портов для подключения по SSH, способ подключения, пароль для подключения по SSH, имя пользователя, объединения групп и т.п. В некоторых случаях — в частности, при работе с большими и сложными конфигурациями, — различные параметры можно выносить в отдельные файлы и каталоги (о структуре каталогов см. ниже).

Более подробно о файле hosts и правилах его написания можно почитать в официальной документации.

Информация об узлах (Facts)

Перед внесением изменений Ansible подключается к управляемым узлам и собирает информацию о них: о сетевых интерфейсах и их состоянии, об установленной операционной системе и т.п. Он может делать это как с помощью собственного модуля, так и с помощью инструментов ohai и facter, если они установлены (такая возможность специально предусмотрена для пользователей, уже имеющих опыт работы с системами удаленного управления конфигурациями: ohai и facter являются библиотеками фактов для Chef и Puppet).

Во время деплоя, как правило, требуется не только установить какое-либо приложение, но и настроить его в соответствии с определенными параметрами на основании принадлежности к группе серверов или индивидуально (например, ip-адрес BGP-соседа и номер его AS или параметры для базы данных). Как уже было сказано, загромождать файл hosts будет не очень красиво, поэтому разработчики Ansible пошли следующим путём:

• файлы с переменными групп хранятся в директории “group_vars/имя_группы”;

• файлы с переменными хостов в директории “hosts_vars/имя_хоста”;

• файлы с переменными роли (о них речь пойдет ниже) в директории “имя_роли/vars/имя_задачи.yml”;

Помимо пользовательских переменных можно (и даже нужно) использовать факты, собранные ansible перед выполнением сценариев и отдельных задач.

Модули Ansible

В состав Ansible входит огромное количество модулей для развёртывания, контроля и управления различными компонентами, которые можно условно разделить на следующие группы (в скобках приведены названия некоторых продуктов и сервисов):

• облачные ресурсы и виртуализация (Openstack, libvirt);

• базы данных (MySQL, Postgresql, Redis, Riak);

• файлы (шаблонизация, регулярные выражения, права доступа);

•  мониторинг (Nagios, monit);

• оповещения о ходе выполнения сценария (Jabber, Irc, почта, MQTT, Hipchat);

• сеть и сетевая инфраструктура (Openstack, Arista);

• управление пакетами (apt, yum, rhn-channel, npm, pacman, pip, gem);

• система (LVM, Selinux, ZFS, cron, файловые системы, сервисы, модули ядра);

• работа с различными утилитами (git, hg).

О том, с чем умеет работать Ansible “из коробки”, можно прочитать в официальной документации. Список действительно впечатляет.

Примеры простых задач

С помощью Ansible можно одновременно выполнить одну задачу на целой группе серверов. Попробуем, например, отправить запрос ping на серверы выбранной группы:

$ ansible dnsservers -m ping
dns1.example.com | success >> {
“changed”: false,
“ping”: “pong”
}
dns2.example.com | success >> {
“changed”: false,
“ping”: “pong”
}

Следующий пример соберёт информацию о хостах и выведёт её на консоль в формате JSON:

$ ansible dnsservers -m setup

А вот так можно создать логический том (или, в зависимости от текущего состояния, изменить его размер) с именем examplevolume в группе examplegroup:

$ ansible dnsservers -m lvol -a “vg=examplegroup lv=examplevolume size=1024 state=present”
dns1.example.com | success >> {
“changed”: true,
“msg”: “”
}
dns2.example.com | success >> {
“changed”: false,
“msg”: “”
}

Ansible позволяет не только выполнять единичные задачи, но и писать сценарии, которые необходимо выполнить на управляемых узлах. Рассмотрим структуру и правила написания таких сценариев более подробно.

Cценарии (playbooks)

Все сценарии в Ansible пишутся на YAML. Это — человекочитаемый формат сериализованных данных, гораздо более простой, чем XML или JSON.

Чтобы выполнить сценарий используется команда ansible-playbook со следующим сиснтаксисом:

ansible-playbook <имя_файла_сценария.yml> … [другие параметры]

В начале сценария обязательно должна присутствовать последовательность символов «–––» (так в YAML обозначается начало документа). Перед каждым новым разделом списка ставится дефис ( — ):


– hosts: webservers

Основными параметрами/группами простого сценария являются:

• hosts — в нем указываются управляемые узлы или группы узлов, к которым нужно применить изменения;

• tasks — здесь описывается состояние, в которое необходимо привести управляемый узел, альтернативой этому могут служить роли;

Также в сценарии перед непосредственным описанием задач могут быть указаны следующие параметры или группы параметров:

• gather_facts — собирать или нет информацию о хостах перед выполнением задач, по умолчанию — да;

• vars — в нем указываются различные переменные, которые будут использованы при выполнении сценария;

• connection — можно указать метод соединения с хостами: pure ssh, paramiko, fireball, chroot, jail, local, accelerate (применимо также для выполнения отдельного модуля);

•  sudo — после установления соединения выполнять задачу с привилегиями другого пользователя, по умолчанию другой пользователь — root;

•  sudo_user — в сочетании с предыдущим параметром можно указать с привилегиями какого именно пользователя будет выполнена задача;

• vars_prompt — перед выполением плэйбука Ansible в интерактивном режиме может уточнить указанные в этом разделе параметры;

• remote_user (в предыдущих версиях — просто user) — имя пользователя для авторизации на удалённом хосте.

Шаблонизация

В Ansbile используется шаблонизатор Jinja2. Приведём пример простого шаблона (часть конфига powerdns):

# пароль для подключения к базе данных
gpgsql-password={{ lookup(‘password‘, ‘credentials/’ + inventory_hostname + ‘/postgresql/powerdns‘, length=15) }}
# IPv4-адрес, который будет “слушать” powerdns
local-address={{ ansible_default_ipv4.address }}
# IPv6-адрес, который будет “слушать” powerdns
local-ipv6={{ ansible_default_ipv6.address }}
# nsid dns-сервера (EDNS option 3, rfc5001)
server-id={{ ansible_hostname }}

В приведённом примере мы подставляем в шаблон следующие значения:

• из заранее собранных фактов о хосте:

• ansible_default_ipv4.address — основной IPv4-адрес хоста;

• ansible_default_ipv6.address — основной IPv6-адрес хоста;

• ansible_hostname — имя хоста (результат выполнения команды hostname).

• inventory_hostname — имя хоста в инвентарном файле;

• пароль пользователя powerdns из внешнего источника данных (в данном случае файл) для подключения к базе Postgresql, полученный с помощью lookup-плагина password из стандартной поставке. Особенность некоторых lookup-плагинов — если данных нет, то они могут их сгенерировать и сохранить для последующего использования.

Обработку шаблонов и, в данном случае, генерацию конфигурационного файла выполняет модуль template; он же может задать необходимые права доступа и изменить владельца/группу:

– name: generate powerdns config
template: src=pdns.conf.j2 dest=/etc/powerdns/pdns.conf owner=powerdns group=powerdns mode=600

Обратим внимание на то, что файл шаблона и файл с паролем пользователя базы данных находятся на машине управления, а результатом будет файл на удалённом узле.

Обработчики событий (Handlers)

Ansible не просто выполняет задачи в указанном порядке, но и проверяет их состояние на наличие изменений. Если при выполнении сценария требовалось, например, добавить строку в конфигурационный файл, и в результате выполнения он изменился (необходимой строки действительно не было), то Ansible может выполнить специальную задачу, описанную как обработчик события (handler). Если при выполнении строка уже была в конфигурационном файле, то обработчик выполнен не будет. Обработчики событий описываются в конце сценария; в описании задачи они указываются через параметр notify. Приведём пример:


– hosts: webservers
vars:
max_clients: 200
tasks:
# сгенерируем файл конфигурации на основе шаблона
# и укажем, что требуется выполнить задачу “restart apache”
# если файл изменился
– name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
– restart apache- name: ensure apache is running
service: name=httpd state=started
# раздел описания обработчиков
handlers:
– name: restart apache
# используем модуль service для перезапуска веб-сервера
service: name=httpd state=restarted mode=

Контроль выполнения

Допустим, что при выполнении сценария нам нужно проверять определённые переменные или состояния и, в зависимости от них, выполнять или не выполнять какие-либо задачи. Для этого можно использовать оператор “when”:

tasks:
# сохраняем файл шаблона и сохраняем результат задачи
# в переменную last_result
– template: src=/templates/foo.j2 dest=/etc/foo.conf
register: last_result
# проверяем переменную last_result.changed и если она имеет
# значение true – задача будет выполнена, иначе – будет пропущена
– command: echo ‘the file has changed’
when: last_result.changed

Делегирование задачи другому хосту

Иногда требуется выполнить задачу на определённом узле, но в контексте другого узла. Например, во время обновления узла может возникнуть необходимость отключить для него мониторинг, находящийся на отдельном сервере. Для этого используется управляющая директива delegate_to. Приведём пример:

name: disable nagios alerts for this host webserver service
nagios: action=disable_alerts host={{inventory_hostname}} services=dnsserver
delegate_to: mon_host.example.com


Результатом выполнения этой задачи будет отключение сообщений для сервиса dnsserver в Nagios.

Роли

Ролью называется типовой набор переменных и задач, назначаемых для одного или нескольких серверов. Если вам нужно применить к серверу или группе серверов типовой набор операций, вам достаточно просто назначить ему роль. Предварительно в проекте каталоге проекта должна быть создана соответствующая структура. В сценариях роли назначаются следующим образом:


– name: check and apply basic configuration to all hosts
hosts: all
roles:
– common
– name: check and apply configuration to group1
hosts: group1
roles:
– pgsql
– name: check and apply configuration to group2
hosts: group2
roles:
– fooapp

Структура проекта

├── production # инвентарный файл для продакшн-серверов
├── stage # инвентарный файл для stage-окружения

├── group_vars/
│ ├── group1 # здесь назначаются переменные для
│ └── group2 # конкретных групп
├── host_vars/
│ ├── hostname1 # специфические переменные для хостов в
│ └── hostname2 # случае необходимости прописываются здесь

├── site.yml # основной сценарий
├── webservers.yml # сценарий для веб-сервера
├── dbservers.yml # сценарий для сервера базы данных

└── roles/
├── common/ # здесь описываются роли
│ ├── tasks/ #
│ │ └── main.yml # – файл задач роли, может включать файлы
│ │ # меньшего размера
│ ├── handlers/ #
│ │ └── main.yml # – файл с обработчиками (handlers)
│ ├── templates/ # – директория для шаблонов, в данном
│ │ └── ntp.conf.j2 # случае – для конфига ntp
│ ├── files/ #
│ │ ├── bar.txt # – файл-ресурс для копирования на хост
│ │ └── foo.sh # – скрипт для выполнения на удалённом хосте
│ └── vars/ #
│ └── main.yml # – ассоциированные с ролью переменные

├── pgsql/ # такая же структура, как выше, для роли pgsql
└── fooapp/ # такая же структура, как выше, для роли fooapp

Ansible AWX

Во всех приведенных выше примерах управление Ansible осуществляется с помощью интерфейса командной строки. Но с официального сайта можно загрузить графическую панель управления Ansibleworks AWX, очень симпатичную внешне и удобную в использовании. Собственно, за счет ее распространения и осуществляется монетизация продукта: управление небольшим (до 10) количеством серверов обходится бесплатно, если же серверов больше — нужно приобретать лицензию. Похожие варианты монетизации используются и разработчиками конкурирующих решений — Puppet и Chef.

Заключение

Ansible — достаточно простой, но при этом эффективный инструмент для удаленного управления конфигурациями. В рамках этой статьи мы сделали лишь беглый обзор его возможностей и рассказали, как пишутся сценарии для решения простых задач. Все возможности и варианты использования Ansible в рамках одной статьи охватить невозможно. О применении этого инструмента для решения более специфических задач мы расскажем в последующих публикациях.

Ссылка на источник : https://habrahabr.ru/company/selectel/blog/196620/