Показаны различия между двумя версиями страницы.
Предыдущая версия справа и слева Предыдущая версия Следующая версия | Предыдущая версия | ||
ansible [2023/01/20 15:54] admin |
ansible [2025/01/16 15:58] (текущий) admin |
||
---|---|---|---|
Строка 1: | Строка 1: | ||
====== Ansible ====== | ====== Ansible ====== | ||
+ | [[: | ||
- | < | + | [[:ansible:yml|Yaml. Декларативный |
- | < | + | |
- | Управление хостами, | + | |
- | При запуске плейбука из консоли, | + | |
- | В командах мы описываем желаемое состояние системы, при выполнении софт проверяет так ли это, если | + | [[: |
- | Команды можно выполнять одиночно из cli, либо объединять в файлы конфигурации т.н. плейбуки **" | + | |
- | < | + | [[:ansible:over|Overall]] |
- | < | + | |
- | Описано две задачи, | + | |
- | + | ||
- | <code yaml> | + | |
- | - hosts: web-servers | + | |
- | tasks: | + | |
- | - name: Installs nginx web server | + | |
- | apt: pkg=nginx state=installed update_cache=true | + | |
- | - name: Push future default virtual host configuration | + | |
- | copy: src=files/ | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | **Inventory** файл в котором хранится перечень целевых хостов, | + | |
- | По умолчанию **/ | + | |
- | Хосты могут объединяться в группы, | + | |
- | + | ||
- | < | + | |
- | < | + | |
- | ./ | + | |
- | <code yaml> | + | |
- | all: | + | |
- | children: | + | |
- | myGroup: | + | |
- | vars: | + | |
- | myVariable1: | + | |
- | myVariable2: | + | |
- | myVariable3: | + | |
- | hosts: | + | |
- | alias1: | + | |
- | ansible_host: | + | |
- | alias2: | + | |
- | ansible_host: | + | |
- | alias3: | + | |
- | ansible_host: | + | |
- | </ | + | |
- | Непонятки с организацией этого инвентаря, | + | |
- | + | ||
- | Далее в коде доступны эти хосты и набор переменных к каждому | + | |
- | ./ | + | |
- | <code yaml> | + | |
- | ... | + | |
- | with_items: "{{ groups[' | + | |
- | + | ||
- | "{{ hostvars[item] }}" # Элемент группы, | + | |
- | "{{ hostvars[item][myVariable1-4] }}" # Во вложенном массиве доступна вся инфа о хосте, в т.ч. набор переменных из инвентори, | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | **Roles**, роли используются для разделения плейбука на части, и организации файлов. Для роли создается каталог, | + | |
- | Создание происходит автоматически, | + | |
- | Особенность в том что роли могут быть вложенными т.е. составлять цепочку выполнения\\ | + | |
- | {{:ansible_roles.png? | + | |
- | + | ||
- | + | ||
- | Все переменные в ансибл **глобальные**, | + | |
- | Хороший путь ансибл это максимально **простое и линейное описание** последовательного процесса, | + | |
- | + | ||
- | + | ||
- | **Шаблоны** нечто иное как использование переменных типа **{ { inventory_hostname } }** (двойные скобки вместе), | + | |
- | + | ||
- | + | ||
- | **notify** обработчик, | + | |
- | **handlers** описание обработчика, | + | |
- | + | ||
- | + | ||
- | **ansible.cfg** основной конфиг\\ | + | |
- | + | ||
- | < | + | |
- | < | + | |
- | [[https:// | + | |
- | <code yaml> | + | |
- | [defaults] | + | |
- | # Используемый инвентори | + | |
- | inventory = ./myhosts | + | |
- | + | ||
- | # Чтобы убрать предупреждение об автопоиске питона | + | |
- | interpreter_python = auto_silent | + | |
- | + | ||
- | # Подключаемый пользователь | + | |
- | remote_user = anuser | + | |
- | + | ||
- | # Отключение подтверждения нового ssh ключа | + | |
- | host_key_checking = False | + | |
- | + | ||
- | # Отключение сбора фактов | + | |
- | gathering = explicit | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | </ | + | |
- | + | ||
- | ===== Использование ===== | + | |
- | Созданный на хосте пользователь должен быть судошным без ввода пароля, | + | |
- | + | ||
- | Yaml файл начинается с директивы **" | + | |
- | + | ||
- | **Установка** | + | |
- | <code bash> | + | |
- | # apt install ansible | + | |
- | # yum install epel-release && yum install ansible | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Общее ==== | + | |
- | ==== Исполнения ==== | + | |
- | + | ||
- | По умолчанию ансибл выполняет все команды на хостах, | + | |
- | Выполнение можно делегировать на другой хост в т.ч. на локальный, | + | |
- | + | ||
- | При делегировании возможно переменные указывают на делегированный хост, а не на инвентори, | + | |
- | + | ||
- | Во всех случаях таска выполнится столько раз сколько хостов указано, | + | |
- | И кстати нормально, | + | |
- | + | ||
- | Так же есть директива " | + | |
- | + | ||
- | <code yaml> | + | |
- | --- | + | |
- | - hosts: webservers | + | |
- | # | + | |
- | tasks: | + | |
- | - name: Take out of load balancer pool | + | |
- | ansible.builtin.command: | + | |
- | delegate_to: | + | |
- | + | ||
- | - name: Take out of load balancer pool | + | |
- | local_action: | + | |
- | + | ||
- | - name: Send summary mail | + | |
- | local_action: | + | |
- | module: community.general.mail | + | |
- | body: "{{ mail_body }}" | + | |
- | run_once: True | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Циклы ==== | + | |
- | [[https:// | + | |
- | + | ||
- | **loop**, **with_item**, | + | |
- | кстати говоря может быть with_< | + | |
- | + | ||
- | По умолчанию обход выполняется просто по хостам из инвентаря, | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | Инвентарь | + | |
- | <code yaml> | + | |
- | all: | + | |
- | children: | + | |
- | loctest: | + | |
- | vars: | + | |
- | zabbix_agent_server: | + | |
- | zabbix_url: http:// | + | |
- | zabbix_api_use: | + | |
- | zabbix_host_status: | + | |
- | hosts: | + | |
- | one: | + | |
- | param_name: 10.10.40.204 | + | |
- | two: | + | |
- | param_name: 1.1.1.1 | + | |
- | three: | + | |
- | param_name: 2.2.2.2 | + | |
- | </ | + | |
- | + | ||
- | Обработка | + | |
- | <code yaml> | + | |
- | --- | + | |
- | - name: Test play | + | |
- | hosts: loctest | + | |
- | gather_facts: | + | |
- | tasks: | + | |
- | - name: check | + | |
- | delegate_to: | + | |
- | ansible.builtin.debug: | + | |
- | msg: | + | |
- | - "{{ hostvars[item][' | + | |
- | loop: "{{ groups[' | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | Инвентарь | + | |
- | <code yaml> | + | |
- | all: | + | |
- | children: | + | |
- | cl_autotest: | + | |
- | hosts: | + | |
- | S221AUTOTEST: | + | |
- | S222AUTOTEST: | + | |
- | cl_halftest: | + | |
- | hosts: | + | |
- | S201: | + | |
- | S207: | + | |
- | cl_sib: | + | |
- | hosts: | + | |
- | S202: | + | |
- | S203: | + | |
- | </ | + | |
- | + | ||
- | Обработка | + | |
- | <code yaml> | + | |
- | --- | + | |
- | - name: Show List Inventory | + | |
- | hosts: 127.0.0.1 | + | |
- | gather_facts: | + | |
- | tasks: | + | |
- | - name: Groups | + | |
- | ansible.builtin.debug: | + | |
- | msg: "{{ item }}" # или без цикла, сразу список "{{ groups | list }}" | + | |
- | loop: "{{ groups | list }}" | + | |
- | + | ||
- | msg: "{{ groups | select(' | + | |
- | # Еще есть вариант фильтрации (reject работает наоборот) | + | |
- | "..| reject(' | + | |
- | + | ||
- | # Еще варианты перебора и отображения инвентаря, | + | |
- | - name: Print | + | |
- | #vars: | + | |
- | # cluster_group: | + | |
- | ansible.builtin.debug: | + | |
- | msg: | + | |
- | #- "{{ hostvars[inventory_hostname] }}" | + | |
- | #- "{{ inventory_hostname }}" | + | |
- | #- "{{ groups[' | + | |
- | #- "{{ group_names | select(' | + | |
- | + | ||
- | #- "{{ groups[ansible_limit] }}" | + | |
- | - "Host name is - {{ hostvars[item][' | + | |
- | + | ||
- | loop: "{{ groups[ansible_limit] }}" | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Переменные ==== | + | |
- | [[https:// | + | |
- | **" | + | |
- | + | ||
- | <code yaml> | + | |
- | # Распечатать инфу хоста | + | |
- | ansible myhost -m setup | + | |
- | ansible myhost -m setup -a " | + | |
- | + | ||
- | # Или в плейбуке | + | |
- | - name: "Print facts" | + | |
- | ansible.builtin.debug: | + | |
- | msg: | + | |
- | - "{{ ansible_facts }}" | + | |
- | - "{{ ansible_facts[" | + | |
- | </ | + | |
- | + | ||
- | **Результат выполнения** | + | |
- | <code yaml> | + | |
- | - name: Execute against dev | + | |
- | shell: 'echo " | + | |
- | register: cmd_dev_out | + | |
- | - debug: | + | |
- | msg: "{{ cmd_dev_out }}" | + | |
- | + | ||
- | - name: Get host info | + | |
- | local_action: | + | |
- | module: community.zabbix.zabbix_host_info | + | |
- | server_url: '{{ zabbix_server_url }}' | + | |
- | (..) | + | |
- | register: cmd_dev_out | + | |
- | + | ||
- | - name: " | + | |
- | ansible.builtin.debug: | + | |
- | msg: "{{ cmd_dev_out }}" | + | |
- | + | ||
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Условие выполнения ==== | + | |
- | **when** - выполнять таску если условие выполняется\\ | + | |
- | Применяется очевидно только к таскам\\ | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | <code yaml> | + | |
- | - name: Checking that required variables are set | + | |
- | fail: msg=" | + | |
- | when: item not in vars | + | |
- | loop: | + | |
- | - win_zbx_path | + | |
- | - win_repo | + | |
- | + | ||
- | - name: Run with items greater than 5 | + | |
- | ansible.builtin.command: | + | |
- | loop: [ 0, 2, 4, 6, 8, 10 ] | + | |
- | when: item > 5* | + | |
- | + | ||
- | - name " | + | |
- | when: condition1 == " | + | |
- | + | ||
- | - name " | + | |
- | when: | + | |
- | - sshkey_result.rc == 1 | + | |
- | - github_username is undefined or | + | |
- | github_username |lower == ' | + | |
- | + | ||
- | | + | |
- | when: hostvars[item][' | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Инфо о хосте ==== | + | |
- | **ansible_facts** - содержит множество данных о целевом хосте\\ | + | |
- | Занимает время при каждом выполнении, | + | |
- | + | ||
- | <code bash> | + | |
- | ansible 10.11.193.43 -m setup | + | |
- | ansible 10.11.193.43 -m setup -a ' | + | |
- | ansible 10.11.193.43 -m setup -a ' | + | |
- | ansible all -m debug -a " | + | |
- | </ | + | |
- | + | ||
- | <code yaml> | + | |
- | - name: Collect only facts returned by facter | + | |
- | ansible.builtin.setup: | + | |
- | gather_subset: | + | |
- | + | ||
- | {{ ansible_facts[' | + | |
- | + | ||
- | {{ hostvars[' | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Манипуляции с текстом ==== | + | |
- | [[https:// | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | + | ||
- | Инвентори или group_vars: | + | |
- | <code yaml> | + | |
- | mylist: | + | |
- | - cl_first | + | |
- | - cl_second | + | |
- | - cl_three | + | |
- | - cl_four | + | |
- | </ | + | |
- | + | ||
- | Простой вывод списка, | + | |
- | <code yaml> | + | |
- | --- | + | |
- | - name: Test play | + | |
- | hosts: 127.0.0.1 | + | |
- | tasks: | + | |
- | - name: check | + | |
- | debug: | + | |
- | msg: | + | |
- | - "{{ mylist | replace(' | + | |
- | - "{{ list1 | difference(list2) }}" | + | |
- | - "{{ list | select(' | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Работа с группами инвентори ==== | + | |
- | + | ||
- | <code yaml> | + | |
- | # Перечень групп (развернут с хостами) | + | |
- | {{ groups }} | + | |
- | + | ||
- | # Содержимое конкретной группы | + | |
- | {{ groups['< | + | |
- | + | ||
- | # Перечень без развертывания | + | |
- | {{ groups.keys() }} | + | |
- | + | ||
- | # Тоже без развертывания | + | |
- | {{ groups | list }} | + | |
- | + | ||
- | # Группы в которые входит хост выполнения | + | |
- | {{ group.names }} | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | ==== Аргументы/ | + | |
- | + | ||
- | * **-b [become]** - выполнять с повышенными привилегиями | + | |
- | * **[roles]** - список ролей применяемые для плейбука | + | |
- | * **-i** - каталог с инвентори | + | |
- | * **-a** - аргументы | + | |
- | * **-l (--limit)** - группа/ | + | |
- | + | ||
- | + | ||
- | ==== Vault ==== | + | |
- | При использовании пароля в файле, используется только вывод файла т.е. запуск, | + | |
- | + | ||
- | <code bash> | + | |
- | # Зашифровать файл | + | |
- | ansible-vault encrypt ' | + | |
- | + | ||
- | # Расшифровать файл | + | |
- | ansible-vault decrypt ' | + | |
- | + | ||
- | # Зашифровать строку | + | |
- | ansible-vault encrypt_string ' | + | |
- | + | ||
- | Переменная среды: ANSIBLE_VAULT_PASSWORD_FILE=~/ | + | |
- | Ключ для запроса в cmd: --ask-vault-pass | + | |
- | Ключ для указания в cmd: --vault-password-file | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Ограничения запуска ==== | + | |
- | Указывая хост (или группу) можно ограничить те места, откуда будет выполняться задача, | + | |
- | + | ||
- | <code bash> | + | |
- | ansible-playbook mybook.yml --limit < | + | |
- | ansible < | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== Работа с файлами ==== | + | |
- | Как минимум три модуля: | + | |
- | * **lineinfile** - добавить, | + | |
- | * **replace** - добавить, | + | |
- | * **blockinfile** - добавлять несколько строк, окруженных маркерами | + | |
- | + | ||
- | < | + | |
- | < | + | |
- | ** lineinfile **\\ | + | |
- | [[https:// | + | |
- | Поиск/ | + | |
- | <code yaml> | + | |
- | - name: Ensure SELinux is set to enforcing mode | + | |
- | ansible.builtin.lineinfile: | + | |
- | path: / | + | |
- | regexp: ' | + | |
- | line: SELINUX=enforcing | + | |
- | + | ||
- | - name: Make sure group wheel is not in the sudoers configuration | + | |
- | ansible.builtin.lineinfile: | + | |
- | path: / | + | |
- | state: absent | + | |
- | regexp: ' | + | |
- | </ | + | |
- | + | ||
- | ** replace **\\ | + | |
- | [[https:// | + | |
- | Поинтереснее, | + | |
- | Указав " | + | |
- | Для замены собсна тоже принимает строку\\ | + | |
- | + | ||
- | <code yaml> | + | |
- | - name: " | + | |
- | ansible.builtin.replace: | + | |
- | path: / | + | |
- | after: "# Start gameserver hosts" | + | |
- | before: "# End gameserver hosts" | + | |
- | #regexp: ' | + | |
- | #replace: ' | + | |
- | regexp: ' | + | |
- | replace: ' | + | |
- | </ | + | |
- | + | ||
- | ** blockinfile **\\ | + | |
- | [[https:// | + | |
- | Вставляет блок текста, | + | |
- | Можно указать регулярками (либо конец файла) после чего (до чего) вставлять блок, что то одно !!!\\ | + | |
- | + | ||
- | Работает прежде всего с блоками текста, | + | |
- | С блоками работает нормально, | + | |
- | + | ||
- | <code yaml> | + | |
- | - name: " | + | |
- | ansible.builtin.blockinfile: | + | |
- | #become: yes | + | |
- | # | + | |
- | # | + | |
- | path: / | + | |
- | block: | | + | |
- | 2.2.2.2 two | + | |
- | 3.3.3.3 three | + | |
- | 4.4.4.4 four | + | |
- | marker: " | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | ==== Фильтрация списков словарей ==== | + | |
- | * **selectattr rejectattr** - возвращает весь элемент по указанному условию | + | |
- | * **map** - вырезает только значения указанных аттрибутов, | + | |
- | + | ||
- | < | + | |
- | < | + | |
- | ** selectattr rejectattr **\\ | + | |
- | Есть нюанс тогда когда указанный для фильтрации ключ [[https:// | + | |
- | + | ||
- | Условия для поиска могут быть разными " | + | |
- | + | ||
- | <code yaml> | + | |
- | # Так возвращает элемент (весь элемент словаря) у которого установлен аргумент в указанное значение | + | |
- | # " | + | |
- | "{{ fruit | selectattr(' | + | |
- | + | ||
- | # " | + | |
- | "{{ fruit | selectattr(' | + | |
- | </ | + | |
- | + | ||
- | ** map **\\ | + | |
- | <code yaml> | + | |
- | # Из общего списка словарей вернет только элементы по регулярке, | + | |
- | "{{ fruit | selectattr(' | + | |
- | </ | + | |
- | + | ||
- | </ | + | |
- | + | ||
- | + | ||
- | ===== Преобразования типов данных ===== | + | |
- | [[https:// | + | |
- | dict2items, | + | |
- | + | ||
- | + | ||
- | + | ||
- | ===== Примеры ===== | + | |
- | ==== Zabbix ==== | + | |
- | Для работы нужен " | + | |
- | <code bash> | + | |
- | / | + | |
- | ansible-galaxy collection install community.zabbix | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | + | ||
- | ==== OverAll ==== | + | |
- | < | + | |
- | < | + | |
- | hosts, можно короче\\ | + | |
- | <code yaml> | + | |
- | all: | + | |
- | hosts: | + | |
- | 192.168.0.101 | + | |
- | </ | + | |
- | + | ||
- | test.yaml | + | |
- | <code yaml> | + | |
- | --- | + | |
- | - hosts: all | + | |
- | tasks: | + | |
- | - name: Test ping | + | |
- | delegate_to: | + | |
- | ping: | + | |
- | </ | + | |
- | + | ||
- | + в конфиге еще путь к инвентори | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | Инкремент переменной в цикле \\ | + | |
- | <code yml> | + | |
- | --- | + | |
- | - hosts: all | + | |
- | gather_facts: | + | |
- | run_once: True | + | |
- | tasks: | + | |
- | - name: Get list group | + | |
- | vars: | + | |
- | - llist: '' | + | |
- | - foo: '' | + | |
- | set_fact: | + | |
- | foo: "{{ item +' '+ hostvars[item][' | + | |
- | llist: "{{ llist + foo }}\n\r " | + | |
- | loop: "{{ groups[' | + | |
- | + | ||
- | - name: show | + | |
- | debug: | + | |
- | msg: "{{ llist }}" | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | < | + | |
- | < | + | |
- | + | ||
- | <code yml> | + | |
- | --- | + | |
- | - hosts: all | + | |
- | gather_facts: | + | |
- | run_once: True | + | |
- | tasks: | + | |
- | - name: Get list group | + | |
- | shell: | + | |
- | cmd: "ss -ntlua | grep 8086 | wc" | + | |
- | register: resultt | + | |
- | become: yes | + | |
- | - debug: var=resultt.stdout_lines | + | |
- | </ | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | < | + | |
- | < | + | |
- | Есть несколько вариантов/ | + | |
- | Например вывод списка из инвентори команды: | + | |
- | **ansible-inventory, | + | |
- | Можно просто запросом в консоли через debug\\ | + | |
- | <code yml> | + | |
- | ansible localhost -m debug -a ' | + | |
- | ansible-inventory --graph " | + | |
- | </ | + | |
- | </ | + | |
+ | [[: | ||
+ | [[: | ||
+ | [[: |