Info
Content

Видео курс

Ansible На Русском Языке

https://www.youtube.com/playlist?list=PLg5SS_4L6LYufspdPupdynbMQTBnZd31N


Если на компьютере установлена утилита cowsay, то ансибл будет использовать ее для вывода заголовков тасок. Чтобы это отключить, нужно в конфиге (ansible.cfg) указать переменную nocows равной 0.

Inventory

[vandud@thinkpad ansible]$ cat hosts 
[ru]
ru ansible_host=185.211.247.40 ansible_user=root
[test]
a ansible_host=185.176.25.118 ansible_user=root
b ansible_host=185.176.25.117 ansible_user=root

[vandud@thinkpad ansible]$ cat ansible.cfg 
[defaults]
inventory = ./hosts
deprecation_warnings = False

В файле hosts перечисляются хосты и их параметры (например ключи для подключения, пользователи и прочее) [в нем можно не использовать группы, просто список хостов], по другому этот файл называется inventory.

Хосты без группы будут все равно входить в две группы: all и ungrouped.
При этом группа ungrouped входит в группу all.

То есть можно смешивать в одном файле и просто список хостов и хосты с группами.

В файле ansible.cfg перечисляются параметры. Такие же как и в /etc/ansible/ansible.cfg.


Нужно экспортировать переменную окружения, Иначе ансибл будет использовать /etc/ansible/ansible.cfg, а не тот что у тебя в текущей директории

export ANSIBLE_CONFIG=./ansible.cfg # что-то типа такого

Далее, имея два этих файла можно например пингануть все хосты:

$ ansible -m ping all
[WARNING]: Found both group and host with same name: ru
ru | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
b | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
a | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

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

Можно в ansible.cfg это указать

host_key_checking = False

А можно передать в переменной окружения

export ANSIBLE_HOST_KEY_CHECKING=False;ansible -i hosters -m ping all

Запрашивать пароль при ad-hoc

$ export ANSIBLE_HOST_KEY_CHECKING=False;ansible -i hosters -u i.dudin_pro --ask-become-pass --ask-pass -m ping all
  • --ask-become-pass - для судо
  • --ask-pass - для юзера

Можно вынести общие параметры в переменные. Например имя пользователя, ключ для подключения или что-то еще. Делается это так:

[test:vars]
ansible_user=root

То есть после объявления группы (так же как описано выше), можно ниже описать переменные для всей этой группы.

Также можно развертывать группы внутри групп:

[test:children]
a
b

[a]
a.vandud.ru ansible_host=185.176.25.118

[b]
b.vandud.ru ansible_host=185.176.25.117

[test:vars]
ansible_user=root

Имена групп могут быть в любом регистре.


Команда ansible-inventory --list позволяет вывести весь текущий inventory файл:

$ ansible-inventory --list
{
    "_meta": {
        "hostvars": {
            "a.vandud.ru": {
                "ansible_host": "185.176.25.118",
                "ansible_user": "root"
            },
            "b.vandud.ru": {
                "ansible_host": "185.176.25.117",
                "ansible_user": "root"
            },
            "ru.vandud.ru": {
                "ansible_host": "185.211.247.40",
                "ansible_user": "root"
            }
        }
    },
    "a": {
        "hosts": [
            "a.vandud.ru"
        ]
    },
    "all": {
        "children": [
            "ru",
            "test",
            "ungrouped"
        ]
    },
    "b": {
        "hosts": [
            "b.vandud.ru"
        ]
    },
    "ru": {
        "hosts": [
            "ru.vandud.ru"
        ]
    },
    "test": {
        "children": [
            "a",
            "b"
        ]
    }
}

Еще есть ansible-inventory --graph:

$ ansible-inventory --graph
@all:
  |--@ru:
  |  |--ru.vandud.ru
  |--@test:
  |  |--@a:
  |  |  |--a.vandud.ru
  |  |--@b:
  |  |  |--b.vandud.ru
  |--@ungrouped:

Ad-Hoc

Есть модуль setup, он позволяет узнать факты о хосте (как в puppet). Можно выполнить команду ansible -m setup host и увидеть большой список разных фактов.

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


Модуль shell позволяет выполнить любую команду на удаленном хосте. С помощью ключа -a передаются аргументы в модуль, в нашем случае передается сама команда:

$ ansible -m shell -a 'uptime' test
b.vandud.ru | CHANGED | rc=0 >>
 06:46:00 up  1:59,  1 user,  load average: 0.00, 0.00, 0.00
a.vandud.ru | CHANGED | rc=0 >>
 06:46:00 up  1:58,  1 user,  load average: 0.00, 0.00, 0.00

Модуль command похож на shell, но в нем не видны шелловские штуки (переменные и прочие пайплайны).


С помощью модуля copy можно копировать файлы с локальной машины на удаленные:

$ ansible -m copy -a 'src=.vimrc dest=/tmp/.' test

Также можно указывать разные параметры для файлов (права, владельцев и тд)


Модуль file позволяет работать с файлами, например удалять файлы:

$ ansible -m file -a 'path=/tmp/.vimrc state=absent' test

  • apt работает с пакетами (на чистой системе нужно не забывать обновлять кэш пакетов [apt update], иначе ничего нельзя будет установить)
  • uri может дергать сайты
  • service для управления сервисами (включение выключение и прочее)

Можно передавать ансиблу ключ -v для детализации (имеет четыре уровня: -v, -vv, -vvv, -vvvv)


ansible-doc документация по плагинам. Например:

$ ansible-doc -l | egrep '^postgres'
postgresql_copy                                               Copy data between a file/program and a PostgreSQL table                             
postgresql_db                                                 Add or remove PostgreSQL databases from a remote host                               
postgresql_ext                                                Add or remove PostgreSQL extensions from a database                                 
postgresql_idx                                                Create or drop indexes from a PostgreSQL database                                   
postgresql_info                                               Gather information about PostgreSQL servers                           
...

group_vars

Переменные можно вынести из файла hosts. Для этого нужно создать директорию group_vars и в ней в файлах с именами груп разместить переменные:

.
├── ansible.cfg
├── group_vars
│   ├── ru
│   └── test
└── hosts

В каждом файле group_vars/GROUPNAME нужно записывать параметры в формате YAML:

---
ansible_user: root

И теперь инвентарный файл содержит в себе только группы и адреса серверов:

[ru]
185.211.247.40

[test:children]
a
b

[a]
185.176.25.118

[b]
185.176.25.117

Опытным путем выявлено, что дефисы в именах переменных недопустимы.


Простой playbook

Плейбуки пишутся на YAML, вот простой пример:

---
- name: My first playbook
  hosts: test
  tasks:
    - name: Ping host
      ping:

И запускаются командой ansible-playbook PLAYBOOK_NAME:

$ ansible-playbook playbook.yaml 

PLAY [My first playbook] ******************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
ok: [185.176.25.117]
ok: [185.176.25.118]

TASK [Ping host] **************************************************************************************************************************************
ok: [185.176.25.118]
ok: [185.176.25.117]

PLAY RECAP ********************************************************************************************************************************************
185.176.25.117             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
185.176.25.118             : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Параметры модулей (например var у debug или state у apt) можно записывать в плейбуке в стиле ad-hoc после названия модуля одной строкой через пробел, либо через двоеточие в yaml.

Вот например я добавил несуществующий хост в инвентарный файл, и вывод команды ansible-playbook показывает на какие хосты удалось зайти, а на какие нет:
2020-05-04-073648_1356x277_scrot.png


В ansible можно использовать переменные. Делается это так:
В плейбуке нужно определить поле vars и в нужных местах вызывать переменные по имени внутри конструкции {{ NAME }}:

---
- name : vars and if's
  hosts: test
  
  vars :
    src_file : file
    dest_file: /tmp/file
  
  tasks:
    - name : copy file
      copy : src={{ src_file }} dest={{ dest_file }} mode=0777
   
    - name : print file
      shell: cat {{ dest_file }}
    
    - name : change dest file
      shell: uname -a > {{ dest_file }}
    
    - name : print changed file
      shell: cat {{ dest_file }}

Также переменные можно обозначать в файле hosts, точно так же как и указываются переменные ansible_host и ansible_user.


Хэндлеры

Хэндлеры - нужны в для выполнения задачи при определнных условиях. Например нужно рестартануть веб-сервер при условии что файлы сайта изменились:

---
- name : vars and if's
  hosts: test
  
  vars :
    src_file : file
    dest_file: /tmp/file
  
  tasks:
    - name : change file
      copy: src={{ src_file }} dest={{ dest_file }}
      notify: handler

  handlers:
    - name: handler
      service: name=nginx state=restarted

В данном плейбуке рестартуется nginx при условии что копируемый файл изменился.

В директиве notify вызывается хэндлер по имени в блоке name хэндлера. Вызывается он при условии что таска в которой он вызывается делает какие-либо изменения, то есть имеет статус CHANGED.

В выводе ниже видно что хэндлер запускается только в первый раз (когда файл не совпадал):

[vandud@thinkpad ansible]$ ansible-playbook playbook.yaml 

PLAY [vars and if's] **********************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
ok: [b.vandud.ru]
ok: [a.vandud.ru]

TASK [change file] ************************************************************************************************************************************
changed: [b.vandud.ru]
changed: [a.vandud.ru]

RUNNING HANDLER [handler] *****************************************************************************************************************************
changed: [b.vandud.ru]
changed: [a.vandud.ru]

PLAY RECAP ********************************************************************************************************************************************
a.vandud.ru                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
b.vandud.ru                : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

[vandud@thinkpad ansible]$ ansible-playbook playbook.yaml 

PLAY [vars and if's] **********************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
ok: [b.vandud.ru]
ok: [a.vandud.ru]

TASK [change file] ************************************************************************************************************************************
ok: [b.vandud.ru]
ok: [a.vandud.ru]

PLAY RECAP ********************************************************************************************************************************************
a.vandud.ru                : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
b.vandud.ru                : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

debug

Можно выводить факты о системе.
Выводить можно с помощью модуля debug, он имеет два параметра:

  • var - получает на вход имя выводимой переменной
  • msg - получает любой текст который нужно вывести

Вот плейбук и вывод:

---
- name : vars and if's
  hosts: test
  tasks:
  - name: "print ansible_distribution with debug:msg"
    debug:
      msg: "{{ ansible_distribution }}"
  - name: "print ansible_distribution with debug:var"
    debug:
      var: ansible_distribution
PLAY [vars and if's] **********************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
ok: [b.vandud.ru]
ok: [a.vandud.ru]

TASK [print ansible_distribution with debug:msg] ******************************************************************************************************
ok: [a.vandud.ru] => {
    "msg": "Ubuntu"
}
ok: [b.vandud.ru] => {
    "msg": "Ubuntu"
}

TASK [print ansible_distribution with debug:var] ******************************************************************************************************
ok: [a.vandud.ru] => {
    "ansible_distribution": "Ubuntu"
}
ok: [b.vandud.ru] => {
    "ansible_distribution": "Ubuntu"
}

PLAY RECAP ********************************************************************************************************************************************
a.vandud.ru                : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
b.vandud.ru                : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Поле name можно и не использовать. Того вместо имени в выводе будет указываться название используемого модуля.


set_fact

Можно создать переменную в плейбуке без блока vars. Для этого используется модуль set_fact:

  - set_fact: vandud_var="Server works at {{ ansible_distribution }}"
  - debug:
      msg: "{{ vandud_var }}"

И вывод:

TASK [set_fact] ***************************************************************************************************************************************
ok: [a.vandud.ru]
ok: [b.vandud.ru]

TASK [debug] ******************************************************************************************************************************************
ok: [a.vandud.ru] => {
    "msg": "Server works at Ubuntu"
}
ok: [b.vandud.ru] => {
    "msg": "Server works at Ubuntu"
}

register

Команда register помогает сохранить вывод таски. В ней указывается имя переменной по которой будет доступен вывод. Сама переменная содержит в себе json с множеством полей: начало выполнения таски, была ли ошибка, сам вывод и тд. И так как это json то можно через точку выбрать нужное поле как в примере ниже:

---
- name:  vars and if's
  hosts: test
  tasks:
  - set_fact: vandud_var="Server works at {{ ansible_distribution }}"
  - debug:
      msg:    "{{ vandud_var }}"
  - shell:    uptime
    register: uptime_out
  - debug:
      msg: "{{ uptime_out.stdout }}"

И вывод

TASK [debug] ******************************************************************************************************************************************
ok: [a.vandud.ru] => {
    "msg": " 04:43:31 up 1 day, 21:08,  1 user,  load average: 0.08, 0.02, 0.01"
}
ok: [b.vandud.ru] => {
    "msg": " 04:43:31 up 1 day, 23:56,  1 user,  load average: 0.08, 0.02, 0.01"
}

when

Чтобы указать условия при которых должна выполниться таска, нужно использовать директиву when. Она является свойством таски:

---
- name:  vars and if's
  hosts: test
  tasks:
    - service: name=nginx state=stopped
      when: ansible_venet0_0.ipv4.address == '185.176.25.117'

Следующий плейбук отключает nginx на соответсвующем хосте.

Вывод предыдущего плейбука:

[vandud@thinkpad ansible]$ ansible-playbook playbook.yaml 

PLAY [vars and if's] **********************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************
ok: [b.vandud.ru]
ok: [a.vandud.ru]

TASK [service] ****************************************************************************************************************************************
skipping: [a.vandud.ru]
changed: [b.vandud.ru]

PLAY RECAP ********************************************************************************************************************************************
a.vandud.ru                : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
b.vandud.ru                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Как видно, он скипает неподходящий хост, и изменяет только подходящий под условие.

Блоки

С помощью блоков можно объединять таски в контейнеры (группы). И потом например применить к этой группе общее условие (when):

---
- name:  when and block
  hosts: all
  tasks:
    - block:
      - service: name=nginx state=stopped
      - service: name=apache2 state=started
      when: ansible_venet0_0.ipv4.address == '185.176.25.117'

Циклы

Можно выполнять таску несколько раз проходя по какому-то списку аргументов.
Для этого можно использовать with_items и переменную item:

# playbook.yaml
---
- name: My Super Playbook
  hosts: all
  tasks:
    - name: Say Hello to All
      debug:
        msg: "Hello {{ item }}!"
      with_items:
        - "Ivan"
        - "Niga"
        - "Mazafaka"

Переменная item зарезервирована и в своих целях (кроме циклов) ее использовать нельзя.

В примере выше можно заменить with_items на loop и плейбук отработает идентично.


Также есть оператор until, он позволяет повторять одно и то же действие пока не будет достигнуто какое-то условие:

---
- name: My Super Playbook
  hosts: all
  tasks:
    - name: Loop Until
      shell: echo -n Niga >> /tmp/myfile && cat /tmp/myfile
      register: output
      delay: 2
      retries: 10
      until: output.stdout.find("NigaNigaNiga") == false

В примере выше, в файл печатается слово и выводится на экран. Вывод записывается в переменную и это продолжается пока в переменной не накопится три таких слова.

retries по умолчанию имеет значение 3


Чтобы скопировать много файлов можно использовать with_fileglob. С его помощью можно указать паттерн ("*.txt"), а можно и не указывать

---
- name: My Super Playbook
  hosts: all
  tasks:
  - name: Loop fileglob
    copy: src={{ item }} dest=/var/www/html/
    with_fileglob: "/tmp/test/*"

Как видно, все закопировалось.

[vandud@desktop ansible]$ ansible-playbook playbook.yaml 
...

changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/20.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/20.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/19.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/19.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/18.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/18.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/17.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/17.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/16.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/16.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/15.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/15.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/14.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/14.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/13.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/13.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/12.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/12.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/11.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/11.txt)
changed: [db.ru-ovz.vandud.ru] => (item=/tmp/test/10.txt)
changed: [back.ru-ovz.vandud.ru] => (item=/tmp/test/10.txt)

...

Для рекурсивного копирования подходит модуль copy

Jinja

Можно копировать файлы на сервер изменяя их на ходу. Для этого используется модуль template, он использует переменные, которые можно определить где угодно:

  • hosts
  • group_vars
  • playbook

Также он может использовать переменные из фактов о системе (из модуля setup).

В файлах которые нужно изменять нужно указывать переменные в Jinja формате - {{ varname }}

Модуль template аналогичен модулю copy, только он еще и понимает вызовы переменных в копируемых файлах.


В файле group_vars/all определена переменная:

---
ansible_user: root
mycoolvar: nigamazafaka

Вот такой файл с шаблонами внутри:

Generated by ansible for {{ ansible_fqdn }}<br>
Virtualization type - {{ ansible_virtualization_type }}<br>
OS - {{ ansible_lsb.description }}<br>
User Var - {{ mycoolvar }}

И вот такой плейбук:

---
- name: My Super Playbook
  hosts: db
  tasks:
    - name: Generate index.html
      template: src=index.j2 dest=/var/www/html/index.html

Дают такой результат:

2020-06-17-033123_456x170_scrot.png


Роли

Нужны для упрощения плейбуков, а точнее для структурирования и разбиения на отдельные файлы.

Вместо одного длинного и сложного плейбука будет множество файлов и директорий.

С помощью команды ansible-galaxy init my-cool-role внутри директории roles создается вот такая структура для роли my-cool-role:

└── my-cool-role
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── README.md
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml
  • files - файлы (в плейбуке файлы будут браться из этой папки)
  • templates - тоже файлы, но они обрабатываются как шаблоны jinja, модулем template
  • vars и defaults - для переменных
  • handlers - для хэндлеров
  • tasks - сам плейбук
  • meta - описание зависимостей и прочие мета-данные типа автор и описание

Jinja-темплейт:

[vandud@desktop ansible]$ cat roles/my-cool-role/templates/index.j2 
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>{{ ansible_fqdn }}</title>
  <style>
    body {
	    background-image: url({{ ansible_nodename }}-bg.jpg);
    }
  </style>
</head>

<body>
System Info:<br>
Kernel: {{ ansible_kernel }}<br>
LSB: {{ ansible_lsb.description }}<br>
Hostname: {{ ansible_fqdn }}<br>
CPU: {{ ansible_processor[2] }}<br>
Update time: {{ ansible_date_time.time }} {{ ansible_date_time.date }}
</body>
</html>

Таски в роли:

[vandud@desktop ansible]$ cat roles/my-cool-role/tasks/main.yml 
---
# tasks file for my-cool-role

- name: Copy picture to server
  copy:
    src: "{{ ansible_nodename }}-bg.jpg"
    dest: "/var/www/html/{{ ansible_nodename }}-bg.jpg"
    mode: 770
    owner: www-data
    group: www-data
- name: Copy index to server
  template:
    src: index.j2
    dest: /var/www/html/index.html
    mode: 770
    owner: www-data
    group: www-data

И сам плейбук:

---
- name: Picture and Sysinfo
  hosts: all
  roles:
    - my-cool-role

Получается вот так:

2020-06-17-075054_602x778_scrot.png


extra-vars

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

[vandud@desktop ansible]$ cat playbook.yaml 
---
- name: Picture and Sysinfo
  vars:
    node_to_exec: all
  hosts: "{{ node_to_exec }}"
  roles:
    - my-cool-role

Вот так передаем переменную при вызове:

ansible-playbook playbook.yaml -e "node_to_exec=db ansible_kernel=test_kernel"

Несколько переменных можно перечислить через пробел.

extra_vars имеют наивысший приоритет

На скриншоте видно, что переменная ansible_kernel переопределилась в соответствии с extra_vars

2020-06-17-082517_446x229_scrot.png


import, include

Нужны для включения файла с инструкциями (плейбука) в другой файл (плейбук).

Импорты предобрабатываются, а инклуды обрабатываются по мере выполнения плейбука.

Отличаются они тем, что import сразу (перед выполнением) переопределяет все переменные из импортируемого файла, а include делает это только во время выполнения.

Я не понял в чем на самом деле разница (опытным путем тоже не смог понять). На первый взгляд разницы нет. Думаю пока в моих кейсах эта разница не имеет значения.
Автор курса использует везде include - думаю мне пока следует делать так же.


delegate_to

Нужно для выполнения таски на другом сервере.
Например когда после действий на одном сервере нужно сделать какие-то на другом:

---
- name: delegate_to
  hosts: db
  
  tasks:
  
    - debug:
        msg: reboot server
        
    - copy:
        dest: /tmp/delegate_to
        content: delegated
      delegate_to: back.ru-ovz.vandud.ru

Как видно в примере выше, сам плейбук выполняется для группы db, но одна маленькая таска в нем выполняется на сервере back.ru-ovz.vandud.ru

Проверяем что это работает

[vandud@desktop ansible]$ ansible -m shell -a "cat /tmp/delegate_to" back
back.ru-ovz.vandud.ru | CHANGED | rc=0 >>
delegated

Также таким образом можно писать локальные логи:

---
- name: delegate_to
  hosts: all
  tasks:
    - debug:
        msg: reboot server
    - shell: echo {{ ansible_nodename }} was rebooted >> /tmp/delegate_to
      delegate_to: localhost

Таска на запись в лог делегируется локальной машине и мы получаем вот такой файл:

]$ cat /tmp/delegate_to 
db was rebooted
back was rebooted

И еще можно ждать пока перезагрузится сервер.
Например как-нибудь вот так:

---
- name: delegate_to
  hosts: all
  tasks:
    - shell: sleep 3 && reboot now
      async: 1 # чтобы продолжить выполнение следующих тасок без ожидания завершения этой
      poll: 0 # не ходить за статусом выполнения команды
      run_once: true
    
    - name: wait
      wait_for:
        host: all
        state: started
        delay: 15
        timeout: 30
      delegate_to: localhost

    - name: get uptime
      shell: "uptime"
      register: uptime
    - debug:
        var: uptime

run_once позволяет запустить таску только один раз на сервере который подошел первым (по очередности в hosts)


ignore_errors

Обычно, если одна из тасок зафейлилась, то все последующие таски выполняться не будут.
ignore_errors позволяет это обойти. Нужно в случаях, когда не важно выполнится таска или нет.

---
- name: delegate_to
  hosts: all
  tasks:
    - apt:
        name: treeee
        state: present
      ignore_errors: yes
    - debug:
        msg: Test

failed_when

Можно указывать условия при которых нужно завершить работу плейбука.

---
- name: delegate_to
  hosts: all
  tasks:
    - apt:
        name: treeee
        state: present
      ignore_errors: yes

    - shell: echo niga # тут например результат работы какой-либо команды или скрипта
      register: myvar
      failed_when: "'iga' in myvar.stdout" # либо какая-то ansible-переменная, указывающая на определенное состояние

Еще пример

---
- name: delegate_to
  hosts: all
  tasks:
    - apt:
        name: treeee
        state: present
      ignore_errors: yes

    - shell: uptime -p
      register: uptime
      failed_when: ansible_nodename == 'back'
    
    - debug:
        var: uptime

Остановить выполнение тасок на всех хостах при падении таски на одном из них поможет any_errors_fatal

---
- name: delegate_to
  hosts: all
  any_errors_fatal: yes
  tasks:
    - apt:
        name: treeee
        state: present
      ignore_errors: yes

    - shell: uptime -p
      register: uptime
      failed_when: ansible_nodename == 'back'
    
    - debug:
        var: uptime

Игнорируемые ошибки пройдут нормально. Но failed_when в этом примере остановит весь процесс (хотя он нацелен лишь на один хост


ansible-vault

  • ansible-vault encrypt playbook.yaml - зашифровать плейбук (или любой другой файл)
  • ansible-playbook playbook.yaml --ask-vault-pass - запустить зашифрованный плейбук с ручным вводом пароля
  • ansible-playbook playbook.yaml --vault-password-file pass - пароль из файла
  • ansible-vault decrypt playbook.yaml - расшифровать
  • ansible-vault rekey playbook.yaml - изменить пароль
  • ansible-vault edit playbook.yaml - редактировать зашифрованный файл (откроется редактор)
  • ansible-vault create test - создать зашифрованный файл (откроется редактор)
  • ansible-vault view test - вывести содержимое файла (срабатывает как cat)

Можно зашифровать кусок плейбука или переменную или что-то другое:

  • ansible-vault encrypt_string - полученный текст можно вставить в плейбук
[vandud@desktop ansible]$ echo -n 'nigamazafaka' | ansible-vault encrypt_string
New Vault password: 
Confirm New Vault password: 
Reading plaintext input from stdin. (ctrl-d to end input)
!vault |
          $ANSIBLE_VAULT;1.1;AES256
          65333931323136333731323934313439326664353934323034353964373731383931663731336561
          3962646635656664643037643866656530383831633934340a656237363737653065643138616636
          63663565376638646366313931396232316236643064396332393838633734343163613435613561
          6537623536383639380a326265373936633866623832326437306139633665356635646538343732
          3834
Encryption successful

Вставить в плейбук можно так

---
- name: vault
  hosts: all
  
  vars:
    out_var: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          65333931323136333731323934313439326664353934323034353964373731383931663731336561
          3962646635656664643037643866656530383831633934340a656237363737653065643138616636
          63663565376638646366313931396232316236643064396332393838633734343163613435613561
          6537623536383639380a326265373936633866623832326437306139633665356635646538343732
          3834
  tasks:
    
    - debug:
        var: out_var

Но тогда запускать плейбук нужно с ключом для запроса пароля (либо через файл с паролем)

ansible-playbook playbook.yaml --ask-vault-pass

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

No Comments
Back to top