notes/ansible.md

32 KiB
Raw Blame History

top

Ansible

Официальная документация


Базовые понятия Ansible

Ansible playbook


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

Отладка

Очень полезно получать в консоль результат выполнения плейбука.

  1. Один из способов это создание в плейбуке поля 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
    }
}

  1. 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)> 

Отладчик принимает команды:

Команда Сокр. вызов Действие
print 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