32 KiB
top
Ansible
- Простой playbook
- Переменные
- Отладка
- Блоки и обработка ошибок
- Асинхронные задачи
- Пример playbook - установка Docker + Docker-compose
part1
Базовые понятия Ansible
Установить ansible можно с помощью пакетного менеджера, будет установлена версия, которая есть в репозиториях дистрибутива, скорее всего, эта версия не будет являться последней.
При установке через пакетный менеджер будет создана папка с параметрами по-умолчанию по пути /etc/ansible/
.
Также, ansible можно установить с помощью pip. Будет установлена последняя версия, но папка с параметрами по-умолчанию создана не будет.
Chapter1
inventory
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#intro-inventory
Описание хостов, на которых необходимо выполнять какие-то действия производится в файле inventory.
Синтаксис файла может быть в виде ini
или yaml
форматов.
Пример описания inventory с использованием ini
my.domain.com
[mygroup]
domain.com
app.domain.com
[dbservers]
db.domain.com
Пример описания inventory с использованием yaml
all:
hosts:
my.domain.com:
children:
mygroup:
hosts:
domain.com:
app.domain.com:
dbservers:
hosts:
db.domain.com:
Указывать хосты можно в виде диапазона
[webservers]
www[01:50].example.com
Для удобства хостам можно задавать свои имена и передавать переменные которые будут доступны на хостах
[db]
mydb env=production replicas=2
Можно указать параметры подключения
[db]
myhost ansible_port=222 ansible_host=192.168.1.23
Переменные можно указать для группы хостов
[db]
db1.com
db2.com
[db:vars]
env=production
В inventory можно указать параметры подключения
ansible_connection
ansible_host
ansible_port
ansible_user
ansible_password
Параметры подключения ssh/sftp/scp
ansible_ssh_private_key_file
ansible_ssh_common_args
ansible_ssh_extra_args
ansible_ssh_pipelining
ansible_ssh_executable
ansible_scp_extra_args
ansible_sftp_extra_args
Привилегии
ansible_become
ansible_become_method
ansible_become_user
ansible_become_password
ansible_become_exe
ansible_become_flags
Настройки shell
ansible_shell_type
ansible_python_interpreter
ansible_shell_executable
Пример файла inventory
user@host$ cat hosts.ini
[deploy]
us1 ansible_host=192.168.10.151
[managers]
us2 ansible_host=192.168.10.152
us3 ansible_host=192.168.10.153
[workers]
us154 ansible_host=192.168.10.154
us155 ansible_host=192.168.10.155
[all:vars]
ansible_user=da2001
ansible_port=22
ansible_ssh_private_key_file=~/.ssh/id_rsa.pub
Пользовательский файл инвентаря
Файл инвентаря по-умолчанию обычно находится в /etc/ansible/hosts, но можно использовать опцию -i
для указания пользовательских файлов при запуске команд и плейбуков Ansible. Это удобный способ настройки индивидуального инвентаря для каждого проекта, который можно включить в системы контроля версий, такие как Git:
ansible all -m ping -i my_custom_inventory
Такая опция действительна и для ansible-playbook:
ansible-playbook myplaybook.yml -i my_custom_inventory
Динамический файл инвентаря
Ansible поддерживает сценарии инвентаризации для создания динамических файлов. Это полезно если инвентарь часто меняется, когда серверы создаются и уничтожаются.
Существуют готовые скрипты с открытым исходным кодом в официальном репозитории Ansible GitHub. После загрузки требуемого сценария на Ansible control machine и настройки необходимых параметров (например, учетных данных API) можно запустить исполняемый файл в качестве пользовательского инвентаря с любой командой Ansible, которая поддерживает эту опцию.
Следующая команда использует скрипт инвентаря my_inventory.py с командой ping для проверки подключения ко всем текущим активным серверам:
ansible all -m ping -i my_inventory.py
Как использовать динамические файлы инвентаризации описано в официальной документации Ansible.
Инвентарь можно описывать в отдельной папке и группировать хосты в отдельных файлах.
например, можно создать папку hosts
, в ней папку bd
и уже в этой папке создавать файлы с описанием хостов
Запуск в этом случае будет выглядеть так:
ansible -i hosts -m ping
или
ansible -i bd -m ping
Chapter2
Модули
https://docs.ansible.com/ansible/latest/user_guide/modules.html
Пример использования модулей
ansible webservers -m service -a "name=httpd state=started"
ansible webservers -i /home/user/ansible/hosts.ini -m command -a "/sbin/reboot -t now"
Список доступных модулей на сайте Ansible
описание модулей можно получить в cli, для этого используется команда
ansible-doc -l
будет выведен список доступных модулей в less подобном отображении
Документация по конкретному модулю ansible-doc <название модуля>
ansible-doc user
Chapter3
Ad-hoc команды
https://docs.ansible.com/ansible/latest/user_guide/intro_adhoc.html
Структура команды
ansible -i hosts -m user -a "name=student state=present" all
^ ^ ^ ^
| | | |
инвентарь | аргументы используемые хосты
модуль
Создание пользователя на хостах
если пользователь существует, вернётся сообщение зеленого цвета
если пользователь не существует, ansible попытается его создать. Если команда была запущена не от root, вернётся сообщение красного цвета типа Pemission denied
ansible -i hosts.ini -m user -a "name=da2001 state=present" all
создать нового пользователя с повышением привилегий - sudo
ansible -i hosts.ini -m user -a "name=student state=present" -b -K all
-b
- команда должна выполняться с привилегиями sudo
-K
- запрашивать пароль sudo перед выполнением команды
удалить пользователя
ansible -i hosts.ini -m user -a "name=student state=absent" -b -K all
передать sudo пароль в виде аргументов - extra args
ansible -i hosts.ini -m user -a "name=student state=present" -e "ansible_become=true ansible_become_password=USER-PASS" all
USER-PASS
- пароль пользователя для выполнения команды с привилегиями sudo
part2
Ansible playbook
https://docs.ansible.com/ansible/latest/user_guide/playbooks_intro.html
Chapter4
Простой playbook
cat user.yml
---
- name: user - имя playbook, произвольное
hosts: deploy - группа хостов из файла inventory
tasks: - задачи, выполняемые в этом плейбуке
- name: Create user - имя задачи, произвольное
user: - название модуля, который используется в этой задаче
name: da2001 - аргументы модуля
state: present - аргументы модуля
become: true
ansible-playbook -i hosts.ini user.yml -K
Chapter5
Переменные
https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html
Переменные можно задавать в:
- playbook
- block
- tasks
- group_vars
- host_vars
- inventory
- extra_vars
- var_files
переменная задаётся в фигурных скобках, обязательно в кавычках
cat user.yml
---
- name: user
hosts: deploy
tasks:
- name: Create user
vars:
user: da2001
user:
name: "{{ user }}"
state: present
become: true
Переменная может быть задана во внешнем файле
cat myvars.yml
user: da2001
в плейбуке необходимо указать файл с переменными
---
- name: user
hosts: deploy
vars_files:
- ./myvars.yml
tasks:
- name: Create user
user:
name: "{{ user }}"
state: present
become: true
Вместе с ansible устанавливается плагин, который позволяет считывать переменные из определённых файлов и папок без явного указания этих файлов и папок в плейбуке
group_vars
- папка в которой нужно создать папку с названием группы, для которой будут задаваться переменные. Например, для группы хостовdeploy
необходимо создать такой путь/файл -./group_vars/deploy/vars.yml
cat ./group_vars/deploy/vars.yml
user: da2001
в самом плейбуке нет необходимости где-то указывать ссылки на файл с переменными
cat user.yml
---
- name: user
hosts: deploy
tasks:
- name: Create user
user:
name: "{{ user }}"
state: present
become: true
Если переменные могут использоваться во всех группах, можно создать папку all
- ./group_vars/all/vars.yml
host_vars
- папка, в которой создаётся файл с именем хоста -./host_vars/us1.yml
. Если для хоста имя не задано -./host_vars/192.168.10.151.yml
- создание переменных в файле инвентаря
для хоста us1 добавлена переменная
user
cat hosts.ini
[deploy]
us1 ansible_host=192.168.10.151 user=da2001
[managers]
us2 ansible_host=192.168.10.152
us3 ansible_host=192.168.10.153
[workers]
us154 ansible_host=192.168.10.154
us155 ansible_host=192.168.10.155
[all:vars]
ansible_user=da2001
ansible_port=22
ansible_ssh_private_key_file=~/.ssh/id_rsa.pub
--extra-vars
- передача переменных в команде запуска
ansible-playbook -i hosts.ini user.yml -K --extra-vars "user=da2001"
vars-prompt
- ввод переменных в интерактивном режиме при выполнении playbook
cat user.yml
---
- name: user
hosts: deploy
vars_prompt:
- name: user
prompt: "Введите имя пользователя"
private: no
tasks:
- name: Create user
user:
name: "{{ user }}"
state: present
become: true
private: no
- отображать ли вводимые символы
Chapter6
Отладка
Очень полезно получать в консоль результат выполнения плейбука.
- Один из способов это создание в плейбуке поля
register
с какой-либо переменной для вывода. Далее этот вывод получаем в таскеdebug
. Например:
---
- name: user
hosts: deploy
tasks:
- name: Create user
vars:
user: da2001
user:
name: "{{ user }}"
state: present
become: true
register: output
- debug:
var: output
После запуска плейбука
ansible-playbook -i hosts.ini user.yml -K
к выводу добавится значение таск debug
с выводом значения созданной нами переменной output
TASK [debug] ***********************************************************************************************************
ok: [us1] => {
"output": {
"append": false,
"changed": false,
"comment": "da2001",
"failed": false,
"group": 1000,
"home": "/home/da2001",
"move_home": false,
"name": "da2001",
"shell": "/bin/bash",
"state": "present",
"uid": 1000
}
}
- Debugger https://docs.ansible.com/ansible/latest/user_guide/playbooks_debugger.html#playbook-debugger
Значение | Результат |
---|---|
always | всегда вызывать отладчик, независимо от результата |
never | никогда не запускать отладчик, независимо от результата |
on_failed | вызывать отладчик только в случае сбоя задачи |
on_unreachable | вызывать отладчик только в том случае, если хост недоступен |
on_skipped | вызывать отладчик только в том случае, если задача пропущена |
---
- name: user
hosts: deploy
tasks:
- name: Create user
vars:
user: da2001
user:
name: "{{ user }}"
state: present
become: true
debugger: always
При наступлении условия, при котором вызывается отладчик, выполнение задачи приостанавливается и отладчик ожидает действий от пользователя
user@host:~$ ansible-playbook -i hosts.ini user.yml -K
BECOME password:
PLAY [user] ************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [us1]
TASK [Create user] *****************************************************************************************************
ok: [us1]
[us1] TASK: Create user (debug)>
Отладчик принимает команды:
Команда | Сокр. вызов | Действие |
---|---|---|
p | напечатать информацию о задаче | |
task.args[key] = value | no shortcut | изменить значение аргумента |
task_vars[key] = value | no shortcut | изменить значение переменной (далее необходимо выполнить update_task ) |
update_task | u | повторно создать задачу с обновленными переменными |
redo | r | заново запустить задачу |
continue | c | продолжить выполнение, запуск следующей задачи |
quit | q | выход из отладчика |
Примеры:
[us1] TASK: Create user (debug)> p task
TASK: Create user
[us1] TASK: Create user (debug)> p task.args
{'_ansible_check_mode': False,
...
'_ansible_version': '2.11.6',
'name': 'da2001',
'state': 'present'}
[us1] TASK: Create user (debug)> p task.vars
{'user': 'da2001'}
[us1] TASK: Create user (debug)> p task_vars
{'ansible_all_ipv4_addresses': ['192.168.10.151'],
...
'playbook_dir': '/home/da2001/ansible/udemy/ansible',
'role_names': [],
'user': 'da2001'}}
[us1] TASK: Create user (debug)> p task_vars['user']
'da2001'
[us1] TASK: Create user (debug)> p host
us1
[us1] TASK: Create user (debug)> task_vars['user'] = 'user'
[us1] TASK: Create user (debug)> p task_vars['user']
'user'
[us1] TASK: Create user (debug)> update_task
[us1] TASK: Create user (debug)> redo
Chapter7
Блоки и обработка ошибок
Пример блока
---
- name: user
hosts: deploy
tasks:
- name: Preconfig block
block:
- name: Create user
vars:
user: da2001
user:
name: "{{ user }}"
state: present
- name: Install curl
apt:
name: curl
update-cashe: yes
become: true
Условие выполнения блока
в начале выполнения плейбука, ansible собирает факты о хостах, на основе полученных фактов можно описывать условия выполнения блоков.
Например: добавим условие, при котором блок будет выполняться только если в качестве хоста используется Ubuntu. Для этого в блок нужно добавить:
when: ansible_facts['distribution' == 'Ubuntu']
Обработка ошибок
---
- name: user
hosts: deploy
tasks:
- name: Preconfig block
block:
- name: Create user
vars:
user: da2001
user:
name: "{{ user }}"
state: present
register: error
- name: Install curl
apt:
name: curl
update-cashe: yes
register: error
become: true
rescue:
- name: Some error print
debug:
var: error
always:
- name: Reboot
debug:
msg: "Rebooooooting"
Обработка ошибок происходит в блоке rescue
. В каждом задании мы определили register: error
- переменную, которая будет отображаться при возникновении ошибки. Т.к. в блоке rescue
определена единственная переменная var: error
- она будет выводиться при ошибке в любом задании. Для каждого задания можно определить свою переменную.
Блок always
будет выполняться всегда, вне зависимости от того, были ошибки в заданиях или нет.
Другие возможности управления ошибками
-
any_errors_fatal
- true/false. Если установлено значениеtrue
- появление любой ошибки будет приводить к остановке плейбука,false
- имеет обратное значение, плейбук попытается продолжить своё выполнение при любых ошибках. -
ignore_errors
- true/false. В некоторых задачах можно установить параметр, чтобы игнорировать возникающие ошибки и перейти к выполнению следующей задачи. -
принудительный вызов ошибки. Можно создать отдельную задачу, в которой будет перехвачен вывод и будет сымитирована ошибка, которая приведёт к остановке выполнения плейбука. В нужное место плейбука добавить подобную задачу:
- name: Fail on FAILED
command: echo "FAILED"
register: command_result
failed_when: "'FAILED' in command_result.stdout"
при выполнении этой задачи, команда echo выведет в консоль слово FAILED
, следующей строкой происходит перехват вывода и проверяется на соответствие условию - 'FAILED' in command_result.stdout
, если условие выполняется, сформируется ошибка и дальнейшее выполнение будет остановлено.
Chapter8
Асинхронные задачи
Ansible выполняет задачи плейбука последовательно, иногда возникают ситуации, когда есть независимые друг от друга задачи, которые могут выполняться параллельно. Именно для этого используется асинхронный запуск длинных задач.
Т.е. задача запускается и ansible отключается от неё, чтобы подождать выполнение или переключиться на другую задачу.
Пример - 1
async: 1000
- максимальное время в секундах, в течение которого задача должна выполниться
poll: 5
- интервал в секундах, в течение которого ansible будет проверять состояние задачи
cat async.yml
---
- name: user
hosts: deploy
tasks:
- name: Preconfig block
block:
- name: Sleep
command: sleep 15
async: 1000
poll: 5
become: true
user@host:~$ ansible-playbook -i hosts.ini async.yml -K
BECOME password:
PLAY [user] ************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [us1]
TASK [Sleep] ***********************************************************************************************************
ASYNC POLL on us1: jid=290251027418.31066 started=1 finished=0
ASYNC POLL on us1: jid=290251027418.31066 started=1 finished=0
changed: [us1]
PLAY RECAP *************************************************************************************************************
us1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ASYNC POLL on us1: jid=290251027418.31066 started=1 finished=0
- каждые 5 секунд (значение poll) ansible подключается к задаче по id (jid=290251027418.31066
) и проверяет её статус. При этом, переключение на следующую задачу не произойдёт до завершения текущей задачи.
Пример - 2
Задача 1 - спим 15 секунд, не дожидаясь окончания задачи переходим к следующей
Задача 2 - выполняем команду echo
Зачада 3 - проверяем статус выполнения первой задачи
jid: "{{ sleep.ansible_job_id }}"
- получаем статус задачи (выполнение задачи и получение её статуса важно делать от одного и того же пользователя, иначе ansible не увидит задачу. Т.е. если основная задача выполняется от sudo (become: true
), то и проверять статус также нужно от sudo).
ждём выполнения задачи until: job_result.finished
, при этом задаём необязательные параметры -
retries: 100
- проверяем выполнение отслеживаемой задачи 100 раз
delay: 1
- задержка между повторами - 1 секунда.
cat async.yml
---
- name: user
hosts: deploy
tasks:
- name: Preconfig block
block:
- name: Sleep
command: sleep 10
async: 1000
poll: 0
register: sleep
- name: Echo
command: echo "Задача выполнена"
become: true
- name: Check sleep status
async_status:
jid: "{{ sleep.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 100
delay: 1
become: true
user@host:~$ ansible-playbook -i hosts.ini async.yml -K
BECOME password:
PLAY [user] ************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [us1]
TASK [Sleep] ***********************************************************************************************************
changed: [us1]
TASK [Echo] ************************************************************************************************************
changed: [us1]
TASK [Check sleep status] **********************************************************************************************
FAILED - RETRYING: Check sleep status (100 retries left).
FAILED - RETRYING: Check sleep status (99 retries left).
FAILED - RETRYING: Check sleep status (98 retries left).
FAILED - RETRYING: Check sleep status (97 retries left).
FAILED - RETRYING: Check sleep status (96 retries left).
FAILED - RETRYING: Check sleep status (95 retries left).
changed: [us1]
PLAY RECAP *************************************************************************************************************
us1 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Chapter9
Пример playbook - установка Docker + Docker-compose
---
- name: Preconfig
hosts: deploy
tasks:
- name: Установка Docker
block:
- name: Добавление репо Ububntu universe
apt_repository:
repo: "deb http://archive.ubuntu.com/ubuntu {{ ansible_distribution_release }} main universe restricted multiverse"
state: present
- name: Установка дополнительных пакетов
apt:
name:
- ca-certificates
- curl
- gnupg
- lsb-release
update_cache: true
- name: Добавление ключа Docker
apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
keyring: /usr/share/keyrings/docker-archive-keyring.gpg
state: present
- name: Установка репозитория Docker
apt_repository:
repo: >
deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
{{ ansible_distribution_release }} stable
state: present
update_cache: true
filename: docker
- name: Установка Docker
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
update_cache: true
- name: Проверка корректности установки Docker
service:
name: docker
state: restarted
enabled: true
become: true
- name: Установка Docker-compose
block:
- name: Получение последней версии Docker-compose
uri:
url: "https://api.github.com/repos/docker/compose/releases/latest"
body_format: json
register: page
- name: Установка Docker-compose
get_url:
url: "https://github.com/docker/compose/releases/download/{{ page.json.tag_name }}/docker-compose-Linux-x86_64"
dest: /usr/local/bin/docker-compose
mode: 0755
become: true
- name: Завершение установки
block:
- name: Добавление пользователя в группу Docker
user:
name: "{{ ansible_user }}"
groups: docker
append: true
- name: Перезагрузка
reboot:
become: true
перечень необходимых пакетов, ссылки на репозитории и прочие данные, необходимые для установки взяты из официальной документации
https://docs.docker.com/engine/install/ubuntu/
https://docs.docker.com/compose/install/
git add . && git commit -m 'mod ansible' && git push