Знакомство с Ansible. Часть 5: роли, условия и циклы
Nov 16, 2015 20:36 · 930 words · 5 minute read
В первой части знакомства с Ansible
мы разобрались с установкой и базовой настройкой системы управления конфигурациями и написали наш первый playbook, а во второй части разобрали результат его выполнения. Третью часть цикла посвятили использованию переменных в Ansible
, а в четвертой разбирались с наиболее популярными модулями и их параметрами.
В завершающей части знакомства с Ansible
давайте разберемся с условиями и циклами, а также научимся организовывать playbook в роли!
Для сокращения количества задач в наборах инструкций (playbook) разумно использовать циклы. Например, иногда требуется установить несколько пакетов на один и тот же удаленный хост или выполнить несколько операций над одним и тем же ресурсом.
Рассмотрим простой playbook, который поможет установить несколько пакетов на удаленный сервер:
---
- hosts: test
tasks:
- name: Install packages
apt: name={{ item }} state=latest
with_items:
- htop
- mytop
- wget
sudo: yes
В результате выполнения данного набора инструкций на удаленном хосте будут установлены пакеты, перечисленные в with_items:
. Playbook будет запущен один раз, но модуль apt
будет вызываться для каждого указанного пакета:
ansible-playbook install_packages.yml
PLAY [test] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [test-1]
TASK: [Install packages] ******************************************************
changed: [test-1] => (item=htop,mytop,wget)
PLAY RECAP ********************************************************************
test-1 : ok=2 changed=1 unreachable=0 failed=0
Создать нескольких пользователей и добавить их в определенные группы можно с помощью такого набора инструкций:
---
- hosts: test
tasks:
- name: Add test users
user: name={{ item.name }} state=present groups={{ item.groups }}
with_items:
- { name: 'user1', groups: 'adm' }
- { name: 'user2', groups: 'lpadmin' }
sudo: yes
Результат выполнения данного playbook будет выглядеть так:
ansible-playbook add_users.yml
PLAY [test] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [test-1]
TASK: [Add test users] ********************************************************
changed: [test-1] => (item={'name': 'user1', 'groups': 'adm'})
changed: [test-1] => (item={'name': 'user2', 'groups': 'lpadmin'})
PLAY RECAP ********************************************************************
test-1 : ok=2 changed=1 unreachable=0 failed=0
Примечание. Больше примеров с использованием циклов можно найти в официальной документации по Ansible
.
Ansible
выполняет задачи в порядке их следования в наборе инструкций, но бывают случаи, когда требуется выполнить только часть задач. В третьей части нашего цикла мы уже пробовали правильно устанавливать web-сервер Apache на разные дистрибутивы с помощью переменных. Чтобы задачи выполнялись только в определенном случае, можно (и нужно) указывать условия с помощью when:
.
В условиях в Ansible
для сравнения используются ==
(равно), !=
(не равно), >
(больше), <
(меньше), >=
(больше равно), <=
(меньше равно). Можно также указать несколько условий с помощью операторов and
(и) и or
(или). Для проверки вхождения символа или подстроки в строку используются операторы in
и not
.
Для проверки работы некоторых условий в Ansible
создадим playbook следующего содержания:
---
- hosts: test
tasks:
- name: Check OS family
debug: msg="This is my OS"
when: ansible_os_family == "Debian"
- name: Check if Apache2 is installed
command: dpkg-query -W apache2
register: apache2_check
- name: Print message if apache installed
debug: msg="Apache2 is installed on remote host"
when: "'apache2' in apache2_check.stdout"
- name: Check if admin logged
command: who
register: who_check
- name: Print message if user admin not logged
debug: msg="User admin is not logged on remote host"
when: not 'admin' in who_check.stdout
Результат выполнения данного набора инструкций будет таким:
ansible-playbook debug.yml
PLAY [test] *******************************************************************
GATHERING FACTS ***************************************************************
ok: [test-1]
TASK: [Check OS family] *******************************************************
ok: [test-1] => {
"msg": "This is my OS"
}
TASK: [Check if Apache2 is installed] *****************************************
changed: [test-1]
TASK: [Print message if apache installed] *************************************
ok: [test-1] => {
"msg": "Apache2 is installed on remote host"
}
TASK: [Check if admin logged] *************************************************
changed: [test-1]
TASK: [Print message if user admin not logged] ********************************
ok: [test-1] => {
"msg": "User admin is not logged on remote host"
}
PLAY RECAP ********************************************************************
test-1 : ok=6 changed=2 unreachable=0 failed=0
Напоследок у нас остается немного “магии”. В архитектуре проекта обычно сервера разделяются по своему предназначению и выполняют определенную роль - web-сервер, сервер баз данных, почтовый сервер и т. д. Каждому из серверов требуется отличающийся набор пакетов и настроек для правильного выполнения своей роли. С ростом количества серверов будет расти количество наборов инструкций (playbook), которые будут использоваться повторно.
Ansible
позволяет удобно организовать и структурировать наборы инструкций в соответствии с ролями серверов. Пример структуры набора инструкций с ролями выглядит так:
---
- hosts: servers
roles:
- web
– db
- post
Тогда файловая структура ролей может выглядеть таким образом:
site.yml
servers.yml
roles/
web/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
db/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
post/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
Примечание. Файловая структура не обязательно должна выглядеть так - если какой-либо каталог отсутствует в роли, то он будет проигнорирован и набор инструкций будет выполняться дальше.
Путь к каталогу с ролями можно задать с помощью параметра roles_path
в конфигурационном файле Ansible
. При указании ролей можно использовать тэги.
Также для каждой роли будут применяться следующие правила:
- если существует
roles/.../tasks/main.yml
, то задачи из этого файла будут добавлены в набор инструкций; - если существует
roles/.../handlers/main.yml
, то обработчики из этого файла будут добавлены в набор инструкций; - если существует
roles/.../vars/main.yml
, то переменные из этого файла будут добавлены в набор инструкций; - если существует
roles/.../meta/main.yml
, то любые роли-зависимости будут добавлены в список ролей; - задача копирования может ссылаться на файл в
roles/.../files
без указания абсолютного или относительного пути; - скриптовая задача может ссылаться на скрипт в
roles/.../files
без указания абсолютного или относительного пути; - задача шаблонизации может ссылаться на
roles/.../templates
без указания абсолютного или относительного пути; - импортируемые задачи могут ссылаться на файлы в
roles/.../tasks
без указания абсолютного или относительного пути.
О ролях можно писать очень много и долго, поэтому я лучше порекомендую Ansible Galaxy - крупнейший репозиторий ролей Ansible
, там можно брать уже готовые роли (например, для обучения) или делиться своими ролями.
На этом все, знакомство с Ansible
завершено, но это только вершина айсберга - намного больше предстоит узнать активно используя Ansible
при настройке IT-инфраструктуры.