В предыдущей публикации я рассказывал о файлах инвентаризации Ansible. Теперь вооружившись предыдущими знаниями мы с вами можем перейти к следующей теме – Командный интерфейс Ansible. В англоязычной литературе его еще часто называют ad-hoc. У него тоже есть свои сценарии применения. Например, когда мы с вами тестировали файлы инвентаризации то сами того не подозревая использовали именно командный интерфейс.
Командный интерфейс Ansible
Зачем вообще нужен командный интерфейс Ansible? По большей части для тестирования/отладки и выполнения каких разовых единичных задач. Например, посмотреть имени хостов из группы, время или информацию об IP-адресах.
В последующих примерах я буду использовать файл инвентаризации из примера №3 моей предыдущей публикации.
В своем самом простом варианте пример команды Ansible выглядит следующим образом:
ansible all -i inv.ini -a "date"
roman@ansible:~$ ansible all -i inv.ini -a "date"
tst1 | CHANGED | rc=0 >>
Wed Jun 28 02:39:02 PM UTC 2023
tst2 | CHANGED | rc=0 >>
Wed Jun 28 02:39:02 PM UTC 2023
roman@ansible:~$
Здесь:
- ansible – это имя утилиты командного интерфейса Ansible.
- all – имя группы, для которой необходимо выполнить действие.
- -i – имя файла инвентаризации.
- -a – передача аргументов модулю. Если модуль не указан (параметр -m), то аргументы будут переданы модулю shell. Я передал команду отображения текущей даты и времени.
Аналогично вы можете выполнить любую другую команду:
ansible all -i inv.ini -a "free -m"
roman@ansible:~$ ansible all -i inv.ini -a "free -m"
tst1 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 3877 2277 455 49 1145 1265
Swap: 3890 0 3890
tst2 | CHANGED | rc=0 >>
total used free shared buff/cache available
Mem: 3877 325 3223 1 328 3333
Swap: 3890 0 3890
roman@ansible:~$
У Ansible довольно большой набор модулей. В командном интерфейсе вы можете использовать любой нужный вам модуль. Давайте, например, установим curl на все сервера группы front. Для этого нам нужно использовать модуль apt. В качестве параметров модулю необходимо передать имя пакета (параметр name) и состояние (state=present), чтобы Ansible убедился в том, что модуль присутствует в системе.
ansible front -i inv.ini -m apt -a "name=curl state=present"
roman@ansible:~$ ansible front -i inv.ini -m apt -a "name=curl state=present"
tst1 | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"msg": "'/usr/bin/apt-mark manual curl' failed: E: Could not create temporary file for /var/lib/apt/extended_states - mkstemp (13: Permission denied)\nE: Failed to write temporary StateFile /var/lib/apt/extended_states\n",
"rc": 100,
"stderr": "E: Could not create temporary file for /var/lib/apt/extended_states - mkstemp (13: Permission denied)\nE: Failed to write temporary StateFile /var/lib/apt/extended_states\n",
"stderr_lines": [
"E: Could not create temporary file for /var/lib/apt/extended_states - mkstemp (13: Permission denied)",
"E: Failed to write temporary StateFile /var/lib/apt/extended_states"
],
"stdout": "",
"stdout_lines": []
}
Как любит уведомлять один из браузеров – “Опаньки… Что-то пошло не так.”. Хотя из описания ошибки уже должна быть понятна причина – у учетной записи нет достаточных привилегий. Давайте повысим привилегии через sudo и повторим попытку. Для запроса выполнения команды через sudo необходимо указать параметр -b:
ansible front -i inv.ini -m apt -a "name=curl state=present" -b
roman@ansible:~$ ansible front -i inv.ini -m apt -a "name=curl state=present" -b
tst1 | FAILED! => {
"msg": "Missing sudo password"
}
roman@ansible:~$
Снова что-то пошло не так. Хотя уже определенно мы с вами сделали шаг вперед. Судя по всему необходимо явно указать пароль при использовании sudo. Для этого есть отдельный параметр -K. Добавим его:
ansible front -i inv.ini -m apt -a "name=curl state=present" -b -K
roman@ansible:~$ ansible front -i inv.ini -m apt -a "name=curl state=present" -b -K
BECOME password:
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"cache_update_time": 1687965135,
"cache_updated": false,
"changed": false
}
roman@ansible:~$
Теперь все получилось. Обратите внимание вот на эту строчку:
"changed": false
Это значит, что никаких изменений не было внесено в конфигурацию сервера. На сервере уже была установлена утилита curl.
Какие есть альтернативы интерактивному запросу пароля для sudo? Из наиболее распространенных и безопасных вариантов – использовать Ansible Vault.
Примеры использования командного интерфейса
Теперь я бы хотел показать вам немного примеров того, как можно использовать командный интерфейс Ansible на практике. Безусловно, сценариев его применения гораздо и гораздо больше, чем те несколько примеров, которые я приведу ниже.
В примерах ниже я буду использовать вот этот файл инвентаризации.
Пример 1. Выполнение команды в shell
Команда может быть любая. Например, давайте проверим сколько у нас свободного места на серверах. Модуль shell используется по умолчанию. Дополнительно передавать название модуля через параметр -m нет необходимости. Достаточно только передать параметры модулю через -a:
ansible all -i inv.ini -a "df -h"
roman@ansible:~$ ansible all -i inv.ini -a "df -h"
tst1 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.6M 387M 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 57G 14G 41G 25% /
tmpfs 1.9G 152K 1.9G 1% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 130M 1.7G 8% /boot
tmpfs 388M 4.0K 388M 1% /run/user/1000
tst2 | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
tmpfs 388M 1.3M 387M 1% /run
/dev/mapper/ubuntu--vg-ubuntu--lv 57G 6.8G 48G 13% /
tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/sda2 2.0G 130M 1.7G 8% /boot
tmpfs 388M 4.0K 388M 1% /run/user/1000
roman@ansible:~$ ansible
Пример 2. Установка приложения
Для установки приложения в большинстве случаев используются два модуля – apt и yum. Для Debian и CentOS подобных систем, соответственно.
Например, установим nginx на сервер frontend. В процессе установки мы запросим дополнительные привилегии через sudo (параметр -b) и интерактивно укажем пароль для sudo (параметр -K):
ansible front -i inv.ini -m apt -a "name=nginx state=present" -b -K
roman@ansible:~$ ansible front -i inv.ini -m apt -a "name=nginx state=present" -b -K
BECOME password:
tst1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"cache_update_time": 1687965135,
"cache_updated": false,
"changed": true,
"stderr": "",
"stderr_lines": [],
<....>
"NEEDRESTART-KCUR: 5.15.0-75-generic",
"NEEDRESTART-KEXP: 5.15.0-75-generic",
"NEEDRESTART-KSTA: 1"
]
}
Обратите внимание вот на эту строчку:
"changed": true
Это значит, что изменения были применены и пакет nginx установлен.
Пример 3. Запуск сервиса
В примере 2 мы с вами установили пакет nginx, но теперь давайте убедимся, что сервис nginx запущен и настроен его автоматический запуск при старте системы.
Для этого нам потребуется модуль service:
ansible front -i inv.ini -m service -a "name=nginx state=started enabled=true" -b -K
roman@ansible:~$ ansible front -i inv.ini -m service -a "name=nginx state=started enabled=true" -b -K
BECOME password:
tst1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"enabled": true,
"name": "nginx",
"state": "started",
"status": {
"ActiveEnterTimestamp": "Thu 2023-06-29 16:02:52 UTC",
"ActiveEnterTimestampMonotonic": "2576195565",
<.....>
"WatchdogSignal": "6",
"WatchdogTimestamp": "n/a",
"WatchdogTimestampMonotonic": "0",
"WatchdogUSec": "0"
}
}
Нас не интересует весь рулон вывода на консоль. Нас интересует только вот эти строчки:
"enabled": true,
"name": "nginx",
"state": "started"
т.е. сервис запущен и настроен его автоматический запуск при старте системы.
Пример 4. Создание пользователя
Командный интерфейс Ansible не ограничивается только выполнение shell команд и управления сервисами. Вы также можете, например, создавать пользователей. Предварительно нужно установить модуль passlib для python:
python3 -m pip install passlib
Вот теперь мы можем создать пользователя:
ansible front -b -K -m user -a "name=usr createhome=yes password={{ 'Qwerty123' | password_hash('sha512') }}"
roman@ansible:~$ ansible front -b -K -m user -a "name=usr createhome=yes password={{ 'Qwerty123' | password_hash('sha512') }}"
BECOME password:
tst1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"append": false,
"changed": true,
"comment": "",
"group": 1001,
"home": "/home/usr",
"move_home": false,
"name": "usr",
"password": "NOT_LOGGING_PASSWORD",
"shell": "/bin/sh",
"state": "present",
"uid": 1001
}
Пожалуй, большая часть команды вам уже должна быыть понятна. Кроме параметра указания пароля.
password={{ 'Qwerty123' | password_hash('sha512') }}
Модуль user может сразу задать пароль для пользователя. Но пароль не может быть передан открытым текстом – необходимо передать хэш пароля. Все то, что указано вот в этой конструкции со скобками {{ … }} является ни чем иным, как шаблоном jinja2. О шаблонах мы с вами поговрим в следующих публикациях. Пока достаточно знать того, что содержимое шаблона заменяется определенным текстом. В нашем случе берется текст пароля (Qwerty123) и берется хэш этого пароля. Именно хэш и будет передан параметру password.
Пример 5. Установка обновлений на сервер
Вы также можете запускать обновления в фоновом режиме через командный интерфейс Ansible. Примерно вот так:
ansible back -i inv.ini -b -K -B 3600 -P 0 -a "apt upgrade -y"
roman@ansible:~$ ansible back -i inv.ini -b -K -B 3600 -P 0 -a "apt upgrade -y"
BECOME password:
tst2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"ansible_job_id": "j95838861652.2020",
"changed": true,
"finished": 0,
"results_file": "/root/.ansible_async/j95838861652.2020",
"started": 1
}
roman@ansible:~$
Я приведу дополнительные пояснения только по новым параметрам:
- -B – максимальное время в секундах, которое фоновому заданию можем выполняться.
- – P – время в секундах, через которое происходит повторный опрос задания со стороны сервера Ansible.
Запросить статус задания можно через модуль async_status. В качестве параметра необходимо передать идентификатор задания:
ansible back -i inv.ini -b -K -m async_status -a "jid=j95838861652.2020"
roman@ansible:~$ ansible back -i inv.ini -b -K -m async_status -a "jid=j95838861652.2020"
BECOME password:
tst2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"ansible_job_id": "j95838861652.2020",
"changed": true,
"cmd": [
"apt",
"upgrade",
"-y"
],
"delta": "0:00:53.638043",
"end": "2023-06-29 16:56:59.430687",
"finished": 1,
"msg": "",
"rc": 0,
<....>
Это будет очень длинный вывод, но в нем нас интересуют следующие строки:
tst2 | CHANGED => {
"changed": true,
"finished": 1,
"rc": 0,
Это значит, что изменения были внесены успешно и фоновое задание завершилось без ошибок.
На этом я завершаю публикацию про командный интерфейс Ansible. В следующей статье мы поговорим про Ansible playbook.