Spec-Zone.ru › Ansible

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

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

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

Непрерывная доставка (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

Примечание

Если вам незнакомы такие термины, как «плейбук» и «плей», ознакомьтесь с разделом Работа с плейбуками.

В этом плейбуке пять плейсов. Первый нацелен на узлы 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. Если входит, для этого узла будет добавлена строка ACCEPT в iptables для порта 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 выполняет операции параллельно, пока не достигнет предельного значения «forks» по умолчанию, указанного в файле конфигурации. Однако при последовательном обновлении без простоя может быть нежелательно одновременно обрабатывать такое количество узлов. Если у вас всего несколько веб-серверов, можно задать 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 для взаимодействия с ними. Вместо Nagios можно использовать и другие модули мониторинга, но здесь показана основная цель раздела «pre tasks» — исключить сервер из мониторинга и вывести его из ротации.

На следующем шаге к веб-серверам повторно применяются соответствующие роли. Это приведет к применению к веб-серверам всех деклараций управления конфигурацией из ролей 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, если они обращаются к API, может быть удобно запускать их как local_action. Подробнее о локальных действиях читайте в разделе Управление местом выполнения задач: делегирование и локальные действия. Если вы разработаете что-нибудь полезное для оборудования, для которого еще нет модуля, это может стать хорошим вкладом в проект!

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

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

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

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

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

См. также

Работа с плейбуками

Введение в плейбуки

Роли

Введение в роли плейбуков

Использование переменных

Введение в переменные Ansible

Ansible.com: непрерывная доставка

Введение в непрерывную доставку с Ansible

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

Spec-Zone.ru

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