Как управлять многоступенчатой ​​средой с помощью Ansible

Вступление

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

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

Неполные стратегии управления многоступенчатой ​​средой с помощью Ansible

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

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

Если вы хотите начать работу с рекомендуемой стратегией Ansible, перейдите к разделу https://www.digitalocean.com/community/tutorials/how-to-manage-multistage-environments-with-ansible#ansible-recommended-strategy. -using-groups-and-множественные инвентаризации [используя Ansible группы и множественные инвентаризации].

Полагаться исключительно на групповые переменные

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

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

  • среды развертывания (локальные, dev, stage, prod и т. д.)

  • функциональность хоста (веб-серверы, серверы баз данных и т. д.)

  • регион центра обработки данных (NYC, SFO и т. д.)

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

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

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

Использование дочерних групп для установления иерархии

Ansible позволяет назначать группы другим группам, используя синтаксис + [: children] + в инвентаре. Это дает вам возможность называть определенные группы членами других групп. Дочерние группы имеют возможность переопределять переменные, установленные родительскими группами.

Как правило, это используется для естественной классификации. Например, у нас может быть группа под названием «+ Environment», которая включает группы «+ dev», «+ stage», «+ prod». Это означает, что мы можем установить переменные в группе + environment + и переопределить их в группе + dev +. Точно так же вы можете иметь родительскую группу под названием + functions +, которая содержит группы + web,` + database` и + балансировщик нагрузки.

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

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

  • среда разработки

  • область

  • функция

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

Пример инвентаря

. . .
[function:children]
web
database
loadbalancer


[region:children]
nyc
sfo


[environments:children]
dev
stage
prod

Здесь мы установили иерархию, которая позволяет региональным переменным переопределять функциональные переменные, поскольку группа + region + является дочерней по отношению к группе + function +. Точно так же переменные, установленные в группах + environment +, могут переопределять любые другие. Это означает, что если мы установим для одной и той же переменной другое значение в группах + dev +, + nyc + и + web +, хост, принадлежащий каждому из них, будет использовать переменную из + dev +.

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

Использование Ansible Constructs, которые позволяют явный порядок загрузки

В Ansible есть несколько конструкций, которые допускают явное упорядочение загрузки переменных, а именно + vars_files + и + include_vars +. Их можно использовать в Ansible plays явной загрузке дополнительных переменных в порядке, определенном в файле. Директива + vars_files + действительна в контексте воспроизведения, в то время как модуль + include_vars + может использоваться в задачах.

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

Например, некоторые из файлов + group_vars + могут выглядеть так:

group_vars / DEV

---
env: dev

group_vars / этап

---
env: stage

group_vars / веб

---
function: web

group_vars / база данных

---
function: database

Тогда у нас будет отдельный файл vars, который определяет важные переменные для каждой группы. Обычно для ясности они хранятся в отдельном каталоге + vars +. В отличие от файлов + group_vars +, при работе с + include_vars + файлы должны включать расширение файла + .yml +.

Давайте притворимся, что нам нужно установить переменную + server_memory_size + в другое значение в каждом файле + vars +. Ваши серверы разработки, вероятно, будут меньше ваших производственных серверов. Кроме того, ваши веб-серверы и серверы баз данных могут иметь разные требования к памяти:

вары / dev.yml

---
server_memory_size: 512mb

вары / prod.yml

---
server_memory_size: 4gb

вары / web.yml

---
server_memory_size: 1gb

вары / database.yml

---
server_memory_size: 2gb

Затем мы можем создать книгу воспроизведения, которая явно загружает правильный файл + vars + на основе значений, присвоенных хосту из файлов + group_vars +. Порядок загружаемых файлов будет определять приоритет с последним выигравшим значением.

С + vars_files + пример игры будет выглядеть так:

example_play.yml

---
- name: variable precedence test
 hosts: all
 vars_files:
   - "vars/{{ env }}.yml"
   - "vars/{{ function }}.yml"
 tasks:
   - debug: var=server_memory_size

Поскольку функциональные группы загружаются последними, значение + server_memory_size + будет взято из файлов + var / web.yml + и + var / database.yml +:

ansible-playbook -i inventory example_play.yml
Output. . .
TASK [debug] *******************************************************************
ok: [host1] => {
   "server_memory_size":
}
ok: [host2] => {
   "server_memory_size":
}
ok: [host3] => {
   "server_memory_size":
}
ok: [host4] => {
   "server_memory_size":
}
. . .

Если мы изменим порядок загрузки файлов, мы можем сделать переменные среды развертывания более приоритетными:

example_play.yml

---
- name: variable precedence test
 hosts: all
 vars_files:
   - "vars/{{ function }}.yml"
   - "vars/{{ env }}.yml"
 tasks:
   - debug: var=server_memory_size

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

ansible-playbook -i inventory example_play.yml
Output. . .
TASK [debug] *******************************************************************
ok: [host1] => {
   "server_memory_size":
}
ok: [host2] => {
   "server_memory_size":
}
ok: [host3] => {
   "server_memory_size":
}
ok: [host4] => {
   "server_memory_size":
}
. . .

Эквивалентная книга воспроизведения с использованием + include_vars +, которая работает как задача, будет выглядеть так:

---
- name: variable precedence test
 hosts: localhost
 tasks:
   - include_vars:
       file: "{{ item }}"
     with_items:
       - "vars/{{ function }}.yml"
       - "vars/{{ env }}.yml"
   - debug: var=server_memory_size

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

Прежде всего, использование + vars_files + и + include_vars + требует от вас размещения переменных, которые тесно связаны с группами, в другом месте. Расположение + group_vars + становится заглушкой для фактических переменных, находящихся в каталоге + vars +. Это еще раз добавляет сложности и снижает ясность. Пользователь должен сопоставить правильные файлы переменных с хостом, что Ansible делает автоматически при использовании + group_vars +.

Что еще более важно, использование этих методов делает их обязательными. Каждый playbook будет требовать раздел, который явно загружает правильные файлы переменных в правильном порядке. Playbooks без этого не сможет использовать связанные переменные. Кроме того, выполнение команды + ansible + для специальных задач будет практически невозможно для всего, что полагается на переменные.

Рекомендуемая рекомендуемая стратегия: использование групп и нескольких инвентаризаций

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

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

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

.
├── ansible.cfg
├── environments/         # Parent directory for our environment-specific directories
│   │
│   ├── dev/              # Contains all files specific to the dev environment
│   │   ├── group_vars/   # dev specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the dev environment
│   │
│   ├── prod/             # Contains all files specific to the prod environment
│   │   ├── group_vars/   # prod specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the prod environment
│   │
│   └── stage/            # Contains all files specific to the stage environment
│       ├── group_vars/   # stage specific group_vars files
│       │   ├── all
│       │   ├── db
│       │   └── web
│       └── hosts         # Contains only the hosts in the stage environment
│
├── playbook.yml
│
└── . . .

Как вы можете видеть, каждая среда отличается и разделена. Каталоги среды содержат файл инвентаризации (произвольно названный + hosts +) и отдельный каталог + group_vars +.

Существует некоторое очевидное дублирование в дереве каталогов. Для каждой отдельной среды существуют файлы + web и` + db`. В этом случае дублирование желательно. Изменения переменных можно развернуть в разных средах, сначала изменив переменные в одной среде и переместив их в следующую после тестирования, так же, как вы это сделали бы с изменениями кода или конфигурации. Переменные + group_vars + отслеживают текущие значения по умолчанию для каждой среды.

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

Установка переменных между средами

Одна вещь, которая невозможна в рекомендуемой настройке, - это совместное использование переменных в разных средах. Существует несколько способов реализовать совместное использование переменных между средами. Одним из самых простых является использование способности Ansible использовать каталоги вместо файлов. Мы можем заменить файл + all + в каждом каталоге + group_vars + на каталог + all +.

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

Начните с создания файла переменных среды в иерархии. В этом примере мы поместим его в каталог + environment +. Поместите все переменные среды в этот файл:

cd environments
touch 000_cross_env_vars

Затем перейдите в один из каталога + group_vars +, переименуйте файл + all + и создайте каталог + all +. Переместите переименованный файл в новый каталог:

cd dev/group_vars
mv all env_specific
mkdir all
mv env_specific all/

Далее вы можете создать символическую ссылку на файл переменной среды:

cd all/
ln -s ../../../000_cross_env_vars .

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

.
├── ansible.cfg
├── environments/
│   │
│   ├──
│   │
│   ├── dev/
│   │   ├── group_vars/
│   │   │   ├──
│       │   │   ├──
│   │   │   │   └──
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   ├── prod/
│   │   ├── group_vars/
│   │   │   ├──
│   │   │   │   ├──
│   │   │   │   └──
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   └── stage/
│       ├── group_vars/
│       │   ├──
│       │   │   ├──
│       │   │   └──
│       │   ├── db
│       │   └── web
│       └── hosts
│
├── playbook.yml
│
└── . . .

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

Настройка инвентаризации среды по умолчанию

Можно установить файл инвентаря по умолчанию в файле + ansible.cfg +. Это хорошая идея по нескольким причинам.

Во-первых, он позволяет отключить явные флаги инвентаризации для + ansible и` + ansible-playbook`. Так что вместо того, чтобы печатать:

ansible -i environments/dev -m ping

Вы можете получить доступ к инвентарю по умолчанию, набрав:

ansible -m ping

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

Чтобы установить инвентарь по умолчанию, откройте файл + ansible.cfg +. Это может быть в корневом каталоге вашего проекта или в + / etc / ansible / ansible.cfg + в зависимости от вашей конфигурации.

nano ansible.cfg

Как упоминалось выше, рекомендуется установить среду разработки в качестве инвентаря по умолчанию. Обратите внимание, как мы можем выбрать весь каталог среды вместо файла hosts, который он содержит:

[defaults]
inventory = ./environments/dev

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

Заключение

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

Related