Экосистема Docker: обнаружение сервисов и распределённые хранилища конфигураций
Контейнеры предоставляют простое и удобное решение для проектирования и развёртывания масштабируемых приложений. Docker позволяет реализовать технологию контейнеризации; кроме того, существует множество дополнительных инструментов для развёртывания, разработки проектов и взаимодействия компонентов и окружения.
Обнаружение сервисов (service discovery) – одна из базовых технологий Docker. Обнаружение сервисов позволяет приложению (или его компонентам) получать информацию об окружении и других компонентах, с которыми ему нужно взаимодействовать. Как правило, эта технология реализуется при помощи хранилища типа «ключ-значение», которое также может хранить детали настройки. Инструменты обнаружения сервисов позволяют отделить runtime-конфигурации от самого контейнера, благодаря чему у вас есть возможность повторно использовать образы в нескольких окружениях.
В данной статье речь пойдёт о преимуществах обнаружения сервисов в кластеризованном окружении Docker.
Обнаружение сервисов и глобальные хранилища конфигураций
Обнаружение сервисов базируется на следующей идее: любой новый экземпляр приложения должен программно определить детали текущего окружения. Это позволяет ему подключиться к окружению без вмешательства администратора. Инструменты обнаружения сервисов обычно реализуются в виде глобально доступных реестров, в которых хранится информация о запущенных экземплярах приложений и сервисов. Как правило, реестры распределяются по доступным хостам, что обеспечивает ошибкоустойчивость и масштабируемость.
Основной целью систем обнаружения сервисов является обслуживание деталей соединений и обеспечение взаимодействия компонентов, однако с их помощью можно хранить конфигурации любого типа. Многие развёртывания используют эту возможность, сохраняя информацию о своих настройках с помощью инструмента обнаружения сервисов. Если контейнеры знают, где искать и как использовать эти детали конфигураций, они могут автоматически изменять своё поведение на основе полученных данных.
Как работает обнаружение сервисов?
Каждый инструмент обнаружения сервисов предоставляет API, который может использоваться компонентами для обмена данными. Потому адрес обнаружения сервисов для каждого компонента должен быть либо жестко прописан в приложении или контейнере, либо предоставляться во время исполнения. Обычно обнаружение сервисов реализуется в виде хранилища типа «ключ-значение», которое использует стандартные методы http.
Инструмент обнаружения сервисов работает таким образом: каждый сервис во время запуска регистрируется в системе обнаружения сервисов, предоставляя всю информацию, которая может понадобиться другим компонентам для взаимодействия с ним. К примеру, СУБД MySQL может зарегистрировать IP-адрес и порт, на котором работает демон, и опционально имя пользователя и учётные данные для аутентификации. Когда запускаются компоненты, для работы которых необходим этот сервис, они могут отправить запрос в реестр обнаружения сервисов и получить все доступные данные. После этого они используют полученную информацию для взаимодействия с необходимым сервисом. В качестве примера можно привести балансировщик нагрузки: отправляя запросы инструменту обнаружения сервисов, он может обнаружить все серверы бэкенда, на которые можно распределить трафик.
Таким образом, данные инструменты могут извлечь конфигурации за пределы контейнеров. Одним из преимуществ такого подхода является высокая гибкость компонентов и устранение жёсткой привязки к определённым конфигурациям.
Как хранилища конфигураций связаны с обнаружением сервисов?
Главное преимущество глобально распределённой системы обнаружения сервисов – это возможность хранить необходимые конфигурации любого типа. Это значит, что среда выполнения более высокого уровня может извлечь из контейнера больше конфигурационных данных.
Как правило, для большей эффективности этой технологии приложение проектируется с разумными значениями по умолчанию, которые можно переопределить во время выполнения с помощью запросов к хранилищу конфигураций. Это позволяет использовать хранилище аналогично флагам командной строки. Разница состоит в том, что при использовании глобально доступного хранилища вы можете задать одинаковые настройки каждому экземпляру приложения или компонента без дополнительной работы.
Как хранилище конфигураций связано с управлением кластером?
В развёртываниях Docker одной из основных функций распределённых хранилищ «ключ-значение» является хранение и управление данными о кластере. Хранилища конфигураций – идеальное окружение для отслеживания членства хоста в кластере, что необходимо инструментам управления.
В распределённых хранилищах может находиться следующая информация об индивидуальных хостах:
- IP-адрес хоста.
- Данные о подключениях для самих хостов.
- Произвольные метаданные и ярлыки, которые могут понадобиться планировщику.
- Роль в кластере (при использовании схемы master-slave).
Возможно, вам не стоит заботиться об этих данных при использовании системы обнаружения сервисов в обычных обстоятельствах, однако они дают инструментам управления возможность получать и изменять данные о самом кластере.
Обнаружение отказов
Существует несколько способов реализации обнаружения отказов. Суть данного механизма заключается в том, что в случае отказа компонента система обнаружения сервисов должна узнать об этом и сообщить остальным компонентам, что он не доступен. Такой тип данных крайне необходим для минимизации отказов приложений или сервисов.
Многие инструменты обнаружения сервисов позволяют устанавливать значения параметров с настраиваемым тайм-аутом. Компонент может установить значение с тайм-аутом и своевременно пинговать обнаружение сервисов, чтобы изменить настройки. Если в случае сбоя компонента достигается тайм-аут, данные о подключении этого компонента удаляются из хранилища. Как правило, длительность тайм-аута, зависит от реакции самого приложения на отказ компонента.
Также этого можно достичь путём привязки вспомогательного контейнера к каждому компоненту приложения. Целью такого контейнера является регулярная проверка работоспособности компонента и обновление реестров в случае отказа. Недостаток подобной архитектуры – возможность отказа самого вспомогательного контейнера. Такие неполадки могут стать причиной сохранения неправильных данных в распределённом хранилище. В некоторых системах эта проблема устраняется при помощи периодической проверки работоспособности компонентов инструментами обнаружения сервисов. Таким образом, сама система обнаружения регулярно проверяет состояние зарегистрированных компонентов.
Перенастройка сервисов
Главным улучшением базовой модели системы обнаружения сервисов является динамическая перенастройка. Обычные системы обнаружения сервисов просто позволяют влиять на исходные конфигурации компонентов во время запуска; в отличие от этого, динамическая перенастройка позволяет изменять конфигурации компонентов согласно изменениям в хранилище конфигураций. К примеру, при использовании балансировщика нагрузки во время проверки может оказаться, что один из серверов бэкэнда вышел из строя; в таком случае система обнаружения сервисов сообщает балансировщику о возникшей неполадке, после чего он должен изменить свои настройки.
Это можно реализовать несколькими способами. Пример с балансировщиком – это один из основных сценариев использования такого механизма, потому существует несколько проектов, сосредоточенных исключительно на его перенастройке в случае изменения конфигураций.
Более гибкие проекты могут извлекать изменения конфигураций из программного обеспечения любого типа. Такие инструменты регулярно отправляют запросы системе обнаружения сервисов и в случае изменения используют системы шаблонов, чтобы создать конфигурационные файлы с учетом последних данных. После создания нового конфигурационного файла сервис, к которому относятся эти изменения, перезагружается.
Подобная динамическая перенастройка требует тщательного планирования и конфигурации во время сборки приложения, поскольку контейнер компонента должен включать в себя эти механизмы. Таким образом, сам контейнер становится ответственным за исправление своих конфигураций. Определение значений, которые нужно внести в систему обнаружения сервисов, и проектирование соответствующих данных – это отдельный трудоёмкий процесс, который, однако, имеет существенные преимущества.
Безопасность
Говоря о глобальном хранилище конфигураций, многие пользователи интересуются подробностями его безопасности и надёжности. Действительно, насколько это безопасно – хранить данные о подключении в общедоступном месте?
Ответ на этот вопрос во многом зависит от того, что именно вы помещаете в хранилище и сколько уровней безопасности вы считаете нужным при этом использовать. Почти каждый инструмент обнаружения сервисов предоставляет механизмы шифрования соединений через SSL/TLS. Некоторые сервисы не считают приватность особо важным вопросом, в таких случаях будет достаточно поместить систему обнаружения сервисов в приватную сеть. Однако большинство сервисов, предпочитает предпринимать дополнительные меры безопасности.
Существует ряд подходов к этому вопросу. К примеру, один из проектов предлагает оставлять систему обнаружения сервисов в открытом доступе и шифровать хранимые в ней данные. Тогда приложение, которому необходимы эти данные, должно иметь ключ, чтобы их расшифровать. Тогда сторонние пользователи не получат доступ к данным.
Другой подход состоит в создании списков управления доступом; это позволяет разделить ключи в хранилище на отдельные зоны. При этом система обнаружения сервисов выбирает владельцев и открывает доступ к ключам согласно требованиям, определённым для каждой зоны. Такой подход позволяет одновременно предоставлять доступ к данным одним пользователям и блокировать доступ другим пользователям. Каждый компонент можно настроить так, чтобы он получал доступ только к необходимым ему данным.
Общие инструменты обнаружения сервисов
- etcd: разработан командой CoreOS для обеспечения обнаружения сервисов и глобально распределенного хранилища конфигураций для контейнеров и хост-систем. Этот инструмент использует http API и предоставляет клиент командной строки, доступный на каждом хосте.
- consul: система обнаружения сервисов, которая предоставляет множество продвинутых функций, включая настраиваемую проверку работоспособности, ACL (access control list, список контроля доступа), настройку HAProxy и многое другое.
- zookeeper: этот инструмент немного старше предыдущих. Это зрелая система, которая не предоставляет некоторых функций, доступных в перечисленных выше системах.
Следующие проекты позволяют расширить базовое обнаружение сервисов:
- crypt: защищает данные компонентов при помощи шифрования. Чтобы прочитать данные, компонент может получить ключ для расшифровки. Без ключа прочитать данные невозможно.
- confd: обеспечивает динамическую перенастройку приложений согласно изменениям в системе обнаружения сервисов. Эта система также предоставляет инструмент для отслеживания важных изменений, систему шаблонов (для создания новых конфигурационных файлов на основе обновлённых данных) и функцию перезагрузки приложений, чьи настройки изменились.
- vulcand: используется в качестве балансировщика нагрузки для групп компонентов. Этот инструмент может взаимодействовать с etcd и изменять свои конфигурации согласно изменениям в хранилище.
- marathon: как правило, используется как планировщик, но также предоставляет базовые функции перезагрузки HAProxy в случае обновления данных о сервисах, нагрузку которых он балансирует.
- frontrunner: работает в связке с marathon и обеспечивает более надёжный способ обновления HAProxy.
- synapse: встроенный HAProxy, отвечающий за маршрутизацию трафика между компонентами.
- nerve: работает в связке с synapse, отвечает за проверку состояния экземпляров определённого компонента. В случае сбоя компонента nerve обновляет synapse и удаляет компонент из списка доступных.
Заключение
Обнаружение сервисов и глобально распределённые хранилища позволяют контейнерам Docker адаптировать конфигурации согласно состоянию текущего окружения и взаимодействовать с доступными компонентами. Это необходимо для обеспечения простого масштабирования и развёртывания путём отслеживания и использования изменений в окружении.
В следующей статье данной серии вы прочитаете об оркестровке и планировщиках Docker.
Tags: Docker, Service discovery