Конфигурация VM с Vagrant и Ansible

Ansible vagrant

А я тем временем продолжаю выискивать, чем бы ещё автоматизировать настройку хостов. До сих пор я пользовался связкой Vagrant + bash/PowerShell для линуксовых или виндовых хостов, но каким-то странным образом пропустил тулзу, которая подходит под это дело лучше, чем просто скриптовать всё подряд, — Ansible. Она существует уже лет пять, и, как я заметил, превратилась практически в синоним фразы «автоматическая конфигурация». Сегодня, наконец, я её пожмякаю. Посмотрим, так ли уж Ansible удобнее, чем старый добрый bash.

Что такое Ansible

Как я уже сказал, Ansible — это инструмент для автоматический конфигурации хостов. «Автоматической конфигурацией» может быть как одиночная команда, вроде reboot, отправленная стайке ничего не подозревающих хостов, так и целая коллекция задач — playbook, которая и сервис установит, и конфигурацию скопирует, и убедится, что всё запустилось. Количество хостов при этом не играет ни какой роли. Что один, что сто один — без разницы.

Ещё Ansible использует push подход. То есть когда хосту нужно доставить новые настройки, это не он запрашивает их у контроллера, а хост-контроллер явно отправляет их получателям. В качестве транспорта может идти как SSH для никсовых машин, так и PowerShell для оконных. Так как Ansible написан на Питоне, то того придётся устанавливать и на хосте-контроллере, и на настраиваемых серверах. Последнее нужно потому, что Ansible сначала копирует .py файл с командой на сервер и потом запускает его уже там, а не командует локально.

Ну вроде со вступлением разобрались, будем чего-нибудь делать.

План

Я думаю переписать настройку Consul-сервера, которую делал в прошлых постах. В тот раз это был Vagrant и bash, но Vagrant + Ansible произносится заметно интереснее, так что должно получиться весело.

Навскидку, установка и настройка Consul-сервера на Ubuntu машину проходила так:

  1. Устанавливаем unzip.
  2. Скачиваем и распаковываем Consul.
  3. Даём ему права на запуск.
  4. Копируем consul в /usr/local/bin — он же сервисом будет.
  5. Копируем концигурацию Consul как systemd сервиса в /etc/systemd/system/.
  6. Копируем просто конфигурацию Консула в /etc/systemd/system/consul.d/.
  7. Запускаем сервис.

Вглядит как нечто, с чем Ansible должен справиться на ура.

Установка

Я всё ещё буду пользоваться Vagrant и VirtualBox для создания виртуального хоста, и устанавливать их, как всегда, — одно удовольствие. Но вот установить и запустить Ansible на маке оказалось сложнее, чем привычное скачать-и-запустить. Пришлось добывать питоновский pip, потом им устанавливать ansible, а затем ставить sshpass,  чтобы Ansible мог подключаться по SSH с логином и паролем. За кадром, кстати, осталось то, как я обновлял openssh и пересобирал Python, чтобы дать возможность Ansible скачивать файлы с мака по TLS 1.2. Не удалось, между прочим.

Шаг 0. Создаём и подготавливаем host

Вот люблю я создавать машины. Чтобы Ansible тоже был счастлив, хосту, с которым он будет общаться нужно: создать, собственно, хост, поставить на него Python и создать какого-нибудь пользователя для дружбы по SSH. C Vagrant это делать одно удовольствие.

Первым делом создаём Vagrantfile:

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

Легкотня. Теперь выполняем vagrant up и можем начинать тестировать SSH соединение:

Соединение работает. Кроме этого радостного факта произошла ещё одна полезная вещь: ssh добавил fingerprint новой виртуальной машины в доверенные хосты (~/.ssh/known_hosts). Без этого подключаться к ней можно было бы только убедив Ansible верить всем подряд (есть такая штука в настройках), что для нашей задачи уже перебор.

Гуд. Хост готов, пора его отансиблить©.

Шаг 1. Создаём inventory файл

Ansible хранит хосты, с которыми ему предстоит дружить, в инвентарных файлах. Это обычные INI файлы, в которых можно ложить айпишки, доменные имена, параметры подключения, группы и переменные… много чего можно ложить. Но, в принципе, даже одинокого IP адреса достаточно, чтобы inventory файл стал полноценным.

По умолчанию Ansible будет искать файл в /etc/ansible/hosts, но так как я не хочу пачкать Mac очередным временным файлом, лучше уж я положу его рядом с Vagrantfile. Вот каким инвентарник получился у меня:

Да-да-да, хранить SSH пароль открытым текстом в файле настроек, как пОшло. С другой стороны, виртуальной машины через пару часов не станет, так что почему бы и нет. Но в продакшене я бы определённо пользовался либо SSH сертификатами, либо Ansible Vault.

Ещё один момент. Хотя ansible_ssh_pass параметр и считается deprecated, а я должен пользоваться свежим ansible_pass, новый параметр работал у меня через раз. Не знаю, это проблемы мака, лунного затмения, или золотых рук, растущих из пятой точки, но старый параметр работает всегда, а новый — нет. Выбор был простым.

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

Ansible определённо завёлся, это хорошо. Первая команда запустила ping модуль (-m) для всех (all) хостов из inventory файла по имени hosts (-i hosts), а вторая отправила команду (lsb_release -r) прямо в шелл и узнала, какой версии Убунта там запущена. Если бы в hosts было сто машин, я бы получил сто версий.

all, кстати, не единственный доступный параметр. Можно было бы использовать и имя группы, если бы у меня была хоть одна, и имя хоста, вроде consul-server.

Шаг 2. Создаём playbook

Слать команды по одной — удивительный отстой (классный стих, правда?). Чтобы собрать что-то более сложное, нужно брать сразу много команд и ложить их в специальный файл — playbook.

Плейбук — это обычный YAML файл, в котором будут складироваться, в принципе, все те же вещи, что мы запускали из командой строки: хосты, модули. И не только. Читается этот файл потом как обычный текст. Чтобы это продемонстрировать, попробуем как сделать первый шаг установки консула — установить unzip.

Шаг 2.1 Устанавливаем unzip

Вот такой плейбук сделает необходимую магию на Дебиан-подобных системах:

В этот раз я явно указал имя хоста вместо allconsul-server. За ним идёт секция-коллекция tasks, в которую, собственно, и ложатся индивидуальные команды-модули. Сейчас там только один apt, которые умеет управлять убунтовскими apt пакетами и делать что-то похожее на apt-get install. Вся четвёртая строка практически как обычный текст: «возьми apt, убедись что unzip есть».

Самый кайф именно в «есть». Не «установи», а просто есть. При такой формулировке нормально ожидать, что если unzip уже был, то его трогать не надо. Такое поведение называется идемпотентностью, возможностью повторять одно и то же действие много раз и получать один и тот же результат, и в посте с конфигурацией консула через bash её приходилось делать отдельно. А в Ansible она есть по умолчанию. Даже command модуль, которым мы просто запускали шелл команды, можно запросто научить идемпотентности.

И да, почти забыл. Был ещё один параметр become: true. Это эквивалент sudo. Будучи простым смертным юзером ведь ничего толкового в наши дни не установишь.

Но хватит болтовни, будем запускать плейбук:

На новой Убунте unzip не было, поэтому задача «Install unzip» отчиталась, что что-то изменила. Если же запустить плейбук ещё раз (я пробовал), то во второй раз он скажет, что всё и так прекрасно.

Шаг 2.2 — 2.4 Качаем и устанавливаем Consul

То, что было аж тремя шагами в bash, станет одним шагом в Ansible. Модуль unarchive может и скачать архив, и распаковать, и положить, куда нужно, и даже права доступа настроить.

Настроить его для скачивания консула можно вот так:

Я добавил пару пустых строк для пущей читабельности (не ясно, правда, стало ли читабельнее) и использовал ещё одну новую фичу Ansible — переменные. Но вообще «Install Consul» задача получилась вполне понятной. Из особо интересного: creates свойство, делающее задачу идемпотентной, и mode, устанавливающее пермишены на consul (r-x).

Перезапустив плейбук, можно проверить, что консул теперь действительно существует:

… и, следовательно, мыслит.

Шаг 2.5 Делаем Consul systemd сервисом

Чтобы сделать Consul сервисом нужно просто скопировать уже готовый заголовок сервиса в папку к остальным. Ещё с прошлого поста про Консул у меня остался consul.service, и абсолютно без изменений он пошёл и в этот. Ansible модуль же, который умеет копировать файлы, называется (сюрприз!) copy. Ну никакой фантазии у буржуев.

Шаг 2.6 Настраиваем Consul

Чтобы настроить Consul нужно скопировать ещё один файл. В этот раз JSON. В нашем случае это будет init.json, телепортированный в   /etc/systemd/system/consul.d. Проблема в том, что в init.json будет айпишка сервера, и я не хочу ещё жёстко туда прошивать. Лучше бы её хранить где-нить на уровне playbook, и передавать в конфигурацию как параметр для шаблона. Что приятно, Ansible понимает шаблоны прямо из коробки, так что этот трюк легко провести.

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

Озабоченность принесла свои плоды, так что у нас теперь есть шаблон конфигурации init.json.j2, где j2 означает язык шаблонов Jinja2, и два новых шага (плюс 2 переменных) в плейбуке.

Шаг 2.6 Запускаем сервис

Это будет одна из самых простых задач. В Ansible есть модуль по имени service, который умеет делать с сервисами всё, что угодно. В том числе и запускать:

Если вы дочитали аж до сюда, и можете запустить плейбук целиком, то во вселенной станет на одну айпишку больше, и на её 8500 порту (192.168.99.100:8500) будет вот что:

consul

Да, это живой консул. Всячески кликабельный и полезный.

Шаг 3. Дружим Vagrant с Ansible

Есть ещё такой момент — Vagrant может использовать Ansible напрямую, так что запустить плейбук можно сразу из Vagrantfile:

Я даже убрал строку, которая устанавливала пароль для ubuntu, так как управление инвентарным файлом и паролями теперь головняк для Vagranta, не для меня.

Если теперь удалить существующую виртуалку через  vagrant destroy -f и запустить новую с vagrant up, то полностью готовый хост с Консул получится ровно в одну команду.

Мораль

Мне понравилось. Хотя установка Ansible на Mac м отличалась от тривиальной, конфигурация хоста модулями в YAML мне нравится больше, чем кодом в bash. Её проще читать, идемпотентность получается автоматически, и вместо того, чтобы изобретать каждый раз колесо, можно использовать армаду готовых модулей.

Кроме этого, мы совсем не затронули такую штуку в Ansible как роли — переиспользуемые куски плейбуков. Например, «ftp server». Более того, есть такая штука, как Ansible Galaxy — паблик хаб для таких ролей. Если в ней поискать готовую роль по имени «Consul service», то она-таки там будет. Много, много готовых Консул-ролей.

Конфигурация VM с Vagrant и Ansible: 2 комментария

  1. «Ansible сначала копирует .py файл с командой на сервер и потом запускает его уже там, а не командует локально.»
    Не всегда такое возможно совершить, например на сетевом оборудовании не всегда есть Python, но оборудование конфигурится вполне спокойно конфигурится при помощи Ansible, для этого в playbook указывается
    gather_facts: false
    connection: local

Добавить комментарий для Pavel Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *