Spec-Zone.ru › Ansible 2.10

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

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

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

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

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

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

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

Примечание

Перейти к последним playbook для этого примера.

Playbook развертывает Apache, PHP, MySQL, Nagios и HAProxy на наборе серверов на базе CentOS.

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

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

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

---
# 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

Примечание

Если вы не знакомы с такими терминами, как playbook и plays, ознакомьтесь с Работа с playbook.

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

Следующие четыре plays выполняются на определенных группах хостов и применяют к ним определенные роли. Наряду с ролями для мониторинга Nagios, базы данных и веб-приложения, мы реализовали роль base-apache, которая устанавливает и настраивает базовый Apache. Это используется как веб-приложением, так и хостами Nagios.

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

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

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

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

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

Переменные групп — это переменные, которые применяются к группам серверов. Они могут использоваться в шаблонах и playbook для настройки поведения, предоставления легко изменяемых настроек и параметров. Они хранятся в каталоге 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, аналогично.

Эти переменные используются в различных местах. Вы можете использовать их в playbook, например, в 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 способен выполнять операции на приложениях с несколькими уровнями координированным образом, облегчая оркестрацию сложного поэтапного обновления веб-приложения без простоев. Это реализовано в отдельном playbook, который называется rolling_update.yml.

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

- hosts: monitoring
  tasks: []

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

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

- hosts: webservers
  user: root
  serial: 1

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

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

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 заставляет play выполняться «по частям». Каждая часть считается полным play с подмножеством хостов. Это имеет некоторые последствия для поведения play. Например, если все хосты в партии завершатся неудачно, play завершится неудачно, что, в свою очередь, завершит весь запуск неудачно. Вы должны учитывать это при объединении с max_fail_percentage.

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

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

Обратите внимание, что шаг HAProxy выглядит немного сложным. Мы используем HAProxy в этом примере, потому что он свободно доступен, но если у вас (например) F5 или Netscaler в вашей инфраструктуре (или, возможно, у вас есть настройка AWS Elastic IP?), вы можете использовать Ansible-модули для общения с ними вместо этого. Вы также можете использовать другие модули мониторинга вместо 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.

Работа с playbooks

Введение в playbooks

Роли

Введение в роли 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.10/user_guide/guide_rolling_upgrade.html

Spec-Zone.ru

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