В чем разница между модулями `shell` и `command` в Ansible?

«В чем разница между модулями `shell` и `command` в Ansible?» — вопрос из категории Ansible, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оба модуля выполняют команды на целевых хостах, но принципиально различаются по способу исполнения и безопасности.

Модуль command выполняет команду напрямую, без оболочки (shell). Это означает:

  • Нет раскрытия переменных окружения ($PATH, $HOME).
  • Нет обработки shell-операторов: перенаправления (>, >>), пайпов (|), логических операторов (&&, ||), подстановки (*).
  • Более безопасно, так как исключает риски инъекций через shell-интерпретацию.

Модуль shell выполняет команду через оболочку хоста (по умолчанию /bin/sh). Он поддерживает все возможности shell.

Сравнение на примере:

- name: Попытка использовать перенаправление с command (НЕ СРАБОТАЕТ)
  ansible.builtin.command: echo "data" > /tmp/file.txt
  # Модуль command попытается найти программу с именем 'echo "data" > /tmp/file.txt' и завершится ошибкой.

- name: Использование shell для перенаправления (РАБОТАЕТ)
  ansible.builtin.shell: echo "data" > /tmp/file.txt
  # Команда будет выполнена через /bin/sh, который обработает оператор '>'.

- name: Безопасное использование command с модулем copy
  ansible.builtin.copy:
    content: "data"
    dest: /tmp/file.txt
  # Правильный идиоматичный способ в Ansible — использовать специализированный модуль.

Рекомендации по использованию (из практики):

  1. Всегда предпочитайте command, если команда простая и не требует shell. Это безопаснее и предсказуемее.
  2. Используйте shell только когда необходимы специфические возможности оболочки (пайпы, перенаправление, циклы в одной строке).
  3. Для сложных операций используйте специализированные модули Ansible (copy, lineinfile, template, systemd). Они идиоматичны, обеспечивают идемпотентность и дают лучшую обратную связь.
  4. При использовании shell явно задавайте исполняемую оболочку, если нужна конкретная (например, bash-специфичный синтаксис):
    - name: Run command with bash
      ansible.builtin.shell:
        cmd: echo "Home is $HOME"
        executable: /bin/bash