Я уже рассказывал о том, как установить Ansible. Надеюсь, что теперь получится немного уделить времени для того, чтобы подготовить небольшой вводный курс по самым базовым основам Ansible. Подготовить развернутый и всеобъемлющий курс – это большой труд, который займет много времени. Да и литературы и материалов на просторах интернета предостаточно. Поэтому я не ставлю целью этого цикла статей осветить все тонкости Ansible. А вот небольшое пособие для начинающих – вполне себе должно получится. Что-то вроде экспресс курса. Я бы хотел начать этот курс с того, что расскажу о том, что такое файлы инвентаризации Ansible и для чего они нужны.
Если вас интересует более развернутый вариант по теме инвентаризации Ansible, то вы можете обратиться к официальному руководству.
Зачем нужны файлы инвентаризации
Ansible использует SSH подключение для доступа к тем хостам, на которых он должен выполнить какие-то настройки. Но откуда Ansible знает о том, на каких серверах он должен выполнить настройки? Какие DNS-имена или IP-адреса у этих серверов? Для этого используются файлы инвентаризации. В них вы определяете группы серверов и состав этих групп. При запуске команды или playbook вы указываете где искать файл инвентаризации и для какой группы или хоста необходимо выполнить настройку.
Пример самого базового файла инвентаризации Ansible:
[front]
tst1 ansible_host=10.10.10.106 ansible_user=roman
В этом файле определена группа – front. Внутри этой группы есть один сервер – tst1. Это имя условное – вы можете указать любое. Далее следует два параметра, в которых мы передаем адрес и имя для подключения: ansible_host и ansible_user, соответственно.
При запуске модуля Ansible вы можете передать путь (полный или относительный) до файла с инвентаризацией через параметр -i:
ansible front -i servers.ini -m ping -k
roman@ansible:~/ansible/01-inventory$ ansible front -i servers.ini -m ping -k
SSH password:
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Вы можете задать системный инвентаризационный файл – /etc/ansible/hosts. Если этот файл существует, то параметр -i можно опустить – Ansible будет использовать файл по умолчанию. Переместим содержимое нашего инвентаризационного файла в файл /etc/ansible/hosts. Проверим его содержимое:
cat /etc/ansible/hosts
roman@ansible:~$ cat /etc/ansible/hosts
[front]
tst1 ansible_host=10.10.10.106 ansible_user=roman
roman@ansible:~$
И теперь попробуем повторно запустить модуль ping без параметра -i:
ansible front -m ping -k
roman@ansible:~$ ansible front -m ping -k
SSH password:
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Как видно из скриншота выше – результат идентичен.
Небольшой тюнинг подключений
Всякий раз при выполнении модулей Ansible в примерах выше мы указывали дополнительный ключ -k. Этот ключ указывает Ansible на то, что нужно интерактивно запрашивать пароль в процессе подключения. Мы можем с вами подключаться к серверам и без пароля – по открытому ключу SSH. Достаточно просто его скопировать на тот сервер, куда мы с вами выполняем подключение.
Однако, предварительно нужно сгенерировать эти ключи. Как вообще понять – есть ли у вас эти ключи или их нужно сгенерировать? Попробуйте выполнить вот такую команду:
ls ~/.ssh
roman@ansible:~$ ls ~/.ssh
authorized_keys known_hosts
roman@ansible:~$
При наличии ключей там должны быть файлы id_rsa и id_rsa.pub. Но имена файлов могут отличаться. Если вывод команды похож на вывод выше, то ключей у вас нет. Их нужно сгенерировать:
ssh-keygen -t rsa
roman@ansible:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/roman/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/roman/.ssh/id_rsa
Your public key has been saved in /home/roman/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:EY0jtKfES29slrAsbpmRc8dtbSUHZtC3TUMyghnh19k roman@ansible
The key's randomart image is:
+---[RSA 3072]----+
| .. .=*++o.. |
| ...++.o+.*..|
| *.oo ..+oE.|
| = X +.. +. .|
| = * S o o |
| . B = . . |
| = |
| . |
| |
+----[SHA256]-----+
Проверим вывод теперь:
ls ~/.ssh
roman@ansible:~$ ls ~/.ssh
authorized_keys id_rsa id_rsa.pub known_hosts known_hosts.old
roman@ansible:~$
У меня есть два сервера, конфигурацией которых я планирую управлять. Скопирую на оба этих сервера открытый ключ сервера с Ansible.
Скопирую открытый ключ на первый сервер:
ssh-copy-id roman@10.10.10.106
roman@ansible:~$ ssh-copy-id roman@10.10.10.106
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/roman/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
roman@10.10.10.106's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'roman@10.10.10.106'"
and check to make sure that only the key(s) you wanted were added.
roman@ansible:~$
Затем по аналогии скопирую ключ на второй сервер.
Как проверить, что подключение по SSH ключам работает? Достаточно выполнить обычно подключение по SSH. Например:
ssh roman@10.10.10.111
Вы должны сразу подключиться на сервер 10.10.10.111. Без дополнительного запроса логина и пароля.
А для чего мы все это делали? Чтобы мы могли запускать модули Ansible без ручного ввода пароля:
ansible front -m ping
roman@ansible:~$ ansible front -m ping
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Выполнять процедуру копирование ключей SSH или нет – решать вам. Но, как правило это более удобный способ подключения, но и еще гораздо более безопасный метод, чем подключение через комбинацию логина и пароля.
Два типа файлов инвентаризации
Вернемся к нашим файлам инвентаризации. Существует два формата (или два типа) при работе с файлами инвентаризации Ansible – формат yml и формат ini. В примерах выше я использовал ini формат.
Для наглядности ниже я приведу пример одного и того же файла инвентаризации, но в разных форматах. Начнем с уже знакомого нам ini формата:
nano inv.ini
Добавим следующее содержимое в файл:
[front]
tst1 ansible_host=10.10.10.106 ansible_user=roman
[back]
tst2 ansible_host=10.10.10.111 ansible_user=roman
В инвентаризационном файле выше мы с вами определили две группы – front и back. В каждой группе мы добавили по одному серверу.
Теперь давайте создадим аналогичный файл инвентаризации в ini формате:
nano inv.ym
Содержимое файла:
front:
hosts:
tst1:
ansible_host: 10.10.10.106
ansible_user: roman
back:
hosts:
tst2:
ansible_host: 10.10.10.111
ansible_user: roman
Хочу отметить, что мы не задавали группу all в обоих файлах, но она создается не явно. И включает в себя все группы из файла инвентаризации.
Попробуем запустить хорошо известный нам модуль ping для наших файлов инвентаризации. Начнем с yml файла:
ansible all -i inv.yml -m ping
roman@ansible:~$ ansible all -i inv.yml -m ping
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Как я уже говорил, мы с вами не задавали группу all, но она создается не явно и включает в себя все группы из инвентаризационного файла.
Теперь попробуем применить ini файл:
ansible back -i inv.ini -m ping
roman@ansible:~$ ansible back -i inv.ini -m ping
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
В примере выше я явно указал группу back.
Резюмируем – файлы инвентаризации Ansible поддерживает два формата – ini и yml. Какой из них использовать – сугубо дело предпочтений и привычки. Как по мне, так ini файлы немного проще. По крайней мере лично мне. Поэтому далее в этом цикле статей я буду использовать ini формат.
Файлы инвентаризации Ansible – примеры
Мы с вами дошли до того, что узнали для чего нужны файлы инвентаризации и какие они поддерживают форматы. Теперь предлагаю немного поработать с примерами файлов инвентаризации.
Полный перечень параметров, которые можно использовать для хоста приведен в соответствующем разделе официальной документации.
Пример 1. Определение нескольких групп хостов
По сути мы с вами уже использовали этот пример выше. Я только хотел добавить тот факт, что один и тот же хост может находится сразу в нескольких группах.
Пример:
[front]
tst1 ansible_host=10.10.10.106 ansible_user=roman
[back]
tst2 ansible_host=10.10.10.111 ansible_user=roman
[linux]
tst1 ansible_host=10.10.10.106 ansible_user=roman
tst2 ansible_host=10.10.10.111 ansible_user=roman
В примере выше создано три группы хостов – front, back и linux. Причем группа linux включает в себя сразу оба хоста – tst1 и tst2.
Результат выполнения модуля ping для всех хостов:
ansible all -i inv.yml -m ping
roman@ansible:~$ ansible all -i inv.ini -m ping
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Пример 2. Использование дочерних групп
Если при использовании файла инвентаризации из примера 1 вы обратили внимание на, по сути, дублирование текста для группы linux, то вы совершенно правы. Для таких случае в файле инвентаризации Ansible можно использовать дочерние группы.
Вот так:
[front]
tst1 ansible_host=10.10.10.106 ansible_user=roman
[back]
tst2 ansible_host=10.10.10.111 ansible_user=roman
[linux:children]
front
back
Результат запуска модуля ping для группы хостов linux:
ansible linux -i inv.ini -m ping
roman@ansible:~$ ansible linux -i inv.ini -m ping
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Пример 3. Использование переменных
Если еще внимательнее присмотреться к примеру 1 и примеру 2, то можно заметить, что для подключения к обоим серверам используется один и тот же пользователь – roman. Чтобы сделать файл инвентаризации более читаемым давайте вынесем эту часть конфигурации в отдельную сущность. Ansible использует для этого переменные.
Переменные можно определить как для группы хостов, так и для всего файла инвентаризации. Я определю переменную с именем пользователя для всех хостов. Пример такого файла инвентаризации приведен ниже:
[front]
tst1 ansible_host=10.10.10.106
[back]
tst2 ansible_host=10.10.10.111
[linux:children]
front
back
[all:vars]
ansible_user=roman
Результат работы модуля ping для всех хостов файла инвентаризации:
ansible all -i inv.ini -m ping
roman@ansible:~$ ansible all -i inv.ini -m ping
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
Пример 4. Использование переменных для групп хостов
По аналогии использования переменных для всех хостов вы можете использовать переменные и для отдельных групп хостов.
Практической пользы от примера ниже нет, но он показывает, как можно использовать переменные для отдельных групп хостов:
[front]
tst1
[front:vars]
ansible_host=10.10.10.106
[back]
tst2
[back:vars]
ansible_host=10.10.10.111
[linux:children]
front
back
[all:vars]
ansible_user=roman
Как можно увидеть из примера ниже – результат вывода все того же модуля ping не изменился:
ansible all -i inv.ini -m ping
roman@ansible:~$ ansible all -i inv.ini -m ping
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
tst2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
roman@ansible:~$
На этом примере я завершу статью про файлы инвентаризации Ansible. Еще больше полезных примеров можно найти в официальной документации. Я же ставил своей целью только дать общее представление о том, для чего нужны файлы инвентаризации и показать несколько базовых примеров их использования.