Управление конфигурациями удалённых систем - неотъемлемая часть повседневной работы Администраторов и операционных групп. Поэтому актуальной остаётся задача автоматизации этого трудоёмкого процесса. Для этих целей используется ряд программных инструментов, одним из которых выступает Ansible. Характеристики и способ обработки данных позволяют говорить об очевидных преимуществах программы перед своими аналогами. Рассмотрим более детально её возможности и примеры использования на практике.
Методы управления конфигурациями удалённых систем
Суть процесса автоматизации управления большим количеством удалённых систем состоит в реализации двух основных задач или этапов: приведение конфигурации систем к одинаковому устойчивому состоянию; применение одного из механизмов управления вносимыми изменениями. Для решения указанных задач может быть применён один из двух основных подходов – императивный или декларативный.
Императивный подход предусматривает формирование обязательных директив или алгоритмов для получения нужного состояния конфигураций и обычно реализуется с помощью bash-скриптов. К недостаткам подхода можно отнести сложность структуры программ и их обслуживания, а также невозможность обеспечить точное выполнение требования по приведению конфигураций удалённых систем к одному устойчивому состоянию.
Суть декларативного подхода заключается в формировании набора спецификаций для описания нужных состояний конфигураций удалённых систем и дальнейшего использования для их обработки программного обеспечения (ПО) на стороне клиентских машин. В отличие от предыдущего подхода, составление спецификаций является гораздо менее трудоёмким процессом по сравнению с программированием, и здесь гарантировано получение устойчивого состояния конфигурации сразу для всех систем. К недостаткам можно отнести определённую трудоёмкость работ по установке ПО на клиентах. В качестве примера реализации можно указать хорошо известную программу Chef.
Одним из вариантов декларативного подхода является использование на стороне клиента вместо специального ПО стандартизированных программных средств, таких, например, как Python. Именно этот вариант реализован в системе Ansible. Управление запуском обработчиков спецификаций на стороне клиента здесь осуществляется с помощью push-сообщений, которые посылаются с сервера по защищённому ssh-каналу. Таким образом дополнительно обеспечивается надёжная защита передаваемых по сети данных.
Структурная организация программной среды Ansible
Работа системы сводится к постоянному взаимодействию между собой трёх основных элементов:
- Управляющий узел или сервер;
- Клиентские машины или удалённые клиенты;
- Динамический список хостов или Inventory (в контексте терминологии разработчиков).
Установка и настройка программы предусмотрена только на управляющем узле. На машинах-клиентах достаточно наличие среды выполнения Python версии Python 3 или выше. Список Inventory постоянно находится на управляющем узле, претерпевая изменения согласно актуальному состоянию конфигурации обслуживаемого кластера удалённых машин.
Выполнение подготовительных этапов перед установкой Ansible на Ubuntu 22.04
Как и для любого другого ПО, здесь необходимо выполнить ряд подготовительных действий, что гарантирует впоследствии корректную работу и установку программы. Сюда можно отнести следующие действия:
- Создание на управляющем узле пользователя с правами sudo;
- Создание на сервере пары ssh-ключей;
- Подготовка списка хостов кластера (Inventory);
- Копирование открытых ssh-ключей на клиентские машины;
- Создание на сервере среды выполнения Python 3.
Выполним на нашем сервере каждое из указанных действий.
Создание пользователя
Для начала создадим на сервере учётную запись пользователя с именем testing_ansible. Для этого наберём в терминале:
$ adduser testing_ansible
Учётная запись была успешно создана. После этого добавим вновь созданного пользователя в администраторскую группу sudo:
$ adduser testing_ansible sudo
Результат выполнения команды: «Adding user testing_ansible to group sudo Done.» (пользователь успешно добавлен в группу sudo).
Сменим текущий аккаунт на только что созданный с помощью следующей команды:
$ su -l testing_ansible
Как видим, мы зашли в систему под учётной записью пользователя testing_ansible и в дальнейшем будем формировать все команды от его имени.
Создание ssh-ключей
Ssh-ключи предоставляют альтернативный способ аутентификации пользователей удалённых систем, который имеет более высокий уровень защиты по сравнению с методом аутентификации на основе пароля. Поэтому он является предпочтительным. Суть его использования заключается в передаче на удалённые машины кластера открытого ключа, в то время как закрытый ключ остаётся на сервере и предоставляется только по запросу удалённого клиента.
Сгенерируем пару ssh-ключей при помощи следующей команды:
$ ssh-keygen
В результате выполнения команды ключи были созданы и сохранены в каталоге /home/testing_ansible/.ssh/. Файл закрытого ключа – id_rsa, открытого – id_rsa.pub.
Подготовка списка Inventory
Список необходим для работы программы в автоматическом режиме. Например, для рассылки по сети управляющих push-сообщений программа берёт всю нужную информацию о хостах именно из этого списка. Здесь, в частности, должны быть указаны такие данные, как символические имена хостов, их IP-адреса, а также имена пользователей для подключения к удалённой системе. Целесообразно создать на всех хостах учётные записи пользователей с правами sudo, имена которых совпадали бы. Впоследствии это облегчит выполнение настроек на сервере.
В нашем случае для подключения ко всем хостам кластера будет использоваться учетная запись с именем alexandr75001.
Символические имена хостов будут следующими:
server1
server2
server3
Их IP-адреса:
201.0.111.101
201.0.111.102
201.0.111.103
Впоследствии эта информация должна быть помещена в системный файл /etc/ansible/hosts. Этим мы займёмся позже.
Копирование открытого ssh-ключа на машины кластера
Для возможности беспрепятственного защищённого доступа Ansible к удалённым машинам кластера, необходимо обеспечить наличие на каждой из них созданного нами ранее файла открытого ключа id_rsa.pub. Это можно сделать разными способами, в том числе и ручным копированием. Однако в случае большого числа машин такой подход неприемлем. Поэтому мы автоматизируем этот процесс при помощи команды ssh-copy-id. Для демонстрации процесса будем использовать сторонний хост, не входящий в наш список Inventory. Введём в терминале:
$ ssh-copy-id alexandr75001@176.9.11.135
Указанный в команде узел пока не является доверенным для нашего сервера, поэтому в запросе командной строки нам нужно подтвердить своё согласие на это с помощью подтверждающей языковой конструкции yes.
После этого утилита инициирует поиск файла открытого ключа для текущей учётной записи сервера и когда он будет найден, запросит пароль удалённого пользователя alexandr75001, как показано ниже:
После подключения к хосту утилита скопирует содержимое файла id_rsa.pub в файл authorized_keys, находящийся в домашнем каталоге удалённого пользователя. Ниже показан результат выполнения этой операции – «Number of key added: 1» (Добавлен один ключ).
Для проверки надёжности установленной связи между хостами подключимся к удалённой системе с помощью следующей команды:
$ ssh alexandr75001@176.9.11.135
Можно убедиться, что мы теперь находимся на удалённом хосте под учётной записью alexandr75001, что видно по приглашению командной строки.
Такого же типа действия мы должны были бы выполнить для всех удалённых систем списка Inventory. Это гарантировало бы в дальнейшем безошибочную работу программы Ansible. После такой настройки пароли уже не будут запрашиваться при подключении к удалённым системам.
Для возврата на сервер наберём в терминале команду выхода:
$ exit
Теперь мы опять на сервере, где и продолжим свою работу.
Подготовка программной среды
Для начала проверим версию языка Python, установленного на сервере. Для этого введём в терминале:
$ python3 --version
Установленная версия – «Python 3.10.12», что соответствует системным требованиям для работы Ansible.
После этого обновим индекс программных пакетов Ubuntu:
$ sudo apt update
Поскольку файлы программы Ansible в сети хранятся в отдельном репозитории, необходимо открыть к нему доступ, добавив его имя в список источников для нашей системы. Это можно сделать с помощью следующей команды:
$ sudo apt-add-repository ppa:ansible/ansible
Среда для установки программы подготовлена.
Установка Ansible
Теперь можно приступать к установке. Введем в терминале:
$ sudo apt install ansible
Подтверждаем своё согласие на выделение 300 Mb места на диске, и процесс установки программы начинается.
Установка была успешно завершена. Убедимся в этом с помощью команды определения версии и одновременно просмотрим пути доступа к основным компонентам программы. Введём в терминале:
$ ansible --version
Ниже представлен вывод команды:
ansible [core 2.15.8]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/testing_ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/testing_ansible/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
jinja version = 3.0.3
libyaml = True
Как видим, все компоненты программы на месте, и пути к ним определены. Значит, всё в порядке.
Настройка сервера Ansible
Настройка сервера состоит в формировании списка Inventory в системном файле /etc/ansible/hosts, а также настройке параметров в файле конфигурации /etc/ansible/ansible.cfg. Выполним всё по очереди.
Настройка параметров файла hosts
Как уже говорилось, список хостов кластера необходим для возможности выполнения подключения к машинам в автоматическом режиме без вмешательства Администратора. Путь к этому списку (/etc/ansible/hosts) обычно устанавливается по умолчанию, однако при необходимости его можно изменить в интересах текущего проекта. Откроем файл с помощью следующей команды:
$ sudo nano /etc/ansible/hosts
Вставим в него приведённый ниже код:
[servers]
server1 ansible_host=201.0.111.101
server2 ansible_host=201.0.111.102
server3 ansible_host=201.0.111.103
[all:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=alexandr75001
Код содержит два раздела: [servers] и [all:vars]. В первом из них указаны псевдонимы хостов кластера и их IP-адреса. Во втором разделе указаны общие для всех хостов параметры – установлен общий для всех хостов интерпретатор языка Python, а также общее имя пользователя.
Вставим наш код в файл hosts, как показано выше и сохраним внесённые изменения (ctrl+O, Enter). Вернёмся в командную строку терминала (ctrl+X).
После этого нам остаётся убедиться в том, что программа правильно идентифицировала внесённые нами в список хосты. Для этого наберём в терминале:
$ ansible-inventory --list -y
Вывод команды представлен ниже.
all:
children:
servers:
hosts:
server1:
ansible_host: 201.0.111.101
ansible_python_interpreter: /usr/bin/python3
ansible_user: alexandr75001
server2:
ansible_host: 201.0.111.102
ansible_python_interpreter: /usr/bin/python3
ansible_user: alexandr75001
server3:
ansible_host: 201.0.111.103
ansible_python_interpreter: /usr/bin/python3
ansible_user: alexandr75001
Можно убедиться, что все хосты идентифицированы верно. Для каждого из них правильно указаны IP-адреса, имя пользователя и назначенный интерпретатор языка Python.
Настройка файла конфигурации ansible.cfg
Откроем файл с помощью редактора nano и вставим в него приведённый ниже код:
$ sudo nano /etc/ansible/ansible.cfg
Один из возможных вариантов настройки конфигурационных параметров:
[defaults]
interpreter_python = auto_silent
verbosity = 1
ANSIBLE_PIPELINING = True
retry_files_enabled = False
system_warnings = True
command_warnings = False
display_args_to_stdout = True
display_skipped_hosts = True
[ssh_connection]
ssh_args = -C -o ControlMaster=no -o ControlPersist=60s -o ConnectTimeout=10
retries = 1
sftp_batch_mode = True
transfer_method = sftp
[diff]
always = True
После вставки кода файл конфигурации будет иметь вид, приведённый выше. Сохраним внесённые изменения и выйдем из редактора.
Тестирование работы системы
Тестирование системы сводится к пингованию хостов из списка Inventory с помощью встроенного в Ansible модуля ping. При этом параметры его запуска могут отличаться в зависимости от ситуации.
Протестируем нашу систему с помощью следующей команды:
$ ansible all -m ping
Вывод команды:
server2 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Unable to negotiate with 201.0.111.102 port 22: no matching host key type found. Their offer: ssh-rsa",
"unreachable": true
}
server1 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 201.0.111.101 port 22: Connection timed out",
"unreachable": true
}
server3 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 201.0.111.103 port 22: Connection timed out",
"unreachable": true
}
На основе полученных результатов сделаем окончательные выводы. Для каждого из трёх хостов выдаются примерно одинаковые сообщения о недоступности хоста или ключа. И это нормально, поскольку все эти машины действительно недоступны в сети, ведь мы их использовали исключительно для демонстративных целей. Однако тот факт, что пингование указанных в списке машин было произведено, говорит о том, что все настройки программы были выполнены правильно, и она полностью готова для работы с реальными машинами.
В случае же полной доступности, вывод команды для каждой из машин имел бы следующий вид:
server | SUCCESS => {
"changed": false,
"ping": "pong"
}
Ключевое слово здесь – SUCCESS, то есть полная готовность хоста к работе.