Spec-Zone.ru › Ansible 2.8

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

  • Что такое непрерывная доставка?
  • Развертывание сайта
  • Многократно используемое содержимое: роли
  • Конфигурация: переменные групп
  • Постепенное обновление
  • Управление другими балансировщиками нагрузки
  • Непрерывная доставка по всей цепочке

Что такое непрерывная доставка?

Непрерывная доставка (CD) означает частое предоставление обновлений для вашего программного приложения.

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

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

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

Примечание

Нажмите здесь для получения последних книг команд для этого примера.

Книги команд разворачивают Apache, PHP, MySQL, Nagios и HAProxy на наборе серверов на базе CentOS.

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

Развертывание сайта

Давайте начнем с site.yml. Это наша книга команд для развертывания сайта. Ее можно использовать для первоначального развертывания сайта, а также для внесения обновлений на все серверы:

---
# This playbook deploys the whole application stack in this site.

# Apply common configuration to all hosts
- hosts: all

  roles:
  - common

# Configure and deploy database servers.
- hosts: dbservers

  roles:
  - db

# Configure and deploy the web servers. Note that we include two roles
# here, the 'base-apache' role which simply sets up Apache, and 'web'
# which includes our example web application.

- hosts: webservers

  roles:
  - base-apache
  - web

# Configure and deploy the load balancer(s).
- hosts: lbservers

  roles:
  - haproxy

# Configure and deploy the Nagios monitoring node(s).
- hosts: monitoring

  roles:
  - base-apache
  - nagios

Примечание

Если вы не знакомы с такими терминами, как книги команд и задания, ознакомьтесь с Работой с книгами команд.

В этой книге команд у нас 5 заданий. Первое задание нацелено на all хосты и применяет роль common ко всем хостам. Это для общих настроек сайта, таких как конфигурация репозитория yum, конфигурация брандмауэра и все остальное, что необходимо применить ко всем серверам.

Следующие четыре задания выполняются на определенных группах хостов и применяют определенные роли к этим серверам. Вместе с ролями для мониторинга Nagios, базы данных и веб-приложения, мы реализовали роль base-apache, которая устанавливает и настраивает базовую конфигурацию Apache. Она используется как для образцового веб-приложения, так и для хостов Nagios.

Многократно используемое содержимое: роли

К этому моменту вы должны немного понимать роли и их работу в Ansible. Роли – это способ организации содержимого: заданий, обработчиков, шаблонов и файлов в многократно используемые компоненты.

В этом примере есть шесть ролей: common, base-apache, db, haproxy, nagios, и web. Как вы организуете свои роли – решать вам и вашей прикладной программе, но большинство сайтов будут иметь одну или несколько общих ролей, которые применяются ко всем системам, а затем серию ролей, специфичных для приложения, которые устанавливают и настраивают отдельные части сайта.

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

Конфигурация: переменные групп

Переменные групп – это переменные, которые применяются к группам серверов. Их можно использовать в шаблонах и книгах команд, чтобы настроить поведение, предоставить легко изменяемые параметры и настройки. Они хранятся в каталоге group_vars в том же местоположении, что и ваш инвентарь. Вот файл group_vars/all lamp_haproxy. Как можно ожидать, эти переменные применяются ко всем машинам в вашем инвентаре:

---
httpd_port: 80
ntpserver: 192.0.2.23

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

Вот еще один файл переменных групп. Это group_vars/dbservers, который применяется к хостам в группе dbservers:

---
mysqlservice: mysqld
mysql_port: 3306
dbuser: root
dbname: foodb
upassword: usersecret

Если вы посмотрите на пример, есть переменные групп для группы webservers и группы lbservers, аналогично.

Эти переменные используются в самых разных местах. Вы можете использовать их в книгах команд, например, так, в roles/db/tasks/main.yml:

- name: Create Application Database
  mysql_db:
    name: "{{ dbname }}"
    state: present

- name: Create Application DB User
  mysql_user:
    name: "{{ dbuser }}"
    password: "{{ upassword }}"
    priv: "*.*:ALL"
    host: '%'
    state: present

Вы также можете использовать эти переменные в шаблонах, например, так, в roles/common/templates/ntp.conf.j2:

driftfile /var/lib/ntp/drift

restrict 127.0.0.1
restrict -6 ::1

server {{ ntpserver }}

includefile /etc/ntp/crypto/pw

keys /etc/ntp/keys

Вы можете видеть, что синтаксис подстановки переменных {{ и }} одинаков как для шаблонов, так и для переменных. Синтаксис внутри фигурных скобок – Jinja2, и вы можете выполнять всевозможные операции и применять различные фильтры к данным внутри. В шаблонах вы также можете использовать циклы for и условные операторы if для обработки более сложных ситуаций, как в roles/common/templates/iptables.j2:

{% if inventory_hostname in groups['dbservers'] %}
-A INPUT -p tcp  --dport 3306 -j  ACCEPT
{% endif %}

Это проверка, существует ли имя инвентаря машины, на которой мы в данный момент работаем (inventory_hostname), в группе инвентаря dbservers. В случае положительного результата эта машина получит строку iptables ACCEPT для порта 3306.

Вот еще один пример из того же шаблона:

{% for host in groups['monitoring'] %}
-A INPUT -p tcp -s {{ hostvars[host].ansible_default_ipv4.address }} --dport 5666 -j ACCEPT
{% endfor %}

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

Вы можете узнать больше о Jinja2 и его возможностях здесь, и вы можете узнать больше о переменных Ansible в целом в разделе Использование переменных.

Постепенное обновление

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

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

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

- hosts: monitoring
  tasks: []

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

Следующая часть – это задание обновления. Первая часть выглядит так:

- hosts: webservers
  user: root
  serial: 1

Это просто обычное определение задания, выполняемое на группе webservers. Ключевое слово serial сообщает Ansible, сколько серверов обрабатывать одновременно. Если это не указано, Ansible будет выполнять эти операции параллельно до предела «вилок», указанного по умолчанию в файле конфигурации. Но для постепенного обновления без перерывов в работе вы, возможно, не захотите обрабатывать сразу так много хостов. Если у вас всего несколько веб-серверов, вы можете установить serial в 1, для обработки одного хоста за раз. Если у вас 100, возможно, вы можете установить serial в 10, для обработки десяти за раз.

Вот следующая часть задания обновления:

pre_tasks:
- name: disable nagios alerts for this host webserver service
  nagios:
    action: disable_alerts
    host: "{{ inventory_hostname }}"
    services: webserver
  delegate_to: "{{ item }}"
  loop: "{{ groups.monitoring }}"

- name: disable the server in haproxy
  shell: echo "disable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
  delegate_to: "{{ item }}"
  loop: "{{ groups.lbservers }}"

Примечание

  • Ключевое слово serial заставляет задание выполняться «порциями». Каждая порция считается полным заданием с подвыборкой хостов. Это имеет некоторые последствия для поведения заданий. Например, если все хосты в порции завершатся неудачно, задание завершится неудачей, что, в свою очередь, приведет к неудаче всего выполнения. Вы должны учесть это, когда комбинируете это с max_fail_percentage.

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

Аргументы delegate_to и loop, используемые вместе, заставляют Ansible перебирать каждый сервер мониторинга и балансировщик, и выполнять эту операцию (передавать эту операцию) на сервере мониторинга или балансировщика «от имени» веб-сервера. В программировании внешний цикл – это список веб-серверов, а внутренний цикл – список серверов мониторинга.

Обратите внимание, что шаг HAProxy выглядит немного сложно. Мы используем HAProxy в этом примере, потому что он свободно доступен, но если у вас (например) F5 или Netscaler в вашей инфраструктуре (или, возможно, у вас настроен AWS Elastic IP?), вы можете использовать модули, включенные в Ansible core, для общения с ними вместо этого. Возможно, вам также захочется использовать другие модули мониторинга вместо Nagios, но это просто демонстрирует основную цель раздела «предварительные задания» – исключить сервер из мониторинга и из ротации.

Следующий шаг просто повторно применяет соответствующие роли к веб-серверам. Это приведет к применению всех заявлений о управлении конфигурацией в ролях web и base-apache, включая обновление самого кода веб-приложения. Нам не обязательно делать это так – мы могли бы вместо этого просто обновить веб-приложение, но это хороший пример того, как использовать роли для повторного использования заданий:

roles:
- common
- base-apache
- web

Наконец, в разделе post_tasks мы отменяем изменения в конфигурации Nagios и возвращаем веб-сервер в пул балансировки нагрузки:

post_tasks:
- name: Enable the server in haproxy
  shell: echo "enable server myapplb/{{ inventory_hostname }}" | socat stdio /var/lib/haproxy/stats
  delegate_to: "{{ item }}"
  loop: "{{ groups.lbservers }}"

- name: re-enable nagios alerts
  nagios:
    action: enable_alerts
    host: "{{ inventory_hostname }}"
    services: webserver
  delegate_to: "{{ item }}"
  loop: "{{ groups.monitoring }}"

Опять же, если вы использовали Netscaler, F5 или Elastic Load Balancer, вам нужно было бы просто заменить соответствующие модули.

Управление другими балансировщиками нагрузки

В этом примере мы используем простой балансировщик нагрузки HAProxy для веб-серверов. Он прост в настройке и управлении. Как мы уже упоминали, Ansible имеет встроенную поддержку различных других балансировщиков нагрузки, таких как Citrix NetScaler, F5 BigIP, Amazon Elastic Load Balancers и другие. Подробнее см. документацию Работа с модулями.

Для других балансировщиков нагрузки вам может потребоваться отправлять им командные файлы (как мы делаем для HAProxy выше) или вызывать API, если ваш балансировщик нагрузки его предоставляет. Для балансировщиков нагрузки, для которых Ansible имеет модули, вы можете запустить их как local_action , если они обращаются к API. Подробнее о локальных действиях можно узнать в разделе Делегирование, постепенные обновления и локальные действия. Если вы разработаете что-то интересное для какого-либо оборудования, для которого нет основного модуля, это может стать хорошим модулем для включения в ядро!

Непрерывная доставка по всей цепочке

Теперь, когда у вас есть автоматизированный способ развертывания обновлений приложения, как связать всё это вместе? Многие организации используют инструмент непрерывной интеграции, такой как Jenkins или Atlassian Bamboo, для связывания этапов разработки, тестирования, выпуска и развертывания. Возможно, вам также понадобится инструмент, подобный Gerrit, чтобы добавить этап проверки кода к коммитам как в сам код приложения, так и в ваши Ansible-playbook, или в оба.

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

Для интеграции с системами непрерывной интеграции вы можете легко запускать выполнение playbook с помощью инструмента ansible-playbook командной строки или, если вы используете Red Hat Ansible Tower, с помощью tower-cli или встроенного REST API. (Команда tower-cli 'joblaunch' запустит удалённую задачу через REST API и довольно удобна).

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

См. также

пример lamp_haproxy
Обсуждаемый здесь пример lamp_haproxy.
Работа с Playbook
Введение в Playbook
Роли
Введение в роли playbook
Использование переменных
Введение в переменные Ansible
Ansible.com: Непрерывная доставка
Введение в непрерывную доставку с Ansible

© 2012–2018 Michael DeHaan
© 2018–2019 Red Hat, Inc.
Licensed under the GNU General Public License version 3.
https://docs.ansible.com/ansible/2.8/user_guide/guide_rolling_upgrade.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API