Лучшие практики Ansible: часть 2

Лучшие практики Ansible: часть 2

by moiseevrus

Ansible делает простые вещи простыми, но более сложные вещи могут заставить вас почесать голову, когда вы начинаете свое путешествие с Ansible. Вот несколько советов, которые могут помочь вам избежать некоторых из этих вещей.

Ансибль

Для выбора Ansible в первую очередь в первой части этой серии блогов есть несколько рекомендаций. С этого момента я предполагаю, что вы уже используете Ansible для чего-то. Вам не обязательно знать Ansible глубоко, прежде чем переходить к тексту ниже, но полезно знать немного YAML и основы.

К счастью , в документации Ansible есть необходимая информация . Документы также содержат раздел с рекомендациями .

У нас есть довольно много земли, чтобы покрыть, так что поехали!

Начиная

Как упоминалось в первой части этого блога, вы можете установить Ansible, что означает, что вы также можете довольно хорошо контролировать версию. Однако среды Python могут получить, поэтому, если это вообще возможно, используйте и virtualenv или управляйте версиями своих инструментов другими способами.

Недавно я применил подход, при котором я пишу оболочку и файл Dockerfile, чтобы обеспечить согласованность инструментов на ноутбуках людей и CI/CD. Это работает очень хорошо. Расширение Visual Studio Code Remote Containers также удобно.

Можно также использовать менеджеры пакетов, такие как apt и yum, но тогда вы застрянете с любой версией в репозиториях дистрибутива. Попробуйте получить хотя бы версию 2.8. Версия 2.7 устарела , так как выпущена версия 2.10, и вам не хватает критических исправлений ошибок и множества новых вещей. Версии до 2.7 безнадежно устарели. Огромное количество новых вещей было представлено после того, как RedHat приобрела проект в 2015 году.

Обработка зависимостей

Храните свои плейбуки, роли, модули и плагины Ansible в системе контроля версий. Сюда входят любые сторонние роли зависимостей, которые вы подключаете с помощью ansible-galaxy . В противном случае Ansible будет использовать любые версии, найденные в roles_path . Который может быть или не быть тем, который вы указали в файле requirements.yml !

Однако это может привести к дублированию, если вы запускаете несколько проектов Ansible на одном компьютере, и они зависят от одних и тех же ролей. Действуйте осторожно, так как в этом случае ад зависимости также является реальной проблемой. Моя главная мысль здесь заключается в том, что вы должны думать о том, как вы справляетесь с зависимостями. В конце концов, это инфраструктура как код, поэтому многие вещи, о которых вам нужно думать с помощью реального кода, теперь применимы и к вашей инфраструктуре. Но вы также получаете те же преимущества!

Зависимости ролей также можно указать в файле meta/main.yml роли, но это приводит к путанице в порядке выполнения и приоритете переменных. Эти роли автоматически импортируются во время запуска playbook. Лучше сделать импорт явно с помощью import_role .

Ансибл Галактика

Инструмент зависимостей Ansible Galaxy работает аналогично pip, поэтому, если у вас есть опыт работы с ним, вы знаете некоторые болевые точки. Он извлекает указанные роли напрямую из системы контроля версий, чаще всего с GitHub. Вы действительно хотите установить эти конкретные версии для использования, так как основная ветвь может включать изменения, которые нарушают вашу инфраструктуру.

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

Теперь, когда коллекции Ansible набирают обороты, важность управления зависимостями и их версиями становится еще более важной, поскольку вы будете обрабатывать модули и плагины одинаковым образом.

Организация проекта

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

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

├── ansible.cfg
├── group_vars
│ ├── all
│ │ └── our-vault-secrets.yml
│ └── webservers
│ └── apache-configs.yml
├── inventory.ini
├── master-playbook.yml
├── playbook.yml
├── requirements.yml
├── roles
│ ├── apache
│ │ ├── handlers
│ │ │ └── main.yml
│ │ └── tasks
│ │ ├── configure.yml
│ │ ├── install.yml
│ │ ├── main.yml
│ │ └── service.yml
│ ├── example
│ │ └── tasks
│ │ └── main.yml
│ └── yet-another
│ └── tasks
│ └── main.yml
└── webservers.yml

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

Управление запасами

В зависимости от вашей среды может быть полезно переместить инвентаризацию в отдельный каталог вместе с соответствующими файлами group_vars. Вы также можете работать с несколькими запасами , если это необходимо.

Используйте динамические запасы там, где это целесообразно. Либо среда является динамической, либо у вас уже есть система, которая управляет инвентаризацией серверов и оборудования. Однако статические инвентаризации в формате INI или YAML вполне подходят. INI немного проще для чтения, но не так хорошо работает с переменными , как YAML . Но вы в любом случае должны держать свои переменные вне статического инвентаря. Мы обсудим организацию переменных более подробно позже.

Погружение в реализацию

Начать с написания сборников игр для достижения цели — это быстрый способ начать. Но не забудьте быстро перейти к ролям. Роли обеспечивают такие преимущества, как модульность и возможность повторного использования. Роли можно тестировать изолированно. Роли также легче перемещаются между средами. Однако это немного изменилось с появлением коллекций Ansible. Роли похожи на модули Terraform, или вы можете думать о них как о классе или библиотеке.

Преимущества ролей

Они действуют как своего рода уровень абстракции и помогают вам поддерживать порядок. Если плейбук — это команда apt-get install apache2, то роль — это сам пакет .deb.

Продолжая этот аналог управления веб-сервером, представьте себе роль с именем apache, она управляет всем, что с ней связано:

  • настройка репозитория
  • установка
  • создание конфигурационного файла
  • запуск службы
  • перезапуск во время изменений

Фактическое использование осуществляется через playbook под названием webservers.yml, который импортирует apacheроль для обработки вышеперечисленных вещей.

Нам нужен HTTPS, поэтому давайте сделаем это, используя роль, вызываемую letsencryptдля получения сертификата для использования Apache. Правилами брандмауэра можно управлять с помощью роли iptables, которая позволяет пропускать трафик HTTP и HTTPS на веб-сервер.

Теперь у нас есть три роли, которые объединены в один плейбук для управления нашими веб-серверами. Роли напрямую не зависят друг от друга, поэтому iptablesвполне могут использоваться для открытия портов для SQL-серверов, а letsencryptтакже для получения сертификатов для HAProxy.

Многоразовое использование для победы!

При использовании ролей из плейбуков используйте import_roleили include_roleзадачу, а не более старое rolesключевое слово. Последнее затруднит обработку порядка выполнения ролей с другими задачами, set_factкоторые у вас, вероятно, будут, несмотря на то, что вы уже реализовали все в ролях. Вы также захотите, чтобы роли были слабо связаны и ограничивали зависимости от одной роли к другой. Плейбуки можно использовать, чтобы совмещать множество ролей для достижения целого.

Роль должна быть как можно более простой и концентрироваться на чем-то одном. Для универсальной роли, подобной приведенной выше apache, следует следовать соглашению, а не настройке . Вы не хотите раскрывать каждую ручку конфигурации Apache пользователям вашей роли.

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

Выбор сторонних ролей

В начале у вас может возникнуть соблазн использовать множество сторонних ролей с помощью ansible-galaxy, особенно если вы управляете частью программного обеспечения, которое вы на самом деле не знаете наизусть. Но качество доступных ролей немного непостоянно. Рейтинги и количество загрузок в Ansible Galaxy дают некоторое представление, но важно копнуть немного глубже, прежде чем отказываться от роли в requirements.yml. Некоторые из опубликованных ролей могут хорошо работать для их создателей, но следовать соглашениям, которые не работают для вас.

Например, хорошо написанную роль, которая имеет только один файл задач, main.ymlтрудно изменить, если вы хотите изменить порядок задач. Для дополнительной помощи Джефф Герлинг написал пост об оценке ролей в сообществе.

Playbooks: включает, импортирует и теги

Плейбуки могут быть организованы по-разному. Они могут быть связаны с группой, например, как указано webservers.ymlвыше, или связаны с жизненным циклом, restart-apache.ymlили для конкретных ситуаций, таких как fix-heartbleed.yml.

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

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

Создавайте явные плейбуки и роли с явными и отдельными файлами задач и сохраняйте здравомыслие на долгие годы. Группировка наборов задач внутри роли в отдельные файлы задач также повышает возможность повторного использования. Вы можете выполнять набор задач несколько раз с разными переменными.

В качестве примера, вот файл задачи из iptablesроли, используемой несколькими способами:

# roles/example-iptables/tasks/rules.yml
- name: Create iptables rules
  become: true
  iptables:
    comment: "{{ item.comment | default(omit) }}"
    action: "{{ item.action | default(omit) }}"
    rule_num: "{{ item.rule_num | default(omit) }}"
    table: "{{ item.table | default(omit) }}"
    chain: "{{ item.chain | default(omit) }}"
    source: "{{ item.source | default(omit) }}"
...
    protocol: "{{ item.protocol | default(omit) }}"
    match: "{{ item.match | default(omit) }}"
    jump: "{{ item.jump | default(omit) }}"
    policy: "{{ item.policy | default(omit) }}"
  loop: "{{ iptables_rules }}"
  notify: iptables save

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

- hosts: all
tasks:
- name: Install iptables and configure defaults
import_role:
name: example-iptables
vars:
iptables_rules: "{{ example_default_iptables_rules }}"
---
- hosts: webservers
tasks:
- name: Create iptables rules for HTTP
include_role:
name: example-iptables
tasks_from: rules
vars:
iptables_rules:
- chain: INPUT
protocol: tcp
destination_port: 80
jump: ACCEPT
comment: Accept HTTP
- chain: INPUT
protocol: tcp
destination_port: 443
jump: ACCEPT
comment: Accept HTTPS

Все дело в переменных

Переменные по существу являются глобальными в Ansible. Есть некоторые области видимости, но в основном вы можете относиться к ним как к таковым. Переменные также являются одной из самых сложных вещей для правильного понимания. Сначала они кажутся достаточно простыми, но, глядя на довольно длинную документацию по этому вопросу , вы заметите, что в какой-то момент они могут усложниться.

Исходя из некоторого опыта, переменные проще, чем атрибуты Chef и его двухпроходная модель выполнения, так что по большей части все в порядке. 🙂

Я предлагаю использовать пространство имен для ваших переменных. Короче говоря, использование одной и той же versionпеременной как в версии пакета в apacheроли, так и в версии OpenSSL в fix-heartbleed.ymlнаборе group_varsне будет работать.

Если вы смешиваете и сопоставляете сторонние роли с вашими собственными, добавление названия компании или какого-либо другого известного префикса также поможет отличить их. example_apache_package_versionхотя и длиннее, с первого взгляда понятнее, чем apache_version. По крайней мере, используйте эту последнюю версию. Не каламбур.

Для зашифрованных переменных Ansible Vault полезно добавить префикс или суффикс, чтобы определить, откуда берется фактическое значение. Итак, если у роли есть входная переменная с именем « mysql_root_password", вы захотите зашифровать и сохранить ее как « vault_mysql_root_password".

Затем передайте это среди других связанных переменных:

mysql_package_version: "5.7.31-0ubuntu0.18.04.1" 
mysql_config_file: /etc/mysql/our-special-config.cnf 
mysql_root_password: "{{ vault_mysql_root_password }}"

Куда ставить переменные?

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

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

Я обычно стараюсь придерживаться этих (в порядке возрастания приоритета):

  1. по умолчанию / в роли
  • Читать без особых задач автоматически
  • Хорошее место для документирования входных переменных роли с разумными значениями по умолчанию.

2. group_vars/

  • Обычный подозреваемый при выяснении значения переменной в любой заданной среде и группе серверов.
  • Использование host_vars/ только в случае крайней необходимости

3. vars:поставить задачу

  • В основном для динамических включений, при многократном вызове одной и той же include_task/include_role с разными входными данными.
  • Также полезно для ясности в templateмодуле, чтобы передать некоторые измененные переменные в файл шаблона, сохраняя при этом большую часть логики за пределами шаблона.

4.set_fact:

  • Для более динамичных вещей/определений переменных, собранных во время выполнения
  • Например, для json_queryнекоторой переменной среды, которая находится в «неправильном» формате.

Написание задач

Задачи не должны оставаться без названия. В основном это связано с тем, как работает вывод Ansible по умолчанию. Во время бега ansible-playbookвы будете читать многие из этих строк, так что хорошо, что они рассказывают, что делают. Есть некоторые исключения: include_roleinclude_tasksи их эквиваленты импорта обычно достаточно ясны как в реализации, так и в выводе.

Рассмотрим эту пьесу:

- hosts: webservers
tasks:
- package:
name: apache2

Читая реализацию задачи, вы можете сделать естественный вывод, о чем она, даже без названия задачи, но ее вывод совершенно не ясен:

TASK [package] *****************************************************************
changed: [example]

Глядя на это, вы бы не поняли, каким пакетом управляли, не включив чрезмерное количество отладки.

Сравните это с этим:

- hosts: webservers
tasks:
- name: Install Apache
package:
name: apache2

И вывод:

TASK [Install Apache] **********************************************************
changed: [example]

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

roles/apache/
├── defaults
│ └── main.yml
└── tasks
├── install.yml
└── main.yml

Файл задачи:

# roles/apache/tasks/install.yml
- name: install | Ensure package state
package:
name: "{{ example_apache_package_name }}"
state: "{{ example_apache_package_state }}"

И вывод:

TASK [include_role : apache] ***************************************************TASK [apache : install | Ensure package state] *********************************
changed: [example]

Теперь в приведенном выше вы видите роль, реализующую задачу. Добавляя короткий префикс, вы видите имя файла задачи installи саму задачу, которая действительно обрабатывает состояние пакета.

Чего не хватает в приведенных выше примерах, так это использования become. Become — это ваш sudo-эквивалент, но работает кроссплатформенно. Он используется для указания задач, которые необходимо запускать с правами администратора. Довольно распространенная вещь, учитывая, что вы обычно устанавливаете, настраиваете и запускаете службы с помощью Ansible.

Я обычно becomeчетко устанавливаю каждую задачу, которая требует этого. Это понятнее, документирует задачи, требующие root-доступа, не заставляет пользователя использовать --becomeкомандную строку или более глобальные "become"сценарии в плейбуках.

Я признаю, что это немного утомительно, но оно того стоит, когда команда безопасности начинает спрашивать, почему все работает как root.

Вернуться к переменным

Кроме того, благодаря использованию переменных в задаче у вас внезапно появляется распределяемая роль для Apache, которая может установить правильный пакет как в системах на основе Debian, так и в системах на основе RedHat, поскольку имена их пакетов различаются. Он также может удалить пакет, указав absentсостояние пакета.

Итак, очень быстро мы перешли от одноразового сценария к роли, которая обратно совместима и может использоваться повторно!

Не забудьте указать разумные значения по умолчанию для переменных вашей роли. example_apache_package_stateбыло бы естественно, presentи вещи, специфичные для операционной системы, могли бы обрабатываться через vars/подкаталог и включать файл на основе собранного факта:

# roles/apache/tasks/variables.yml
- name: variables | Read distribution-specific vars
include_vars: "{{ ansible_distribution }}.yml"

Обратите внимание, что include_varsпользователь вашей роли не может переопределить переменную, указав ее «обычным способом», т.е. в group_vars, как include_varsприоритет. Это может привести к некоторой путанице и дополнительной сложности при обработке переменных. Для имени пакета в конкретных переменных дистрибутива, include_varsвероятно, было бы хорошо, но состояние — это то, что вы хотите, чтобы конечный пользователь роли легко контролировал.

Сами переменные обычно должны быть одномерными. Ansible поддерживает списки и словари, но могут возникнуть проблемы с глубоко вложенными переменными. Если ваша конфигурация представляет собой файл dict, и вы хотите изменить одно значение, вы должны заменить все это. Параметр конфигурации hash_behaviour также влияет на то, как dictsони обрабатываются. По умолчанию Ansible переопределяет предыдущие значения любыми предыдущими, которые он находит.

Пример в списках, когда вы group_vars/all/monitoring.ymlуказываете вещи для мониторинга:

example_monitoring_metricbeat_modules:
- module: apache
metricsets:
- status
period: 1s
hosts:
- http://127.0.0.1/
- module: mysql
metricsets:
- status
period: 2s
hosts:
- root@tcp(127.0.0.1:3306)/

Если для одного хоста или группы вам нужно заменить номер порта для MySQL, вам нужно определить весь example_monitoring_metricbeat_moduleзаново. Кроме того, часть, связанная с Apache!

Способ сделать это – использовать переменные внутри переменных. Вот так:

- module: mysql
metricsets:
- status
period: 2s
hosts:
- "root@tcp((127.0.0.1:{{ example_monitoring_mysql_port }})/”

Который будет работать до тех пор, пока вам не понадобится добавить целый модуль в список модулей для мониторинга с помощью Metricbeat.

Но выгода от one dictв этом случае будет заключаться в том, что собственная конфигурация Metricbeat — это YAML , поэтому вы можете просто поместить эту переменную в фильтр {{ example_monitoring_metricbeat_modules | to_nice_yaml }}и быть довольным.

Поэтому важно найти баланс между простотой настройки и простотой управления переменными.

Фильтры

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

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

В качестве примера соберем всех наших SQL-клиентов из групп для iptablesроли:

- name: Set iptables rules for SQL clients
  set_fact:
    sql_client_rules: >
      {{ groups.backend | map('extract', hostvars)
         | list | json_query(get_sql_clients) }}
  vars:
    get_sql_clients: >
      [?backend_is_sql_client].{
        comment: join(' ', ['Allow SQL traffic from', inventory_hostname]),
        protocol: 'tcp'
        source: ansible_host,
        destination_port: '3306',
        jump: 'ACCEPT',
        chain: 'INPUT'
      }- include_role:
    name: example-iptables
    tasks_from: rules
  vars:
    iptables_rules: "{{ sql_client_rules }}"
```

Пример немного запутан, но в основном он просто извлекает hostvarsвсе внутренние серверы, выбирает те, которые используют SQL, и получает необходимые переменные: inventory_hostname и ansible_host, а затем создает красивую строку комментария с помощью функции jmespath join () . Вы могли бы добиться того же с некоторыми другими задачами, но мне нравится его мощь в манипулировании данными.json_query

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

Но обычно правильным решением в таких случаях является рефакторинг переменных, чтобы вам не приходилось беспокоиться о слиянии заказов. Майкл ДеХаан, первоначальный разработчик Ansible, несколько лет назад задал соответствующий вопрос и предложил переместить список пакетов в роль и использовать игру для привязки группы к роли.

Будь проще!

Обработчики

Как указывалось ранее, в разделе ролевых игр и ролей написание явных и отдельных файлов задач упрощает повторное использование роли. Включение частей роли — мощный инструмент, и вы также можете использовать его в обработчиках. Обработчики — это то, что срабатывает, когда что-то изменилось, на основе уведомления .

Допустим, у вас есть перезапуск службы, и вы также хотите дождаться, пока эта служба появится после перезапуска.

Создайте файл задачи restart.yml, включите его в обработчик! Теперь этот файл задачи также можно использовать в плейбуке «restart-services.yml».

Вот пример:

# roles/apache/tasks/restart.yml
- name: Restart webserver
  service:
    name: httpd
    state: restarted- name: Wait for webserver to start
  wait_for:
    port: 80
    delay: 10

Входит в состав обработчика:

# roles/apache/handlers/main.yml
- name: restart apache
include_tasks: restart.yml

Модули

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

Кстати, начиная с версии 2.10 в документации ссылки на встроенные модули указаны с полным именем коллекции (FQCN) , поэтому вышеприведенный сервис в документации будет называться ansible.builtin.service.

Вы также можете довольно легко написать свои собственные модули и распространять их через коллекцию.

Кроме того, если вы привыкли проверять детали реализации в основном репозитории Ansible , проверьте организацию коллекций на GitHub.

Синтаксис и YAML

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

Например, в YAML есть приемы вроде якорей, чтобы не повторяться, но не делайте этого. У Ansible есть достаточно методов, чтобы помочь с этим.

По сути, пишите Ansible, а не YAML.

Ansible позволяет указывать большинство вещей в виде встроенных строк вместо передачи ключей и значений задаче. Не делай и этого! 🙂 Подсветка синтаксиса вашего редактора не будет работать, его трудно читать, а отличия от системы контроля версий становятся труднее понять.

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

Помните, что строки могут иметь несколько разных обозначений в YAML. Тот, что без кавычек, так же функционален, как и тот, что с кавычками. Часто последний требуется в Ansible из-за того, что он содержит шаблоны Jinja2, обозначенные фигурными скобками. Как было сказано в первой части серии, целые числа иногда вызывают путаницу.

Вы могли заметить, что логические значения также могут быть выражены разными способами yes. а не trueв некоторых местах. Оба варианта синтаксически правильны, но для ясности следует придерживаться одного из них. И когда я говорю придерживаться одного, я имею в виду использование trueвместо yes.

Стоит отточить свои навыки создания отступов, поскольку это важно для того, чтобы Ansible понял, что вы имеете в виду. Обратите внимание на разницу между словарем, который содержит пары ключ-значение, и списком, который содержит один или несколько объектов различных типов.

Тестирование вашей инфраструктуры

Ваша инфраструктура тоже заслуживает испытаний. Мы стараемся относиться к этому как к коду. Как и в случае с любым другим кодом, вы захотите проверить его, так как удобочитаемость имеет важное значение. Такие инструменты, как ansible-lint , можно очень легко подключить к конвейеру CI.

Линтеры также улавливают такие вещи, как повторяющиеся ключи в вашем YAML. Это проблема, которую не так просто обнаружить иначе. Если вы случайно укажете параметр задачи дважды, используется только последний.

Использование ролей вместо голых плейбуков действительно помогает при тестировании функциональности. Называть эти модульные тесты немного натянуто, но Molecule был разработан для сведения роли с определенным набором входных данных, и вы можете проверить результат.

Раньше он использовал Testinfra в качестве верификатора по умолчанию, но начиная с 3.0 для этого используется Ansible. Он также использует Ansible для подготовки контейнеров для тестирования.

На первый взгляд может показаться немного излишним сначала сказать «установить пакет foo», а затем убедиться, что пакет «foo» действительно установлен. Но это позволяет легко выявлять регрессии во время разработки роли.

А в случае роли, которая поддерживает несколько операционных систем, запустить конвергенцию для нескольких систем несложно. Такое тестирование жизненно важно, если вы планируете опубликовать свою роль в Galaxy, поскольку в противном случае у вас возникнут проблемы с воспроизведением всех пользовательских сред.

Molecule очень ориентирован на тестирование ролей в изоляции, что также подталкивает вас к написанию подобных вещей. Это полезный подход, как я уже говорил много раз, но иногда вы хотите протестировать всю пьесу. Test Kitchen , созданный в мире, также можно использовать с Ansible через Provisioner . Оба позволяют создавать контейнеры и виртуальные машины для тестирования. Они имеют архитектуру плагинов, поэтому драйверы сообщества доступны, если значения по умолчанию не соответствуют вашим потребностям.

Для тестирования во время выполнения Ansible имеет встроенную задачу подтверждения . Это особенно помогает, когда входные переменные поступают из внешней системы, которой вы не обязательно доверяете. Вы также можете использовать assert в роли, чтобы убедиться, что пользователь правильно все настроил. Assert хорош, но может быстро стать слишком ограниченным. Интересным подходом было бы использование схемы JSON для реализации пользовательского модуля, который проверяет входные данные на соответствие указанной схеме.

Заключение

Фу, вот оно!

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

TL;DR:

  1. Используйте описательные имена и сосредоточьтесь на удобочитаемости ваших игр и ролей.
  2. Разделите свою реализацию на роли и заставьте их работать независимо с разумными значениями по умолчанию.
  3. Стремитесь к повторному использованию с помощью ролей и отдельных файлов задач.
  4. Не злоупотребляйте тегами
  5. Предпочитайте явное неявному, в импорте и использованииbecome
  6. Подумайте о том, как вы справляетесь с зависимостями
  7. Обеспечьте качество сторонней роли, прежде чем использовать ее в качестве зависимости.
  8. Разумно организуйте свои сборники игр
  9. Постарайтесь ограничить уровни приоритета в ваших переменных и сделать их простыми.
  10. Проверьте свои сценарии и роли

Статья является переводом medium.com

You may also like

Leave a Comment