ansible

Ansible

Ansible: настрой 100 серверов одной командой

Ранее вы превратили пустой сервер в веб-сервер тремя командами в терминале. Для одного сервера это быстро. Если серверов десять, придется десять раз зайти по SSH и набрать одно и то же. Если сто, то сто раз, и где-то на сороковом вы опечатаетесь. Ansible существует ровно для того, чтобы этим занимался не человек.

Как устроен Ansible

Первое, что удивляет в Ansible, это что на серверы не нужно ничего устанавливать. Никаких агентов и фоновых программ. Ansible запускается на вашей машине и подключается к серверам по обычному SSH, тому самому, про который шла речь в модуле про Linux. Все, что требуется от сервера, это SSH-доступ и Python, который на серверных дистрибутивах обычно уже есть.

Работает Ansible с двумя файлами. Инвентарь это список серверов, которыми вы управляете. Playbook это описание того, что на этих серверах должно быть. Дальше по очереди.

Инвентарь, список серверов

Инвентарь это обычный текстовый файл. Серверы в нем собираются в группы, имя группы пишется в квадратных скобках:

[web]
web-01 ansible_host=10.0.0.11
web-02 ansible_host=10.0.0.12
web-03 ansible_host=10.0.0.13

Здесь группа web из трех серверов: имя, по которому к серверу обращается Ansible, и его адрес. Групп может быть несколько (web, db, monitoring), и playbook применяется не к серверам поименно, а к группе целиком.

Прежде чем что-то настраивать, стоит проверить, что Ansible вообще достучался до всех машин:

ansible -i inventory.ini web -m ping

web-01 | SUCCESS => "ping": "pong"
web-02 | SUCCESS => "ping": "pong"
web-03 | SUCCESS => "ping": "pong"

Playbook, те самые 10 строк

Playbook пишется на YAML, формат вам знаком по .gitlab-ci.yml из модуля про CI/CD. Вот playbook из видео целиком, файл site.yml:

- name: Настроить веб-серверы
  hosts: web
  become: true
  tasks:
    - name: Установить nginx
      apt:
        name: nginx
        state: present
 
    - name: Запустить nginx и включить автозагрузку
      service:
        name: nginx
        state: started
        enabled: true
 
    - name: Проверить, что сайт отвечает
      uri:
        url: http://localhost
        status_code: 200

Разберем сверху вниз.

Шапка описывает, к кому и как применять. Строка hosts: web целится в группу web из инвентаря. Строка become: true означает выполнять задачи с правами администратора, это тот же sudo из модуля про Linux, без него пакет не установить.

Дальше идет tasks, список задач. У каждой есть name, человеческое описание, которое вы увидите в логе запуска, и модуль, который делает работу. Модули это кирпичики Ansible: apt управляет пакетами, service службами, uri делает HTTP-запросы. Таких кирпичиков сотни: пользователи, файлы, cron, Docker, облака.

И самое важное в этом файле это слова state: present и state: started. Обратите внимание, что здесь нигде не написано «выполни apt install» или «выполни systemctl start». Написано состояние: пакет nginx должен присутствовать, служба должна быть запущена и включена в автозагрузку. Как привести сервер к этому состоянию, Ansible решает сам. Это тот декларативный подход, что мы разобрали до этого, только теперь он перед вами в виде работающего файла.

Запуск

ansible-playbook -i inventory.ini site.yml

Флаг -i указывает на инвентарь, дальше имя playbook. Вывод выглядит так (сокращенно):

PLAY [Настроить веб-серверы] *************************************
 
TASK [Gathering Facts] *******************************************
ok: [web-01]
 
TASK [Установить nginx] ******************************************
changed: [web-01]
 
TASK [Запустить nginx и включить автозагрузку] *******************
changed: [web-01]
 
TASK [Проверить, что сайт отвечает] ******************************
ok: [web-01]
 
PLAY RECAP *******************************************************
web-01 : ok=4  changed=2  failed=0

Первая задача, Gathering Facts, служебная: Ansible собирает информацию о сервере, ее вы не писали. Дальше по списку. Статус changed означает, что Ansible что-то поменял: nginx не стоял, и его пришлось установить. Статус ok означает, что состояние уже совпадало с описанным и делать ничего не пришлось. Внизу итог по серверу: сколько задач прошло, сколько изменили систему, сколько упало.

Сервер настроен. Откройте его адрес в браузере, и там будет страница приветствия nginx, ровно как в модуле про Linux, только в этот раз вы не вводили на сервере ни одной команды.

Второй запуск, идемпотентность вживую

Запустим ту же команду еще раз, ничего не меняя:

PLAY RECAP *******************************************************
web-01 : ok=4  changed=0  failed=0

Все задачи вернули ok, changed=0. Nginx уже установлен, служба уже запущена, состояние совпало, и Ansible не тронул ничего. Вот она, идемпотентность, вживую. Playbook можно запускать хоть каждый час: это не скрипт установки, который повторно что-то сломает, а описание состояния, к которому сервер каждый раз приводится. Если кто-то руками остановил nginx, следующий запуск его поднимет, и в логе это будет видно как changed.

А теперь сто серверов

Момент, ради которого все затевалось. В playbook не меняется ничего. Меняется только инвентарь:

[web]
web-01 ansible_host=10.0.0.11
web-02 ansible_host=10.0.0.12
...
web-99 ansible_host=10.0.0.99

А если имена серверов идут по порядку, всю сотню можно записать одной строкой с диапазоном:

[web]
web-[01:99].company.internal

Команда запуска та же самая, до последнего символа:

ansible-playbook -i inventory.ini site.yml

Ansible пойдет по серверам параллельно, пачками, и в конце выдаст PLAY RECAP на сто строк. По времени это занимает не в сто раз дольше, чем один сервер, именно из-за параллельности.

Отдельно приятно, как это работает при сбоях. Если сервер web-47 оказался недоступен, Ansible покажет по нему failed, а остальные 99 спокойно настроит. Чините сорок седьмой, запускаете playbook снова, и благодаря идемпотентности 99 уже настроенных серверов просто вернут ok, а web-47 получит свой changed. Не нужно вспоминать, на каких серверах вы уже были.

И теперь та задача из начала прошлого блока: сервер сгорел, и нужна точная копия. С Ansible она решается так: новый пустой сервер добавляется строчкой в инвентарь, запускается playbook, и через пару минут копия готова. Файл с playbook при этом лежит в Git, так что у вас есть и история изменений настройки, и ревью перед применением, все, что ранее обещал подход «инфраструктура как код».

Куда это растет

Через переменные один playbook обслуживает разные окружения: на тестовом сервере nginx слушает один порт, на боевом другой, а файл один. Через шаблоны из одного образца конфига генерируются персональные конфиги под каждый сервер. А когда задач становится много, их собирают в роли, переиспользуемые блоки вроде «роль веб-сервера» или «роль базы данных», из которых playbook собирается как из конструктора. Все это территория буткемпа, а для понимания сути хватает сегодняшних десяти строк.