Безопасное ограничение Ansible playbooks на одной машине?

Я использую Ansible для некоторых простых задач управления пользователями с небольшой группой компьютеров. В настоящее время у меня есть мои плейеры, настроенные на hosts: all, а файл моих хостов - это всего лишь одна группа со всеми перечисленными машинами:

# file: hosts
[office]
imac-1.local
imac-2.local
imac-3.local

Я обнаружил, что мне часто приходится настраивать таргетинг на одну машину. Команда ansible-playbook может ограничивать такие игры:

ansible-playbook --limit imac-2.local user.yml

Но это кажется хрупким, особенно для потенциально разрушительной пьесы. Оставляя флаг limit означает, что playbook будет работать везде. Поскольку эти инструменты используются только время от времени, кажется, стоит предпринять шаги для надежного воспроизведения, чтобы мы не случайно запустили несколько месяцев.

Есть ли лучшая практика для ограничения запуска плей-листов на одну машину? В идеале игровые автоматы должны быть безвредными, если некоторые важные детали не учитываются.

Ответ 1

Оказывается, можно ввести имя хоста непосредственно в playbook, поэтому запуск playbook с hosts: imac-2.local будет работать нормально. Но это вроде неуклюже.

Лучшим решением может быть определение хостов playbook с использованием переменной, а затем передача определенного адреса узла через --extra-vars:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

Запуск пьесы:

ansible-playbook user.yml --extra-vars "target=imac-2.local"

Если {{ target }} не задано, программа воспроизведения ничего не делает. При необходимости может быть передана группа из файла hosts. В целом, это похоже на гораздо более безопасный способ создания потенциально разрушительной пьесы.

Playbook, ориентированный на один хост:

$ ansible-playbook user.yml --extra-vars "target=imac-2.local" --list-hosts

playbook: user.yml

  play #1 (imac-2.local): host count=1
    imac-2.local

Playbook с группой хостов:

$ ansible-playbook user.yml --extra-vars "target=office" --list-hosts

playbook: user.yml

  play #1 (office): host count=3
    imac-1.local
    imac-2.local
    imac-3.local

Забыть определить хосты безопасно!

$ ansible-playbook user.yml --list-hosts

playbook: user.yml

  play #1 ({{target}}): host count=0

Ответ 2

Там также милый маленький трюк, который позволяет указать один хост в командной строке (или несколько хостов, я думаю), без промежуточного инвентаря:

ansible-playbook -i "imac1-local," user.yml

Обратите внимание на запятую (,) в конце; это означает, что это список, а не файл.

Теперь это не защитит вас, если вы случайно передадите настоящий файл инвентаризации, поэтому это может быть не очень хорошее решение этой конкретной проблемы. Но это удобный трюк, чтобы знать!

Ответ 3

Этот подход будет завершен, если будет предоставлено более одного хоста, проверив переменную play_hosts. fail module используется для выхода, если условие единственного хоста не выполнено. В приведенных ниже примерах используется файл hosts с двумя хостами alice и bob.

user.yml(playbook)

---
- hosts: all
  tasks:
    - name: Check for single host
      fail: msg="Single host check failed."
      when: "{{ play_hosts|length }} != 1"
    - debug: msg='I got executed!'

Запустить playbook без фильтров хоста

$ ansible-playbook user.yml
PLAY [all] ****************************************************************
TASK: [Check for single host] *********************************************
failed: [alice] => {"failed": true}
msg: Single host check failed.
failed: [bob] => {"failed": true}
msg: Single host check failed.
FATAL: all hosts have already failed -- aborting

Запустить playbook на одном хосте

$ ansible-playbook user.yml --limit=alice

PLAY [all] ****************************************************************

TASK: [Check for single host] *********************************************
skipping: [alice]

TASK: [debug msg='I got executed!'] ***************************************
ok: [alice] => {
    "msg": "I got executed!"
}

Ответ 4

Там ИМХО более удобный способ. Вы действительно можете в интерактивном режиме запросить у пользователя машину (-ы), к которой он хочет применить playbook, благодаря vars_prompt:

---

- hosts: "{{ setupHosts }}"
  vars_prompt:
    - name: "setupHosts"
      prompt: "Which hosts would you like to setup?"
      private: no
  tasks:
    […]

Ответ 5

Чтобы расширить ответ на вопрос о joemailer, если вы хотите, чтобы способность сопоставления шаблонов соответствовала любому подмножеству удаленных компьютеров (как это делает команда ansible), но все же хотите, чтобы было очень сложно случайно запустить playbook на всех машинах это то, что я придумал:

В той же самой пьесе, что и в другом ответе:

# file: user.yml  (playbook)
---
- hosts: '{{ target }}'
  user: ...

Пусть имеют следующие хосты:

imac-10.local
imac-11.local
imac-22.local

Теперь, чтобы запустить команду на всех устройствах, вы должны объяснить, чтобы целевая переменная была "все"

ansible-playbook user.yml --extra-vars "target=all"

И чтобы ограничить его до определенного шаблона, вы можете установить target=pattern_here

или, альтернативно, вы можете оставить target=all и добавить аргумент --limit, например:

--limit imac-1*

т.   ansible-playbook user.yml --extra-vars "target=all" --limit imac-1* --list-hosts

что приводит к:

playbook: user.yml

  play #1 (office): host count=2
    imac-10.local
    imac-11.local

Ответ 6

Пользователи AWS, использующие сценарий внешней инвентаризации EC2, могут просто фильтровать по идентификатору экземпляра:

ansible-playbook sample-playbook.yml --limit i-c98d5a71 --list-hosts

Это работает, потому что скрипт инвентаризации создает группы по умолчанию.

Ответ 7

Я действительно не понимаю, как все ответы настолько сложны, способ сделать это просто:

ansible-playbook user.yml -i hosts/hosts --limit imac-2.local --check

Режим check позволяет работать в режиме пробного запуска без каких-либо изменений.

Ответ 8

Начиная с версии 1.7, ansible имеет опцию run_once. Раздел также содержит некоторые обсуждения различных других методов.

Ответ 9

У нас есть несколько общих игровых автоматов, которые можно использовать большим количеством команд. У нас также есть файлы инвентаризации, специфичные для среды, которые содержат несколько деклараций групп.

Чтобы заставить кого-то вызвать плейер, чтобы указать группу для запуска, мы запустим фиктивную запись в верхней части учебника:

[ansible-dummy-group]
dummy-server

Затем мы включаем следующую проверку в качестве первого шага в общий плей-лист:

- hosts: all
  gather_facts: False
  run_once: true
  tasks:
  - fail:
      msg: "Please specify a group to run this playbook against"
    when: '"dummy-server" in ansible_play_batch'

Если фиктивный сервер отображается в списке хостов, эта программа воспроизведения будет запускаться против (ansible_play_batch), тогда вызывающий не указал группу, и выполнение программы воспроизведения потерпит неудачу.

Ответ 10

Здесь показано, как запустить playbooks на целевом сервере.

Это немного сложнее, если вы хотите использовать локальное соединение. Но это должно быть нормально, если вы используете переменную для параметра hosts и в файле hosts создайте специальную запись для localhost.

Во всех плейбуках линия hosts: установлена в:

- hosts: "{{ target | default('no_hosts')}}"

В файле инвентаризации хостов добавьте запись для localhost, которая устанавливает соединение как локальное:

[localhost]
127.0.0.1  ansible_connection=local

Затем в командной строке выполните команды, явно задающие цель - например:

$ ansible-playbook --extra-vars "target=localhost" test.yml

Это также будет работать при использовании ansible-pull:

$ ansible-pull -U <git-repo-here> -d ~/ansible --extra-vars "target=localhost" test.yml

Если вы забудете установить переменную в командной строке, команда выдаст ошибку (если вы не создали группу хостов с именем no_hosts!) С предупреждением:

skipping: no hosts matched

И, как уже упоминалось выше, вы можете настроить таргетинг на одну машину (если она есть в вашем файле hosts) с помощью:

$ ansible-playbook --extra-vars "target=server.domain" test.yml

или группа с чем-то вроде:

$ ansible-playbook --extra-vars "target=web-servers" test.yml

Ответ 11

У меня есть оболочка script, называемая условием, заставляет вас выбирать цель, поэтому мне не нужно ее обрабатывать в другом месте.

Для любопытных я использую env vars для параметров, которые использует мой vagrantfile (добавление соответствующего аргумента arg для облачных систем), и пусть остальные аргументы args проходят. Когда я создаю и предоставляю более 10 серверов одновременно, я включаю автоматический повтор попыток на неудавшихся серверах (при условии достижения прогресса - я обнаружил при создании 100 или около того серверов за раз, когда некоторые из них в первый раз не срабатывали).

echo 'Usage: [VAR=value] bin/provision [options] dev|all|TARGET|vagrant'
echo '  bootstrap - Bootstrap servers ssh port and initial security provisioning'
echo '  dev - Provision localhost for development and control'
echo '  TARGET - specify specific host or group of hosts'
echo '  all - provision all servers'
echo '  vagrant - Provision local vagrant machine (environment vars only)'
echo
echo 'Environment VARS'
echo '  BOOTSTRAP - use cloud providers default user settings if set'
echo '  TAGS - if TAGS env variable is set, then only tasks with these tags are run'
echo '  SKIP_TAGS - only run plays and tasks whose tags do not match these values'
echo '  START_AT_TASK - start the playbook at the task matching this name'
echo
ansible-playbook --help | sed -e '1d
    s#=/etc/ansible/hosts# set by bin/provision argument#
    /-k/s/$/ (use for fresh systems)/
    /--tags/s/$/ (use TAGS var instead)/
    /--skip-tags/s/$/ (use SKIP_TAGS var instead)/
    /--start-at-task/s/$/ (use START_AT_TASK var instead)/
'