Документация Инструкции Введение в Ansible


Что такое Ansible?

Ansible - это система управления конфигурациями, с помощью которой можно эффективно управлять большим количеством серверов.

Что такое система управления конфигурациями?

Это инструмент в помощь системным администраторам и DevOps инженерам для быстрого выполнения команд и управления состоянием большого количества серверов. Среди известных можно назвать Puppet, Chef, fabrica и, собственно, Ansible.
Обычно их делят на реализующие pull-модель и push-модель.
Pull-модель преполагает, что управляемые хосты подтягивают инструкции с мастер-сервера.
Push-модель реализует подход, когда инструкции по желанию или по событию доставляются с управляющего на управляемые хосты.
Ansible чаще всего используется для push-модели управления, но умеет и pull-модель.


У меня всё заскриптовано bash скриптами. Чем какая-то система будет лучше?

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

А чем Ansible лучше остальных?

Выгодные отличия Ansible от других систем управления конфигурациями:
- быстро осваивается, достаточно поверхностного понимания синтаксиса YAML и Jinja
- нет необходимости устанавливать специальное ПО на хосты, нужен только SSH и python
- подробная и наглядная документация
- большое количество модулей
- позволяет реализовать принцип идемпотентности в управлении состояниями хостов


Что такое идемпотентность?

Это важный момент, разберем подробно.
Идемпотентность - это такая характеристика действия, согласно которой повторное выполнение этого действия будет давать тот же результат, что и первый запуск.
В контексте систем управления конфигурациями это означает, что сценарии, написанные с соблюдением такого подхода, не изменят, не сломают и не выдадут ошибок на управляемом хосте при повторном запуске.
Например, нам нужно добавить пользователя на хост, для bash это будет выглядеть так:
useradd newuser -ms /bin/bash
Но если мы запустим команду второй раз, то получим ошибку
useradd newuser -ms /bin/bash
useradd: user 'newuser' already exists
Поэтому нам нужно дополнительно добавлять проверку, например так:
id newuser || useradd newuser -ms /bin/bash
В случае Ansible мы только декларируем состояние, например:
- hosts: localhost
  gather_facts: no
  tasks:
    - user:
        name: newuser
        shell: /bin/bash
        state: present
При первом запуске плейбук Ansible ответит:
TASK [user] ***
changed: [localhost] => {
  "ansible_facts": {
    "discovered_interpreter_python": "/usr/bin/python3"
  },
  "changed": true,
  "comment": "",
  "create_home": true,
  "group": 1001,
  "home": "/home/newuser",
  "name": "newuser",
  "shell": "/bin/bash",
  "state": "present",
  "system": false,
  "uid": 1001
}
При повторном:
TASK [user] ***
ok: [localhost] => {
  "ansible_facts": {
    "discovered_interpreter_python": "/usr/bin/python3"
  },
  "append": false,
  "changed": false,
  "comment": "",
  "group": 1001,
  "home": "/home/newuser",
  "move_home": false,
  "name": "newuser",
  "shell": "/bin/bash",
  "state":
  "present",
  "uid": 1001
}
Обратите внимание, что статус задания сменился с `changed` на `ok` и повторный запуск вернул значение `"changed": false` Таким образом, сценарии, написанные с учетом идемпотентности, реализуют ту самую декларативность в описании состояния инфраструктуры, а инфраструктура соответствует состоянию, описанному в коде нашего скрипта.
Это и есть Iac - Infrastructure as Code - инфраструктура как код.

Основная терминология Ansible

Инвентарь (Inventory) - cписок хостов, может быть статичным в виде текcтового файла в формате ini или динамическим в виде скрипта или плагина, который подгружает структуру данных из стороннего источника, например, Openstack API или база LDAP.
$ cat hosts
[web]
nginx01
nginx02
nginx03

[mysql]
mysql01
mysql02
mysql03

[prod:children]
web
mysql

[devel]
dev-nginx01
dev-mysql01
Данный пример описывает группы хостов web, mysql, prod и devel, группа prod наследует содержимое групп web и mysql.

Задание (Task) - атомарная операция, выполняемая на управляемом хосте, например:
apt:
  package: nginx
  state: present
Данный пример аналогичен команде `apt install nginx`

Сценарий (Play) или Плейбук (Playbook) - сценарий или скрипт, содержащий одну или несколько заданий на выполнение, например:
$ cat prod-playbook.yml
---
- hosts: nginx
  tasks:
    - apt:
        package: nginx
        state: present
    - shell: whoami
Роль (Role) - более сложная абстракция, выглядит как структура директорий и файлов, которые описывают набор дефолтных переменных, зависимостей от других ролей, может содердать содержит файлы, темплейтов и задания.

Факты (Facts) - структура данных, которая содержит информацию о хосте, например, версию дистрибутива, IP адреса и файловые системы. Ansible забирает эту информацию с хоста, и на нее можно ссылаться в коде плейбуков и ролей.
Сбор фактов хоста занимает некоторое время, поэтому их можно кэшировать или отключить их сбор при выполнении плейбука.

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

В общем случае структура файлов и директорий выглядит примерно таким образом:
.
├── ansible.cfg
├── group_vars
│   └── all.yml
├── host_vars
├── hosts
│   ├── all.yml
│   ├── localhost.yml
│   └── openstack.yml
├── playbook_01.yml
├── playbook_02.yml
└── roles
    └── nginx
        ├── defaults
        ├── handlers
        ├── tasks
        └── templates
ansible.cfg - файл конфигурации

group_vars - переменные, которые являются атрибутами групп хостов

host_vars - переменные, которые являются атрибутами хостов

hosts - инвентарь со списками хостов

roles - директория, содержащая роли

playbook_0[12].yml - плейбуки для выполнения

group_vars, host_vars, hosts могут быть файлами или директориями, содержащими какую-то семантическую человекочитаемую иерархию, например:
group_vars/
├── all.yml
├── mysql
├── nginx
└── users


Основные команды

Их две: anible и ansible-playbook Команда ansible служит для вызова отдельных модулей, например:
ansible all -m shell -a "lscpu"
Здесь мы вызываем модуль shell для выполнения команды на всех хостах и аргументом передаем команду, которую хотим запустить.

Для запуска сценария передаем файл команде ansible-playbook:
ansible-playbook playbook_01.yml -D -vv -C
Параметр -C/--check запускает плейбук в режиме check_mode, в тестовом режиме прогонит задания, не выполняя их фактически. Здесь следует иметь в виду, что некоторые модули, например, shell или command не умеют отрабатывать check_mode, о чем сообщают в выводе при запуске с -C/--check, поэтому следует ими пользоваться только в особых случаях.

Параметр -D/--diff покажет в diff формате разницу старого и нового состояния файлов.

Теперь, познакомившить с основными принципами и понятиями Ansible, можно установить виртуальный сервер из шаблона 'Openstack & Ansible shellbox' с готовой к работе структурой файлов Ansible, и попробовать его на практике.