От установки AWX до запуска первого плейбука — настройка централизованного управления Ansible

wwtwwh3edq-fkzaucew35slxxdy.png

Количество серверов в нашей инфраструктуре уже перевалило за 800, хотя еще год назад их было около 500. Для работы с этим всем активно используются решения от Red Hat. Про FreeIPA — для организации и управления доступами для Linux-серверов — мы уже писали, сейчас же я хочу затронуть тему управления конфигурациями. Для этих целей у нас юзается Ansible, а с недавних пор к нему добавился AWX — представленное полгода назад решение для централизованного управления плейбуками, расписанием их запусков, управления инвентори, учетными данными для доступа к серверам, а также механизм callback’ов для запроса конфигураций со стороны сервера.

Из-за ряда вещей мы не сразу смогли интегрировать его для работы с нашим основным проектом War Robots, но полей для проверки AWX нашлось предостаточно. Во-первых, в компании ведутся разработки новых проектов, которым нужны dev/stage-окружения и, само собой, production-окружения в перспективе. А недавно к этому добавился еще и проект для внутренней аналитики, которому потребовался полностью новый кластер.

Итак, начнём!

AWX был представлен в сентябре 2017 года — это бесплатный open source проект, распространяющийся под лицензией Apache-2.0 и являющийся апстримом для коммерческого проекта Ansible Tower. В целом, тут тот же принцип, что и у других проектов Red Hat: Red Hat Cloud Forms — ManageIQ; RHEV — Ovirt; Red Hat Identify Managment — FreeIPA и так далее.

Данная статья представляет из себя руководство — от установки AWX до запуска первого плейбука. Но сначала перечислим основные возможности AWX:

  • Интеграция с системами контроля версий (git/mercurial/subversion).
  • Отслеживание статуса выполнения плейбуков в реальном времени.
  • Настройка расписания для автоматического запуска плейбуков.
  • Выполнение нескольких плейбуков в рамках одного workflow.
  • Удаленное выполнение команд без плейбуков (Ansible ad hoc).
  • Поддержка механизма callbackов, позволяющих новым серверам запрашивать конфигурации со своей стороны.
  • Управление Inventory для ансибла, в том числе с возможностью интеграции с платформами AWS/Azure/OpenStack и т.д., а также поддержка собственных скриптов для генерации Dynamic Inventory.
  • Гибкая система разграничения прав доступа. Интеграция с LDAP/SAML/Active Directory и т.д.
  • Встроенная поддержка уведомлений для Email/Slack/PagerDuty/HipChat/MatterMost/IRC.
  • Интеграция с внешними системами агрегации логов: Logstash/Splunk/Loggly/Sumologic.


Установка


В данный момент поддерживается несколько вариантов установки:

  1. Kubernetes.
  2. Openshift.
  3. Docker/Docker Compose.


Все они описаны в документации на GitHub, а для примера рассмотрим вариант с чистым Docker, так как это самый быстрый вариант, не требующий дополнительной настройки OpenShift/Kubernetes.

Устанавливать всё будем на Centos 7. Установка Докера также описана в официальной документации, поэтому в статье ее трогать не будем.

Далее нам нужно установить ansible и модуль docker-py. Это можно сделать из pip:

pip install ansible
pip install docker-py


Клонируем репозиторий AWX:

git clone https://github.com/ansible/awx.git
cd awx/installer


Правим файл inventory. В первую очередь, рекомендую поправить переменную postgres_data_dir. По умолчанию она равна /tmp/pgdocker, но если оставить в таком виде — через некоторое время можно потерять postgresql базу, которую использует AWX.

Если вы хотите использовать внешнюю базу, укажите переменные:

pg_hostname
pg_username 
pg_password 
pg_database
pg_port


После этого запускаем:

ansible-playbook -i inventory install.yml


Эта команда запустит выполнение плейбука, который загрузит нужные docker-образы и запустит контейнеры непосредственно с AWX и дополнительными компонентами: Postgres, MemCached, RabbitMQ.

После завершения выполнения плейбука мы должны увидеть следующие контейнеры:

docker ps

CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS              PORTS                                NAMES
b1bd94f83420        ansible/awx_task:latest   "/tini -- /bin/sh ..."   6 days ago          Up 6 days           8052/tcp                             awx_task
abf30fd81335        ansible/awx_web:latest    "/tini -- /bin/sh ..."   6 days ago          Up 6 days           0.0.0.0:80->8052/tcp                 awx_web
b13ee3c7cbb7        memcached:alpine          "docker-entrypoint..."   2 months ago        Up 6 days           11211/tcp                            memcached
3c4cac5a4ce5        rabbitmq:3                "docker-entrypoint..."   2 months ago        Up 6 days           4369/tcp, 5671-5672/tcp, 25672/tcp   rabbitmq
b717c6019e02        postgres:9.6              "docker-entrypoint..."   2 months ago        Up 6 days           5432/tcp                             postgres


Следить за процессом установки AWX можно следующим образом:

docker logs -f awx_task


AWX будет доступен по адресу сервера на 80 порту (если вы не поменяли порт в файле inventory).

Логин и пароль по умолчанию:

Admin:password


Использование и примеры


Теперь перейдем непосредственно к AWX, но сначала немного разберемся с тем, как всё организовано.

В первую очередь нас интересует раздел Projects. Projects в терминологии AWX означает набор плейбуков, которые расположены локально на сервере с AWX или в репозитории.

Создадим наш первый Project:

vux5fsqhdi3ysx67nhirplwe0lm.png

— Name: имя проекта, пускай это будет firstproject.
 — Organization: в AWX это сущность, которая используется для разграничения доступа. К Organization могут относиться инвентори, пользователи, группы пользователей, плейбуки. Выберем Default.
 — SCM TYPE: тип репозитория, может быть либо локальная директория, либо одна из систем контроля версий на выбор: git, mercurial, subversion.
 — SCM Url: урл для репозитория.
 — SCM branch/tag/commit: опционально можно указать необходимый branch/tag/commit.
 — В поле SCM credentials можно выбрать реквизиты, которые будут использоваться для доступа к репозиторию.

Также можно отметить галочками чекбоксы:

— Clean: удалить все локальные изменения перед обновлением.
 — Delete on Update: при обновлении Project’а удалять локальную копию и заново загружать новую копию репозитория.
 — Update on Launch: при каждом запуске плейбука из этого Project’а обновлять локальную копию репозитория до актуальной версии. Можно использовать в связке с Delete on Update, но это может привести к более долгому выполнению плейбука, так как каждый раз потребуется ждать окончания синхронизации с репозиторием.

Выберем Clean и Update on Launch. Нажимаем Save и после этого создание нашего первого Project’а завершено.

Перейдем в раздел Projects и для нашего Project’а нажмем на кнопку Start an scm update. Дождемся завершения первой загрузки нашего репозитория (следить за статусом обновления можно в разделе Jobs).

Посмотрим на плейбук, который находится в нашем репозитории. На Хабре есть множество статей, в которых рассказывается об Ансибле и структуре его плейбуков/ролей поэтому подробно расписывать этот момент не станем (вот несколько статей для примера: 1, 2, 3).

firstproject/
├── ansible.cfg
├── group_vars/
├── host_vars/
├── roles/
│   └── requirements.yml
└── run.yml


Файлы .yml, расположенные в корне директории firstproject, AWX воспримет как плейбуки.

Содержимое файла run.yml:

---
  - name: Test Role
    hosts:
      - all
    gather_facts: true
    roles:
      - roleawx


То есть просто запускаем roleawx, предварительно собрав факты. Hosts указываем all, так как указать хосты и хост группы можно в самом AWX.

Дальше интересный момент — содержимое файла roles/requirements.yml:

- src: git@gitlab.example.com:ansible-roles/roleawx.git
  scm: git


При синхронизации Project’а AWX сам установит все роли в директорию roles в соответствии с файлом requirements.yml. В данном случае он установит роль roleawx из git репозитория.

Создадим роль с помощью команды:

ansible-galaxy init roleawx


Структура роли будет такой:

roleawx/
├── README.md
├── defaults
│   └── main.yml
├── files
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
├── tests
│   ├── inventory
│   └── test.yml
└── vars
    └── main.yml


Содержимое файла tasks/main.yml:

---
# tasks file for roleawx
  - name: Test Message
    debug:
      msg: "AWX and Ansible"


Для начала просто выведем сообщение «AWX and Ansible».

Обратите внимание, для того чтобы AWX автоматически установил роли, указанные в файле requirements.yml, в самой роле должен быть корректно сформирован файл meta/main.yml (если вы создали шаблон для роли с помощью ansible-galaxy init, то с meta/main.yml всё хорошо и AWX сможет загрузить эту роль).

Итак, у нас есть репозиторий с плейбуком, есть репозиторий с ролью. А так же у нас есть несколько виртуальных машин с адресами 192.168.10.233, 192.168.10.234 и 192.168.10.239.

Перед тем, как запустить наш плейбук, нам надо сделать так, чтобы Ansible смог попасть с сервера AWX на наши хосты (в нашем случае по SSH). Мы можем указать пароли прямо в переменных внутри плейбука, но это неинтересно. AWX умеет управлять реквизитами для доступа к серверам и мы этим воспользуемся.

Перейдем во вкладку Credentials и нажмем кнопку Add:

suih98rhqp4fbyak8m0mszxzzai.png

— Name: укажем имя для наших реквизитов.
 — Credential Type: здесь можно выбрать тип реквизитов. Нас интересует Machine, чтобы использовать их для доступа к нашим серверам. Помимо этого AWX предлагает множество разных типов реквизитов доступа, которые можно использовать для интеграции с различными сервисами, такими как scm (git, svn, mercurial), Red Hat Insight, AWS, Azure, Red Hat Satellite, RHEV, Vmware, OpenStack. А ещё можно создавать свои собственные типы credentials.
 — Имя пользователя: выберем root.
 — Пароль: оставляем пустым, так как мы будем использовать доступ по ключу.
 — PRIVATE KEY PASSPHRASE: пароль для ключа, если ключ создан с паролем. В нашем случае ключ без пароля, поэтому поле оставляем пустым.
 — PRIVILEGE ESCALATION METHOD: метод повышения привилегий. Например: sudo, su, pfexec и и т.д.
 — PRIVILEGE ESCALATION USERNAME: пользователь, под которым Ansible должен получить привилегии.
 — PRIVILEGE ESCALATION PASSWORD: пароль для повышения привилегий.

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

Обратите внимание: у ряда полей есть чекбокс Prompt on launch. При активации этого чекбокса соответствующее ему поле будет предложено заполнить вручную при каждом запуске плейбука, с которым ассоциированы данные реквизиты. Таким образом можно не сохранять пароль внутри AWX, а запрашивать его при каждом запуске плейбука.

Итак, мы создали Project и реквизиты для доступа к серверам. Теперь нам необходим Inventory.

Перейдем в раздел Inventory, нажимаем кнопку Add. На выбор будет предложено создать:

— Inventory: обычный Inventory.
 — Smart Inventory: позволяет генерировать inventory на основе уже существующих хостов, основываясь на каких-либо параметрах, например, на типе операционной системы.

Создадим обычный Inventory:

do62ztdla2chffmzpmbmqmtjws4.png

— В поле Name указываем имя.
 — Выбираем Default Organization.
 — В поле Variables можно указать переменные, которые в дальнейшем будут доступны из плейбука.

Пробуем указать:

---
  awxinvvar: "Test"


Остальные вкладки неактивны, пока мы не сохраним наш Inventory.

Сохраняем и возвращаемся в раздел Inventory. Наш Inventory появился в списке. Перейдем в него: после создания верхние вкладки стали активны.

— Permissions: здесь контролируется, кто из пользователей или групп пользователей имеет доступ к Inventory.
 — Groups: список хост-групп.
 — Hosts: список хостов.
 — Sources: список источников для Inventory. Можно выгружать инвентори из AWS/Azure/OpenStack/RHEV и ещё ряда сервисов, можно указать инвентори файл, который находится внутри нашего Project’а или же указать в качестве источника свой собственный скрипт, который генерирует Dynamic Inventory.
 — Completed Jobs: список запущенных плейбуков, ассоциированных с хостами из текущего Inventory.

Наш Inventory заполняем руками, так как у нас мало хостов. Перейдем во вкладку Hosts и создадим несколько хостов:

8ou_ukqsirxmkn7rvfc3bgmxwqw.png

— В поле Host Name можно указать IP-адрес сервера или его DNS-имя.
 — В поле Variables попробуем переопределить переменную awxinvvar для одного из наших хостов:

---
  awxinvvar: "Host1"


После создания хостов перейдем во вкладку Groups и создадим группы для наших хостов:

niggt_yc4xlzhemflhtfrf3y8r8.png

Точно так же укажем имя группы и переопределим переменную awxinvvar для одной из групп.

Возвращаемся во вкладку Hosts, выбираем один из хостов из списка, переходим на вкладку Groups для этого хоста и нажмем Associate Group:

f66tm76tss26ukyrowflgslk-j4.png

На кладке Hosts теперь можно увидеть, в каких группах состоит каждый из хостов:

5y_x0vveun9lbbmcnvfcdrsanbo.png

Кстати, на вкладках Hosts и Groups также доступна кнопка Run command. Это аналог ad-hoc команд в Ansible, которые позволяют выполнить действия на удаленных хостах, без плейбука.

Давайте попробуем. Выберем наши хосты из списка, выберем ключ для доступа по SSH, который создали ранее и попробуем выполнить команду date c помощью модуля shell:

gpkmbdv2bqqej6ix7aeaalbjvr8.png

Нажимаем Launch. Нас должно перекинуть на страницу, на которой мы сможем в реальном времени следить за выполнением. Также все запуски плейбуков/ad-hoc команд видны в разделе Jobs.

pwrhcbcnfyyfcxmy5nokqagdflm.png

Наша ad-hoc команда успешно выполнилась.

Давайте теперь попробуем запустить наш плейбук. Перейдем в раздел Templates, нажмем кнопку Add, выберем Job Template.

В терминологии AWX Template — это набор параметров, которые используются для запуска плейбука. В минимальном виде необходимо указать имя шаблона, выбрать project, выбрать playbook, выбрать inventory.

Выглядит создание шаблона так:

4o4dsictigtghc15fbmgnzy06-4.png

— Name и Description: имя и описание шаблона.
 — Job Type: Run или Check. То есть запуск плейбука или только проверка плейбука (dry-run) без внесения изменений.
 — Inventory: Inventory, с которым будет запускаться плейбук.
 — Project и Playbook: предназначены для выбора Project’а с плейбуками и конкретного плейбука из Project’а.
 — Limit: список хостов и групп, на которых будет запущен плейбук.
 — Verbosity: насколько подробно Ansible будет выводить результат выполнения (аналог ключей -v -vv -vvv).
 — Job tags: список тегов — задачи, с которыми должны быть запущены. Если не указывать, будет выполнены все задачи описанные в ролях.
 — Skip tags: список тегов — задачи, с которыми не будут выполняться.
 — Labels: метки, которые будут ассоциироваться с данным шаблоном. Можно использовать для фильтрации в самом AWX.
 — Show diff: показывать изменения, которые делает Ансибл (аналог ключа --diff).

Сохраняем проект, возвращаемся в раздел Templates, и запускаем наш плейбук (кнопка в виде ракеты):

ycqe_zd3zans2-ukzxxxt6xflvc.png

Ура, наш плейбук запустился, загрузил нужные роли и успешно отработал. Кстати, на этой же странице вы можете загрузить результат выполнения плейбука. Также имеется возможность поиска по выводу плейбука.

Помните, мы добавили переменную awxinvvar в нескольких местах? Давайте попробуем вывести её в и посмотреть, что получится.

Добавляем в нашу роль в файл tasks/main.yml следующее:

  - name: Print var
    debug:
      msg: "{{ awxinvvar }}"


И снова запускаем наш template.

ptybfsxtqpc3k8yxiez14nyzm2e.png

Плейбук видит нашу переменную, которую мы определили в Inventory и корректно её переопределяет в соответствии с приоритетом применения переменных.

Переменные, кстати, можно хранить и в репозитории в директориях host_vars group_vars, если вам так удобнее. Правда, в таком случае они не будут отображаться в Inventory в самом AWX.

Вместо заключения


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

Примечание: новые релизы сейчас выходят часто и могут возникнуть проблемы при обновлении. Делайте бэкапы!

Данное руководство написано для ознакомления с базовыми функциями AWX, а если будет интересно — напишем про дополнительный полезный функционал, вроде интеграции с источниками для Dynamic Inventory, механизм Callback’ов и т.д.

P.S. Вот так, кстати, выглядит наш дашборд AWXа, который мы используем для части инфрастуктуры:

0yosop_jolgxh-xhcsjk1pbcjf0.png

© Habrahabr.ru