Знакомство с Ansible. Часть 1. Файлы инвентаризации Ansible

Я уже рассказывал о том, как установить 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. Еще больше полезных примеров можно найти в официальной документации. Я же ставил своей целью только дать общее представление о том, для чего нужны файлы инвентаризации и показать несколько базовых примеров их использования.

Добавить комментарий

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