Модуль shell в Ansible служит мостом между вашими плейбуками и интерфейсом командной строки (CLI) управляемых систем.
Он позволяет выполнять команды командной строки на удаленных объектах, упрощая выполнение ряда различных задач системного администрирования, управления конфигурацией и автоматизации.
В этой статье мы покажем:
- Работа модуля shell
- Примеры использования модуля shell
- Выполнение действий по результатам работы модуля shell
- Разница между модулем shell и командным модулем
- Почему не рекомендуется использовать модуль shell
Что такое модуль Shell?
По своей сути модуль shell – это строительный блок Ansible, предназначенный для выполнения команд в среде shell на удаленных узлах, будь то простые задачи, например проверка прав доступа к файлам, или сложные операции, например запуск пользовательских скриптов.
Модуль shell использует плагины подключения Ansible для установления безопасного соединения с целевыми машинами.
После подключения он запускает сеанс оболочки (обычно /bin/sh на Unix-подобных системах) и выполняет команду, которую вы указали в этой оболочке.
Затем модуль перехватывает вывод команды (stdout и stderr) и код возврата, делая эту информацию доступной для дальнейшей обработки в вашем плейбуке.
Параметры модуля оболочки Ansible
Модуль shell имеет множество различных параметров. Наиболее часто используемые из них следующие:
- cmd (или свободная форма): Основной параметр модуля, здесь вы указываете команду, которую хотите запустить.
- creates: Помогает обеспечить идемпотентность. Если указанный файл существует, команда не будет выполнена.
- chdir: Позволяет изменить рабочий каталог перед выполнением команды.
- executable (исполняемый): Если вам нужен определенный интерпретатор оболочки (например, /bin/bash), используйте этот параметр.
- removes: Параметр, обратный параметру create. Если указанный файл не существует, команда не будет выполнена.
Это лишь некоторые из доступных параметров, полный список которых приведен в документации Ansible.
Использование модуля shell: Практический пример
В этом примере мы создадим резервную копию каталога на удаленном хосте и скопируем в него содержимое /opt/myapp, а затем проверим завершение резервного копирования, выведя список содержимого резервного каталога.
Если резервное копирование прошло успешно, будет выведено сообщение, подтверждающее это.
---
- name: Create directory backup using shell module
hosts: all
become: true
tasks:
- name: Create backup directory
ansible.builtin.shell: |
mkdir -p /var/backups/myapp
- name: Copy files to backup directory
ansible.builtin.shell: |
cp -r /opt/myapp /var/backups/myapp
- name: Verify backup completion
ansible.builtin.shell: |
ls /var/backups/myapp
register: backup_result
- name: Display backup status
debug:
msg: "Backup completed successfully: {{ backup_result.stdout_lines }}"
when: backup_result.rc == 0
Выполнение нескольких команд оболочки
Хотя модуль shell предназначен для выполнения одной команды, вы можете создать цепочку из нескольких команд, используя многострочную команду или одну строку с операторами shell, или создать скрипт и выполнить его с помощью модуля shell.
---
- name: Run multiple commands
hosts: all
become: true
tasks:
- name: Execute multiple commands using shell module
ansible.builtin.shell: |
echo "Starting setup..."
mkdir -p /opt/myapp
touch /opt/myapp/config.yaml
echo "Setup complete."
Использование Changed_when и Failed_when в модуле Shell
Модуль Shell не возвращает статус changed.
Чтобы определить, когда команда не выполнилась или скрипт что-то изменил в системе, можно использовать инструкции changed_when и failed_when.
Инструкция changed_when позволяет определить, когда задача действительно вносит изменения в цель.
- name: Install dependencies via Composer.
ansible.builtin.shell: "/usr/local/bin/composer global require phpunit/phpunit --prefer-dist"
register: composer
changed_when: "'Nothing to install or update' not in composer.stdout"
Если модули php уже присутствуют на целевой машине, команда composer ничего не делает и просто возвращает сообщение.
Бывают случаи, когда некоторые ошибки допустимы.
Именно в таких случаях мы будем использовать инструкцию failed_when.
- name:
ansible.builtin.shell: "ls | grep wp-config.php"
register: thecommand
failed_when: thecommand.rc not in [0, 1]
Его также можно использовать при запуске плейбука, чтобы предотвратить аварийное завершение работы инструмента установки из-за нехватки ресурсов.
- name: Making sure the /tmp has more than 2gb
ansible.builtin.shell: "df -h /tmp|grep -v Filesystem|awk '{print $4}'|cut -d G -f1"
register: tmpspace
failed_when: "tmpspace.stdout|float < 2"
Модуль shell или command
В Ansible есть модуль command, который служит для той же цели – выполнения команд на объектах.
Даже если цель этих двух модулей идентична, есть и различия:
- Модуль shell Ansible выполняет команды непосредственно через оболочку целевых хостов. По умолчанию модуль shell использует sh для выполнения команд (можно определить другие оболочки с помощью опции executable). С помощью команды module команды не выполняются через оболочку.
- Модуль command не поддерживает переменные окружения, пайпы и такие операторы, как <, >, &, ;…
Поэтому безопаснее использовать модуль command, так как на них не могут повлиять переменные оболочки пользователя.
С другой стороны, поскольку операторы недоступны, вы должны обрабатывать значения в своем плейбуке с помощью фильтров Jinja.
Почему не рекомендуется использовать модуль shell
Хотя модуль shell является мощным и предоставляет вам гибкость в написании скриптов, однако, как правило, не рекомендуется использовать его, а использование специализированных модулей считается лучшей практикой.
Существует несколько причин, по которым не рекомендуется использовать модуль shell:
- Идемпотентность: Обеспечить идемпотентность (запуск одного и того же плейбука несколько раз без побочных эффектов) при использовании shell-скриптов довольно сложно.
- Удобство чтения и обслуживания: скрипты оболочки может быть сложнее читать, понимать и поддерживать по сравнению с использованием специальных модулей Ansible, и они не возвращают информацию о том, что изменилось или произошло.
- Труднее отлаживать: Отладка задачи проще и занимает меньше времени, чем длинная цепочка команд оболочки.
Однако есть сценарии, в которых использование модуля оболочки лучше, чем использование выделенного модуля, который использует слишком много предположений и в итоге оказывается сложнее в использовании, чем скрипты оболочки с аналогичными функциями.
Аналогичным образом, если для вашей конкретной задачи не существует специального модуля, гибкость скриптов оболочки может пригодиться.
Заключение
Модуль Shell в Ansible – мощный инструмент для выполнения команд командной оболочки на удаленных узлах, но он связан с рисками обслуживания.
Как правило, лучше использовать специальные модули Ansible, предназначенные для выполнения нужных вам задач, оставляя модуль shell для ситуаций, когда подходящего модуля не существует.
см. также:
- 🐧 Модуль Ansible Ping: Проверка доступности хоста
- 🐧 Управление службами с помощью модуля Ansible Service
- 📜 Ansible Security: Обеспечение безопасности инфраструктуры с помощью Ansible
- 🔐 Ansible SSH аутентификация и повышение привилегий
- 📜 Как использовать Ansible Lint для сканирования плейбуков