С чего начать Первые шаги трек · 15 ступеней
Linux Labs

Ansible: инвентарь, модули и разовые команды

8 мин Ansible 2.16

Система настройки серверов по SSH: по инвентарю и плейбукам приводит машины к описанному состоянию без агента на них.

Шпаргалка

8 команд Версия для печати
  • ansible -i hosts.ini all -m ping связь со всеми машинами
  • ansible -i hosts.ini all --list-hosts кого затронет команда
  • ansible-inventory -i hosts.ini --graph группы и машины деревом
  • ansible -i hosts.ini web -m command -a 'uptime' команда на машинах
  • ansible -i hosts.ini web -m copy -a 'src=a.conf dest=/tmp/a.conf'
  • ansible -i hosts.ini web -b -m service -a 'name=nginx state=started'
  • ansible -i hosts.ini all -m ping -o ответ одной строкой
  • ansible-playbook -i hosts.ini site.yml плейбук

Обзор

Ansible настраивает машины без агента: подключается по SSH, копирует туда модуль — небольшую программу на Python, — запускает его и забирает ответ. Список машин — инвентарь. Модуль сначала смотрит, что на машине, и меняет только разницу, поэтому повторный запуск ничего не трогает — идемпотентность.

На учебной машине — ansible [core 2.16.3] и пакет ansible 9.2 со 103 коллекциями модулей; ansible --version пишет config file = None: настроек по умолчанию нет, инвентарь передают ключом -i. Разовые команды — ansible, плеи из файла — ansible-playbook.

Рецепты

4

Инвентарь

ini
[web]
node2

[db]
db1 ansible_host=10.0.0.21 ansible_user=deploy

[local]
localhost ansible_connection=local

[web:vars]
ansible_user=student
Что Где Значит
имя машины node2 так машина называется в выводе; по нему же Ansible подключается, если нет ansible_host
ansible_host строка машины адрес или имя для SSH
ansible_user строка машины или [группа:vars] под кем входить; без него — под твоим именем
ansible_connection=local строка машины работать на этой машине без SSH
[web] заголовок группа; all — все машины инвентаря
text
student@node1:~/inv$ ansible-inventory -i hosts.ini --graph
@all:
  |--@ungrouped:
  |--@web:
  |  |--node2
  |--@local:
  |  |--localhost
student@node1:~/inv$ ansible -i hosts.ini all --list-hosts
  hosts (2):
    node2
    localhost

Без -i Ansible ищет /etc/ansible/hosts; на учебной машине его нет, и команда видит только localhost. Ошибки инвентаря в плейбуке — ansible-playbook.

Разовые команды

ansible <машины> -m <модуль> -a '<параметры>' — один модуль на всех машинах группы. Ответ — по машине:

text
student@node1:~/inv$ ansible -i hosts.ini web -m copy \
> -a 'content="hello\n" dest=/tmp/hello.txt'
node2 | CHANGED => {
    "changed": true,
    "dest": "/tmp/hello.txt",
    ...
}

Повтор той же команды — node2 | SUCCESS и "changed": false: файл уже такой. Модуль command (он же по умолчанию, без -m) не знает, что делает команда, и всегда пишет CHANGED:

text
student@node1:~/inv$ ansible -i hosts.ini web -m command -a 'id -un'
node2 | CHANGED | rc=0 >>
student
В выводе Значит
SUCCESS модуль отработал, менять было нечего
CHANGED модуль изменил машину (у command — всегда)
FAILED! модуль отработал с ошибкой — причина в msg
UNREACHABLE! к машине не подключиться — ansible

-o печатает ответ каждой машины одной строкой. service в ответе выводит сотни полей юнита — -o или плейбук читать удобнее.

become: через sudo

Модули выполняются от того, под кем Ansible вошёл. Запись в /etc без прав:

text
node2 | FAILED! => {
    ...
    "msg": "Destination /etc not writable"
}

-b (--become) — выполнить модуль через sudo:

text
student@node1:~/inv$ ansible -i hosts.ini web -b -m command -a 'id -un'
node2 | CHANGED | rc=0 >>
root

На учебных машинах sudo у student без пароля. Где sudo спрашивает пароль, добавь -K (--ask-become-pass). В плейбуке то же — become: true.

Плейбуки и роли

yaml
# site.yml
- hosts: web
  become: true
  vars:
    pkg: nginx
  tasks:
    - name: Установить {{ pkg }}
      apt: { name: "{{ pkg }}", state: present, update_cache: true }
    - name: Конфиг из шаблона
      template: { src: nginx.conf.j2, dest: /etc/nginx/nginx.conf }
      notify: reload nginx        # триггерит handler при изменении
    - name: Запустить и включить
      service: { name: "{{ pkg }}", state: started, enabled: true }
  handlers:
    - name: reload nginx
      service: { name: nginx, state: reloaded }
bash
ansible-playbook -i inventory.ini site.yml
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml --limit web1 --tags config
ansible-galaxy init roles/myrole       # каркас роли

Переменные — group_vars/, host_vars/; секреты — ansible-vault (ansible-vault encrypt secrets.yml, запуск с --ask-vault-pass). На учебной машине сети наружу нет: update_cache и пакеты из сети не сработают.

Как читать вывод прогона, changed=0 на втором прогоне, обработчики, --check --diff и ошибки плейбука — ansible-playbook.

Неполадки

5

UNREACHABLE!

Ansible не подключился по SSH; до модуля дело не дошло, код возврата 4. Причина — в msg, это текст ошибки самого ssh (строки перенесены):

text
node3 | UNREACHABLE! => {
    "msg": "Failed to connect to the host via ssh: ssh: Could not
      resolve hostname node3: Temporary failure in name resolution",
node2 | UNREACHABLE! => {
    "msg": "Failed to connect to the host via ssh: admin@node2:
      Permission denied (publickey).",
web1 | UNREACHABLE! => {
    "msg": "Failed to connect to the host via ssh: Host key
      verification failed.",
Текст Причина Что делать
Could not resolve hostname имени нет ни в DNS, ни в /etc/hosts исправь имя или задай ansible_host
Permission denied (publickey) у этого пользователя нет твоего ключа верный ansible_user или ключ в его authorized_keys
Host key verification failed ключа хоста нет в known_hosts или он сменился ssh к этому адресу вручную и принять ключ; сменившийся — ssh-keygen -R <адрес>

На учебных машинах для имён node1 и node2 проверка ключа хоста выключена (/etc/ssh/ssh_config.d/99-lab.conf), а для IP-адреса в ansible_host — нет: тот же node2 по адресу даёт Host key verification failed. Проверяй вручную тем же пользователем: ssh -o BatchMode=yes node2 true; подробности — ansible … -vvv. Ключи — ssh-keys.

Destination /etc not writable

Модуль работает без прав root: нужен -b или become: true — ansible.

sudo: a password is required

Нужен --become и доступный sudo. По паролю — --ask-become-pass (-K) или NOPASSWD, см. sudo.

Задача каждый раз «changed»

Используешь command/shell вместо идемпотентного модуля. Бери модули (apt, copy, template, lineinfile) — они меняют только при необходимости. Для command — creates=/changed_when:, подробнее — ansible-playbook.

Vault: ничего не расшифровать

Нужен пароль vault (--ask-vault-pass или --vault-password-file). Без него зашифрованные переменные недоступны.

Термины

3
идемпотентность idempotency
Свойство действия: повторное применение к уже достигнутому состоянию не меняет целевой результат по сравнению с одним применением. Ещё встречается в: ansible-playbook: запуск плейбука
инвентарь (inventory)
Список машин и групп, с которыми работает Ansible: имя машины, адрес ansible_host, пользователь ansible_user, способ подключения. Обычно файл inventory.ini, передаётся ключом -i. Ещё встречается в: ansible-playbook: запуск плейбука
модуль Ansible Ansible module
Программа, которую Ansible запускает на машине для одного вида работы — ping, copy, template, service. Модуль сначала смотрит, что на машине, и отвечает ok или changed. Ещё встречается в: ansible-playbook: запуск плейбука

См. также

  • ansible-playbook — запуск плейбука, вывод, обработчики и ошибки.
  • ssh-client — Подключение по SSH, копирование scp/rsync, ~/.ssh/config, проброс портов.
  • ssh-keys — Генерация ключей, authorized_keys, ssh-agent, права на файлы .ssh.
  • sudo — что делает -b.
  • bash-scripting — Переменные, условия, циклы, аргументы и безопасный режим set -euo pipefail.
Загрузка…