Перейти к основному содержимому

Бест-практисы Ansible

·1052 слов·5 минут
гайды
Юрий Семеньков
Автор
Юрий Семеньков
DevOps, tech, geek, mentor
Оглавление

В своей текущей работе я очень часто использую Ansible:

  • раскладываю конфигурации Nginx на серверах,
  • управляю пользователями
  • настраиваю серверы
  • управляю конфигами Hadoop и Solr кластеров
  • и многое другое.

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

Но не без минусов, конечно. Например, на больших объемах серверов и заданий Ansible становится довольно медлительным и решение подобных проблем становится очень индивидуальной болью. Зачастую приходится переписывать роли, менять порядок выполнения заданий, тюнинговать SSH подключения.

За время работы я сформировал несколько хороших практик, которыми хочу поделиться с вами.

✍️ Используй FQCN
#

- name: Ensure the directory is created
  ansible.builtin.file: <---
    path: /tmp/directory
    state: directory

Модули, которые мы вызываем в Ansible хранятся в коллекциях. FQCN — fully-qualified collection names, это как полное доменное имя, только для модулей ансибла. А точнее оно указывает из какой коллекции взят требуемый модуль.

Ansible сейчас поставляется в двух вариантах, которые мы можем установить:

ansible-core - только исполняемые файлы ansible, дополнительные коллекции ansible community - это ansible-core вместе с пакетом стандартных коллекций, которых чаще всего достаточно для большинства задач. Именно это мы уставливаем при pip install ansible.

Разработчики рекомендуют всегда указывать названия модулей вместе с названиями коллекций для упрощения обращений к документации, соответствию общепринятому стилю кода и.. чтобы ansible-lint не ругался

🗂️ Описывай переменные в host_vars и group_vars
#

Мы часто используем различные переменные. Например, мы можем на уровне инвентори указать, что на сервер gateway-01 мы хотим установить Java версии 8, а на supply01 — Java 11. Или указать нестандартный путь к логам для сервиса sausage-store-backend.

❯ tree inventories/
inventories/
├── group_vars
│   ├── dev.yml        <~ здесь — переменные для группы dev
├── host_vars
│   ├── gateway-01.yml <~ здесь — переменные для конкретных хостов
│   ├── landing-01.yml
│   ├── prod-01.yml
│   ├── supply01.yml
│   └── web-01.yml
└── hosts.yml          <~ здесь — только хосты

Да, мы можем описать переменные прямо в общем inventory-файле. И на это можно закрыть глаза, если у нас всего 2-3 хоста, но это плохая практика, которая сильно усложнит поддержку инвентаря при расширении инфраструктуры.

Так же в group_vars или host_vars можно создать директорию с названием хоста или группы (прямо как в инвентори), а внутрь положить отдельные файлы с переменными, для лучшей организации хранения переменных:

inventories/group_vars/dev/db_settings
inventories/group_vars/dev/cluster_settings

🤔 Помни, что переменные не мержатся, а заменяются
#

В дополнение к предыдущему пункту хочу просто напомнить, что одинаковые переменный из разных файлов не сливаются, а заменяются. Например, у вас есть переменная-список users в файле `group_vars/dev.yml``:

❯ cat inventories/group_vars/dev.yml
users:
  - vpupkin
  - ppetrovic

А рядом лежит такая же переменная, но с другим списком и в другом файле `host_vars/supply01.yml``:

❯ cat inventories/host_vars/supply01.yml
users:
  - iivanov
  - kpomoev

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

А какой приоритет? От наименьшего к наибольшему:

  • all group (because it is the ‘parent’ of all other groups)
  • parent group
  • child group
  • host

Финальной переменной будет список из файла host_vars/supply01.yml. Вот раздел документации описывающий это — ссылка.

☢️ Не используй shell и command
#

Основная затея Ansible (как и вообще подхода infrastructure as code) — это описание целевого состояния системы в виде кода. Также Ansible — это про идемпотентность. Это когда повторный запуск задания не принесет никаких изменений, то есть приведет к тому же самому состоянию.

Если мы прокатим наш плейбук второй, третий, десятый, сотый раз — ничего не изменится, потому что мы описали там целевое состояние. Например указали что файл foobar.txt должен присутствовать в директории (state: present), пакет ncdu должен быть установлен, а строка XYZ должна быть в файле /tmp/foobar. Повторный прокат плейбука не создаст нового файла, повторный прокат не добавит новую строку. За этим следят встроенные модули file, copy, lineinfile, apt.

Да, у модулей shell/command есть параметр, который позволяет не выполнять команду, если на сервере, к примеру, есть определенный файл. Но, в целом, они не следят за состоянием системы. Просто выполняют то что сказано. Не приводят к целевому состоянию.

Понятно, что простой shell: ls -lah никому не навредит, но более сложные команды - могут. Вот например запуск скрипта для установки nodejs.. что там делается.. кто будет следить за статусом выполнения…

Старайся максимально избегать использования command и shell модулей на столько на сколько это возможно. Большинство задач можно решить тем, что уже создано для Ansible и будет контролировать состояние задания.

🌚 Не перебарщивай с переменными
#

Есть множество ролей на GitHub, в которых файлы с заданиями буквально на 70% состоят из фигурных скобок и переменных. Это позволяет многие параметры роли сделать настраиваемыми пользователем. Но стоит смотреть правде в глаза — это визуально усложняет поддержку роли, а я уверен, что нужно стараться поддерживать свои инструменты максимально возможно простыми.

🏎️ Тюнингуй ansible.cfg
#

Даже простой тюнинг конфигурационного файла можно довольно сильно ускорить выполнение твоих плейбуков. Только будь осторожен с `strategy = free``, потому что такой режим позволяет выполнять следующую таску не дожидаясь пока предыдущая выполнится на другом хосте.

Вот пример базового тюнинга конфигурации Ansible.

[defaults]
host_key_checking=False
pipelining = True
strategy = free
ansible_ssh_private_key_file=~/.ssh/id_rsa
ansible_python_interpreter=/usr/bin/python3
callbacks_enabled = timer, profile_tasks, profile_roles
forks = 30

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
retries=3

А вот — документация.

Можно попробовать еще установить плагин Mitogen, который меняет способ взаимодействия Ansible и SSH.

🤐 Никаких кредов в файлах
#

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

Записываем пароль в файл, а затем выполняем команду, которая зашифрует файл целиком:

ansible-vault encrypt --vault-password-file ~/vault.pass private-key.crt

А можно зашифровать только одну переменную. Вводим команду и передаем ей наш пароль и название переменной:

ansible-vault encrypt_string --vault-password-file ~/vault.pass 'SECRET' --name VARIABLE
s3cmd_secret_key: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          33663339333062616634353663636237396336396434326538316335623062383535393736643937
          3738623538373438373962333631386366623166393934660a363931373165336462633361373835

🕵️‍♂️ Применяй линтер
#

Очень интересные вещи можно узнать про себя просто запустив ansible-lint по всем своим файлам, например:

❯ ansible-lint -p roles
.......
Finished with 305 failure(s), 126 warning(s) on 429 files.

Он тоже настраивается и часть проверок можно отключить.

🧑🏻‍💻Пользуйся handlers
#

Если тебе нужно перезапускать systemd-сервис не нужно делать это при каждом прогоне плейбука. С помощью handlers можно настроить перезапуск сервиса только в определенном случае, например, при изменении конфигурационного файла.

- name: Solr_exporter | daemon-reload
  ansible.builtin.systemd:
    daemon_reload: true

- name: Public_solr_exporter | restart
  ansible.builtin.systemd:
    name: public_solr_exporter
    daemon_reload: true
    state: restarted
    enabled: true

💁‍♂️ Вот такой набор советов получился. Прокомментировать статью, поделиться идеями, поболтать и задать вопрос можно в 👉 телеграм-чате, а так же обязательно подписаться на 👉 телеграм-канал!

Related

Мониторинг SSL сертификатов в Zabbix
·843 слов·4 минут
гайды
Сканер открытых портов в Raycast
·417 слов·2 минут
софт гайды
Split DNS в MacOS, OpenVPN и Tunnelblick
·592 слов·3 минут
гайды софт