Pull to refresh
827.96
OTUS
Цифровые навыки от ведущих экспертов

Рекомендации по Ansible

Reading time 6 min
Views 12K
Original author: Sergii Bieliaievskyi

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

Переменные можно разделить на две категории:

  • Переменные в отдельных файлах (в таблице ниже "Filesystem").

  • Переменные в коде (в таблице ниже "Code").

Теперь, если вы посмотрите на их приоритет, то все встает на свои места.

Filesystem-переменные имеют более низкий приоритет по сравнению с Code-переменными. Обратили ли вы внимание на упомянутую выше гибкость и чрезмерную свободу? Давайте продолжим далее с учетом этих знаний.

1. Объявляйте переменные в отдельных файлах

Переменные лучше располагать в отдельных файлах (Inventory, group_vars, host_vars, role/defaults/main.yml и role/vars/main.yml). Все "постоянные" переменные должны быть явно определены. Постоянные переменные — это переменные, влияющие на роль или поведение плейбука. В отличие от "временных" переменных, используемых в качестве буфера для временного хранения значений, часто с ограниченной областью видимости. Например, переменные, объявленные в vars, существуют только внутри block. Например:

- name: Variables scope
  hosts: localhost
  connection: local
  vars:
    MY_VAR: "I am global var"
  tasks:
    - block:
      - name: Print variable inside the block.
        debug:
          var: MY_VAR
        vars:
          MY_VAR: "I am local var"
- name: Print variable outside the block.
  debug:
    var: MY_VAR
PLAY [Variables scope]
 TASK [Gathering Facts]
 ok: [localhost]
 TASK [Print variable inside the block.]
 ok: [localhost] => {
 "MY_VAR": "I am local var"
 }
 TASK [Print variable outside the block.]
 ok: [localhost] => {
 "MY_VAR": "I am global var"
 }

Таким образом, мы должны определять переменные в файлах. И все переменные должны быть определены явно. Для роли есть файл defaults/main.yml. Значения в этом файле имеют самый низкий приоритет, поэтому здесь можно размещать в том числе пустые переменные. Это облегчит жизнь контрибьюторам, особенно тем, кто видит код впервые.

2. Используйте README

Если роль использует много различных переменных, возможно, все они даже нужные и полезные, то описывайте их в файле README. Команда ansible-galaxy init поможет вам в этом, сгенерировав шаблон README. Вероятно, вам самому, в незнакомом репозитории будет приятно увидеть README с информацией о том, что роль ожидает увидеть на входе и что будет на выходе. Плохим примером будет разделение кода и описания. Например, код в git, а описание на wiki-странице. Нет никакой гарантии, что контрибьюторы обновят и код, и wiki-страницу. Обычно после пул реквеста работа заканчивается.

3. Используйте префиксы

У всех "постоянных" переменных (упомянутых в первом совете) должны быть префиксы. В качестве префикса лучше всего использовать имя роли. Это очень полезно, когда переменные для разных ролей нужно разместить в одном месте. Например, что произойдет в плейбуке с несколькими ролями, если все роли используют переменную port? Добавляя префикс, мы гарантируем, что одни переменные не будут перезаписаны другими. Пример: роль — consul. переменная — url, имя переменной — consul_url.

4. Называйте задачи осмысленными именами

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

Например:

# No name/description
- copy: dest=/tmp/text.txt, content="bla-bla"
- name: Print variable global var.
 debug:
   var: MY_VAR
TASK [copy]
changed: [localhost]
TASK [Print variable global var.] *
ok: [localhost] => {
"MY_VAR": "I am global var"
}

5. DRY (Don't Repeat Yourself)

Ansible похож на обычный язык программирования. И как и в обычном языке, в Ansible есть различные механизмы, которые помогают следовать принципу DRY (Don't Repeat Yourself). Но это требует предварительного планирования организации вашего кода. При написании кода думайте, чтобы его можно было переиспользовать.

Крупные блоки:

Блоки внутри роли: (include/import)tasks, (include/import)role. Как это может использоваться? Например, вы используете модуль uri для отправки API-запросов. Допустим, это POST-запросы. Вместо того чтобы повторять 10 раз uri со всеми настройками, можно создать что-то вроде метода и использовать его где угодно. Аналогично методам в обычных языках программирования наш метод тоже принимает входные параметры.

Например: send_post.yml

- name: .::::::::::::. [ Sent POST request ] .::::::::::::.
 uri:
   url: "{{ URL }}"
   method: POST
   status_code: 200
   body: "{{ BODY_VAR | to_nice_json }}"
   body_format: json
   validate_certs: yes
   client_cert: tls.crt
   client_key: tls.key
   register: return_values
 when: BODY_VAR is defined

Этот код можно использовать повторно.

- name: Bla-bla
   include_tasks: send_post.yml
   vars:
       URL: "{{ main_url }}/{{ item }}"
       BODY_VAR: "{{ item }}"

URL и BODY_VAR — это параметры метода.

6. Используйте блоки (block)

Используйте block.  

Описывайте параметры задач только один раз, группируя их. Также block может использоваться аналогично блоку try / catch в традиционных языках программирования.

- block:
   ...
  rescue:
   ...

block/rescue — отличная альтернатива ignore_errors. По сути, расширенная обработка ошибок. Это может быть полезным, например, когда вам нужно выполнить какой-то код в плейбуке, даже в случае сбоя. Например, удалить некоторые файлы.

 - block:
   - name: .....
   - name: .....
   - name: .....
   always:
     file:
       path: /tmp/xxxx
       state: absent

7. Не используйте модули command и shell

Старайтесь не использовать модули command и shell, потому что они не идемпотентные. Хотя есть ряд приемов, которые помогают смягчить эту проблему. Используйте:

  • when

  • creates (если файл существует, то этот шаг не выполняется).

  • removes (если файл существует, то этот шаг выполняется).

  • changedwhen.

Тем не менее если это возможно, держитесь подальше от command и shell.

8. Не используйте теги

Не используйте теги. Теги могут стать ночным кошмаром для людей, которые видят ваш код впервые. Комбинации тегов увеличивает количество возможных вариантов выполнения плейбука. Но если у вас нет выбора, то подробно описывайте теги и их комбинации в README. Однако не все теги плохи. Есть исключения. Например, always, never —  читать подробнее.

skip_ansible_lint — пропустить ansible-lint для задачи.

9. Принцип минимальных привилегий

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

---
 - hosts: wordpress
    become: no
     ...
    role:
      - role: wordpress

tasks/main.yml
---
- name: Install mysql-server pkg
  apt:
    name: mysql-server
    state: present
  become: yes

10. Используйте YAML-синтаксис для параметров

Используйте YAML вместо встраиваемого синтаксиса. Сравните эти два варианта:

YAML

- name: Install apache httpd
  apt:
    name: apache2
    state: present

Встраиваемый

- name: Install apache httpd
  apt: pkg=apache2 state=pesent

11. Используйте gitignore

Добавьте .gitignore к своим ролям, если вы храните код в git-репозитории. Простой .gitignore может выглядеть следующим образом:

*.retry
*/__pycache__
*.pyc
*.log
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

12. Используйте советы из документации Ansible

Используйте рекомендации по организации контента с официальной страницы ansible  

13. Используйте отдельный каталог для ролей сообщества

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

14. Тестируйте Ansible-код

Используйте фреймворки для тестирования кода Ansible. Например, molecule. Этот фреймворк позволяет тестировать ваш код с разных сторон. Помимо традиционного тестирования, он также может запускать все виды линтеров и проверять код на идемпотентность.

15. Версионирование ролей

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

requirements.yaml:

---
- src: git@gitlab.company.com:mygroup/ansible.git
 scm: git
 version: "0.1"
...

Допустимые атрибуты:

  • src

  • scm

  • version

  • name


Перевод статьи подготовлен в преддверии старта курса «DevOps практики и инструменты».

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

Tags:
Hubs:
+8
Comments 1
Comments Comments 1

Articles

Information

Website
otus.ru
Registered
Founded
Employees
101–200 employees
Location
Россия
Representative
OTUS