Инструменты пользователя

Инструменты сайта


ansible

Это старая версия документа!


Ansible

Концепция

Управление хостами, по сети, через ssh подключение, нужен беспарольный доступ с хоста ансибла на целевой хост
При запуске плейбука из консоли, используется авторизованный пользователь, в файле ansible.cfg можно указать другого в параметре «remote_user»

В командах мы описываем желаемое состояние системы, при выполнении софт проверяет так ли это, если нет, то выполняет необходимые действия
Команды можно выполнять одиночно из cli, либо объединять в файлы конфигурации т.н. плейбуки «playbooks», описание в формате yaml

:!: Пример плейбука

Описано две задачи, сначала установка nginx, затем копирование файла

- 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/site.conf dest=/etc/nginx/sites-enabled/ mode=0640

Inventory файл в котором хранится перечень целевых хостов, с которыми ведется работа. Так же здесь могут хранится переменные.
По умолчанию /etc/ansible/inventory/hosts, можно задавать другое расположение через конфиг. Расширение добавлять не нужно
Хосты могут объединяться в группы, с-но при выполнении можно указывать эти группы

:!: Пример файла инвертори

./inventory/hosts.yaml

all:
  children:
    myGroup:
      vars:
        myVariable1: value
        myVariable2: value
        myVariable3: value
      hosts:
        alias1: 
          ansible_host: 0.0.0.0
        alias2: 
          ansible_host: 1.1.1.1
        alias3: 
          ansible_host: 2.2.2.2

Непонятки с организацией этого инвентаря, полезная команда «ansible-inventory -i hosts.yaml –list» для отладки

Далее в коде доступны эти хосты и набор переменных к каждому ./test.yaml

...
with_items: "{{ groups['myGroup'] }}" # Применить таску ко всем хостам из группы
 
"{{ hostvars[item] }}" # Элемент группы, хост
"{{ hostvars[item][myVariable1-4] }}" # Во вложенном массиве доступна вся инфа о хосте, в т.ч. набор переменных из инвентори, персонализированный получается

Roles, роли используются для разделения плейбука на части, и организации файлов. Для роли создается каталог, технически структура файлов может быть любой, но есть соглашение об конкретной организации файлов, что добавляет универсальности и порядка.
Создание происходит автоматически, командой $ ansible-galaxy init role-name
Особенность в том что роли могут быть вложенными т.е. составлять цепочку выполнения

Все переменные в ансибл глобальные, но есть замороченная система уровней, которая как то работает, и есть куча нюансов, так что с именованием нужно быть аккуратнее
Хороший путь ансибл это максимально простое и линейное описание последовательного процесса, по возможности стоит максимально исключить условия, циклы и прочую логику из конфигов, лучше написать 10 тривиальных строк вместо одной «кучерявой»

Шаблоны нечто иное как использование переменных типа { { inventory_hostname } } (двойные скобки вместе), это собсна и есть «jinja2»- система шаблонов для python

notify обработчик, который будет вызван в случае успешного выполнения задачи
handlers описание обработчика, который может быть вызван по имени

ansible.cfg основной конфиг

:!: Пример

Тут есть более полное описание

[defaults]
# Используемый инвентори
inventory = ./myhosts
 
# Чтобы убрать предупреждение об автопоиске питона
interpreter_python = auto_silent
 
# Подключаемый пользователь
remote_user = anuser
 
# Отключение подтверждения нового ssh ключа
host_key_checking = False
 
# Отключение сбора фактов
gathering = explicit

Использование

Созданный на хосте пользователь должен быть судошным без ввода пароля, либо нужно вводить пароль при выполнении заданий

Yaml файл начинается с директивы «—« (три тире), обозначает начало очередного файла

Установка

# apt install ansible
# yum install epel-release && yum install ansible

Общее

Исполнения

По умолчанию ансибл выполняет все команды на хостах, указанных в параметре «hosts», со всеми вытекающими, ресурсы/зависимости и т.д.
Выполнение можно делегировать на другой хост в т.ч. на локальный, («delegate_to: localhost» и «local_action» одно и тоже, но синтаксис разный)

При делегировании возможно переменные указывают на делегированный хост, а не на инвентори, хотя тут неясно. Есть еще вариант указания «connection: local», отличий вроде нет

Во всех случаях таска выполнится столько раз сколько хостов указано, можно указать «hosts: 127.0.0.1» тогда выполнится один раз
И кстати нормально, при таком варианте инвентори и все хосты из него доступны, ничего не подменивается

Так же есть директива «run_once» для однократного выполнения на первом хосте из доступных

---
- hosts: webservers
  #connection: local
  tasks:
    - name: Take out of load balancer pool
      ansible.builtin.command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
      delegate_to: 127.0.0.1
      
    - name: Take out of load balancer pool
      local_action: ansible.builtin.command /usr/bin/take_out_of_pool {{ inventory_hostname }}    

    - name: Send summary mail
      local_action:
        module: community.general.mail
        body: "{{ mail_body }}"
      run_once: True

Циклы

Дока

loop, with_item, until, первый замена второму, with_item уже выводится из использования
кстати говоря может быть with_<много вариантов> (list/dict и т.д.)

По умолчанию обход выполняется просто по хостам из инвентаря, массив хостов- «hostvars[inventory_hostname][…]«

:!: Перебор хостов из инвентаря

Инвентарь

all:
  children:
    loctest:
      vars:
        zabbix_agent_server: 10.10.40.204
        zabbix_url: http://10.10.40.204:800
        zabbix_api_use: true
        zabbix_host_status: enabled
      hosts:
        one: 
          param_name: 10.10.40.204
        two: 
          param_name: 1.1.1.1
        three: 
          param_name: 2.2.2.2

Обработка

---
  - name: Test play
    hosts: loctest
    gather_facts: False
    tasks:
      - name: check
        delegate_to: 127.0.0.1
        ansible.builtin.debug:
          msg:
          - "{{ hostvars[item]['zabbix_interface_ip'] }}" (либо {{ item }})
        loop: "{{ groups['loctest'] }}"
:!: или так

Инвентарь

all:
  children:
    cl_autotest:
      hosts:
        S221AUTOTEST:
        S222AUTOTEST:
    cl_halftest:
      hosts:
        S201:
        S207:
    cl_sib:
      hosts:
        S202:
        S203:

Обработка

---
  - name: Show List Inventory
    hosts: 127.0.0.1
    gather_facts: False
    tasks:
      - name: Groups
        ansible.builtin.debug:
          msg: "{{ item }}" # или без цикла, сразу список "{{ groups | list }}"
        loop: "{{ groups | list }}"
        
        msg: "{{ groups | select('match', '^cl_.*') | replace('cl_', 'GSC_') }}"
        # Еще есть вариант фильтрации (reject работает наоборот)
        "..| reject('match', '^value2$|^value2$') |.."
 
  # Еще варианты перебора и отображения инвентаря, тут передан параметр --limit для фильтрации хостов
- name: Print
  #vars:
  #  cluster_group: "{{ group_names | select('match', '^cl_.*') }}"
  ansible.builtin.debug:
    msg:
      #- "{{ hostvars[inventory_hostname] }}"
      #- "{{ inventory_hostname }}"
      #- "{{ groups['cl_test-cluster'] }}"
      #- "{{ group_names | select('match', '^cl_.*') }}"
 
      #- "{{ groups[ansible_limit] }}"
      - "Host name is - {{ hostvars[item]['host_name'] }}"

  loop: "{{ groups[ansible_limit] }}"

Переменные

Дока
«Магические» переменные типа hostvars, groups, group_names, inventory_hostname, ansible_limit

  # Распечатать инфу хоста
ansible myhost -m setup
ansible myhost -m setup -a "filter=ansible_cmdline"
 
  # Или в плейбуке
- name: "Print facts"
  ansible.builtin.debug:
    msg:
      - "{{ ansible_facts }}"
      - "{{ ansible_facts["processor"] }}"

Результат выполнения

- name: Execute against dev
  shell: 'echo "dev"'
  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: "Use"
  ansible.builtin.debug:
    msg: "{{ cmd_dev_out }}"

Условие выполнения

when - выполнять таску если условие выполняется
Применяется очевидно только к таскам

:!: Примеры
- name: Checking that required variables are set
  fail: msg="{{ item }} is not defined"
  when: item not in vars
  loop:
    - win_zbx_path
    - win_repo

- name: Run with items greater than 5
  ansible.builtin.command: echo {{ item }}
  loop: [ 0, 2, 4, 6, 8, 10 ]
  when: item > 5*
 
- name "dcdc"
  when: condition1 == "condition1" or condition2 == "condition2"
 
- name "fvfv"
  when: 
    - sshkey_result.rc == 1
    - github_username is undefined or 
      github_username |lower == 'none'
 
   (...)
   when: hostvars[item]['my_variable'] is defined

Инфо о хосте

ansible_facts - содержит множество данных о целевом хосте
Занимает время при каждом выполнении, можно отключить в таске либо в конфиге, «gather_facts: False»

ansible 10.11.193.43 -m setup
ansible 10.11.193.43 -m setup -a 'filter=facter_*'
ansible 10.11.193.43 -m setup -a 'gather_subset=!all,!any,facter'
ansible all -m debug -a "var=hostvars[inventory_hostname]"
- name: Collect only facts returned by facter
  ansible.builtin.setup:
    gather_subset: !all,!facter,!ohai,network
 
{{ ansible_facts['devices']['xvda']['model'] }}
 
{{ hostvars['myHost']['ansible_facts']['os_family'] }}

Манипуляции с текстом

Дока

:!: Вывод/обработка списка

Инвентори или group_vars:

mylist:
  - cl_first
  - cl_second
  - cl_three
  - cl_four

Простой вывод списка, заменяя префикс

---
  - name: Test play
    hosts: 127.0.0.1
    tasks:
      - name: check
        debug:
          msg: 
            - "{{ mylist | replace('cl_', 'GSC ') }}"
            - "{{ list1 | difference(list2) }}"
            - "{{ list | select('match', '^prefix.*') | reject('match', '^bad1$|^bad2$') | list }}"

Работа с группами инвентори

  # Перечень групп (развернут с хостами)
{{ groups }}
 
  # Содержимое конкретной группы
{{ groups['<имя-группы>'] }}
 
  # Перечень без развертывания
{{ groups.keys() }}
 
  # Тоже без развертывания
{{ groups | list }}
 
  # Группы в которые входит хост выполнения
{{ group.names }}

Аргументы/Параметры

  • -b [become] - выполнять с повышенными привилегиями
  • [roles] - список ролей применяемые для плейбука
  • -i - каталог с инвентори
  • -a - аргументы
  • -l (–limit) - группа/хост для выполнения указанного задания

Vault

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

# Зашифровать файл
ansible-vault encrypt 'path_file'
 
# Расшифровать файл
ansible-vault decrypt 'path_file'
 
# Зашифровать строку
ansible-vault encrypt_string 'string'
 
Переменная среды: ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt\\
Ключ для запроса в cmd: --ask-vault-pass
Ключ для указания в  cmd: --vault-password-file

Ограничения запуска

Указывая хост (или группу) можно ограничить те места, откуда будет выполняться задача, в блоке «hosts» при этом должна быть указана родительская группа, «all» например, иначе ошибка аля «not found target»

ansible-playbook mybook.yml --limit <group[host]_name>
ansible <group[host]_name> -m ping

Работа с файлами

Как минимум три модуля:

  • lineinfile - добавить, заменить или удалить одну строку
  • replace - добавить, заменить или удалить несколько строк
  • blockinfile - добавлять несколько строк, окруженных маркерами

blockinfile

Дока
Вставляет блок текста, соблюдая строки
Можно указать регулярками (либо конец файла) после чего (до чего) вставлять блок, что то одно !!!

Работает прежде всего с блоками текста, сам текст указан в «block», обрамление в «marker» (директива »{mark}« подставляет слова BEGIN/END в метке)
С блоками работает нормально, проверяет наличие, если изменений нет, то пропускается, если есть, то обновляет текст, если указать в block пустую строку, то блок удалится вместе с метками

- name: "Запись в файл hosts"
  ansible.builtin.blockinfile:
    #become: yes
    #become_method: sudo
    #become_user: root
    path: /tmp/hosts-test
    block: |
      2.2.2.2 two
      3.3.3.3 three
      4.4.4.4 four
    marker: "{mark} Gameservers from ansible inventory"

replace

Дока
Поинтереснее, но все же заточен на построчную поиск/замену
Указав «любой символ» работает с каждым найденным словом как с отдельным элементом, причем даже пробелы не щадит(
Для замены собсна тоже принимает строку

- name: "Запись в файл"
  ansible.builtin.replace:
    path: /tmp/hosts-test
    after: "# Start gameserver hosts"
    before: "# End gameserver hosts"
    #regexp: '^1.1.(.+)$'
    #replace: '11.11.11.11'
    regexp: '.*'
    replace: '11.11.11.11'

Фильтрация списков словарей

  • *selectattr / rejectattr - возвращает весь элемент по указанному условию * map - вырезает только значения указанных аттрибутов, по одному аттрибуту из всех подходящих элементов * ** -

selectattr / rejectattr

Есть нюанс тогда когда указанный для фильтрации ключ есть не во всех элементах. Указанный по ссылке пример в итоге возвратит два списка, один с установленным аттрибутом, второй без аттрибута.

Условия для поиска могут быть разными «equalto/match/search» и т.д.

  # Так возвращает элемент (весь элемент словаря) у которого установлен аргумент в указанное значение
    # "('origin1', 'none')" - для поиска пустого значения 
"{{ fruit | selectattr('origin1', 'equalto', '21') }}" 
 
  # "selectattr('origin1', 'undefined')" - Для поиска именно неустановленного аттрибута
"{{ fruit | selectattr('origin1', 'undefined') }}"

map

  # Из общего списка словарей вернет только элементы по регулярке, далее покажем только значение только одного аттрибута, всех этих элементов
"{{ fruit | selectattr('origin1', 'match', '^..$') | map(attribute='origin1') }}"

Преобразования типов данных

Дока

dict2items,items2dict,combine,zip и т.д.

Примеры

Zabbix

Для работы нужен «zabbix-api», плюс ансибл работает со своей версией питона

/usr/bin/python3.8 -m pip install zabbix-api
ansible-galaxy collection install community.zabbix
:!:
 

OverAll

:!: Минимальный стартовый пример

hosts, можно короче

all:
  hosts:
    192.168.0.101

test.yaml

---
- hosts: all
  tasks:
    - name: Test ping
      delegate_to: 127.0.0.1
      ping:

+ в конфиге еще путь к инвентори

:!:
 
ansible.1665333610.txt.gz · Последнее изменение: 2022/10/09 16:40 — admin