Микросервисы (microservices) – очередной виток развития компонентной разработки программных комплексов и приложений. Разбиение сложной задачи на составные более простые части, изоляция сложности, и поиск абстракций, позволяющих упростить и сделать задачу управляемой и решаемой – основа программирования в целом. Разбиение программы на пакеты, функции, классы, а затем и на совершенно независимо работающие друг от друга компоненты логически вытекает из анализа задачи.
Микросервисы – это компоненты вашего приложения, независимо друг от друга работающие в облаке и соединенные между собой не прямыми вызовами внутри одного процесса, а передачей данных по сети, используя заранее оговоренные протоколы (обычно HTTP или gRPC) и порты.
Эластичность и практически неограниченная вычислительная мощность облака дает нам возможность разбить приложение на логические компоненты и запускать их и управлять ими индивидуально. При необходимости легко увеличить пропускную способность приложения, увеличив количество экземпляров компонентов (работающих в виде микросервисов), испытывающих наибольшую нагрузку. Это так называемое горизонтальное масштабирование (horizontal scaling или scaling out) – при работе в облаке его возможности практически безграничны, при условии выбора удачной архитектуры приложения, дающей возможность разбить его вычислительные потоки на независимые части. Вертикальное масштабирование же подразумевает рост мощности одного сервера и его аппаратных возможностей, что крайне ограничено, и более того, мощные серверы обычно очень дороги.
Передача данных между микросервисами осуществляется по сети, по хорошо известным протоколам, поддерживаемым практически всеми известными языками и их библиотеками. Микросервисы больше не являются частью единого проекта и репозитория в системе контроля версий, и разрабатывающие их команды теперь свободны делать любой выбор, эффективно позволяющий решить задачу, стоящую перед компонентом. Это открывает двери для быстро меняющегося мира технологий, и когда-то сделанный выбор архитектуры и языка для одного компонента больше не диктует того же новым компонентам и сервисам.
Гораздо меньший размер и менее связанная с другими компонентами функциональность позволяет программистам быстро проводить в жизнь новые идеи, рефакторинг кода, и пробовать новые подходы и процессы разработки. Разумный размер кода делает процесс разработки эффективным и удобным. Это же позволяет проще настроить системы постоянного контроля качества и развертывания сделанных изменений на сервере (CI/CD, continuous integration and delivery), и сделать их работу прозрачной и высокопроизводительной, позволяя программистам быстро проверить, было ли их последнее изменение удачным.
Обратной стороной компонентной разработки в распределенной среде является отсутствие гарантии работоспособности – любой сетевой вызов, в отличие от вызова функции внутри единого процесса, подвержен отказам и сбоям, иногда в течение долгого времени. Размытые границы между микросервисами диктуют аккуратный выбор протоколов и передаваемых структур данных. Тестировать взаимодействие микросервисов, взаимодействующих по сети, иногда бывает крайне сложно.
Мы подробнее рассмотрим некоторые аспекты дизайна и разработки микросервисов и похожих на них компонентов в отдельной главе.
Мы только что увидели, как много потенциальных преимуществ может принести с собой разбиение приложения на независимые компоненты, или микросервисы. Особенно они важны для программистов, получающих намного больше свободы в своих экспериментах и выборе технологии. Однако запуск таких компонентов должен быть быстрым, а взаимодействующие технологии должны уживаться на одних и тех же серверах (в пределах кластера) без конфликтов и сложных конфигураций.
Решить эту задачу можно виртуальными машинами, запуская на них микросервисы. Однако виртуальная машина требует установки и запуска отдельной, самостоятельной операционной системы, и время ее запуска делает быстрое масштабирование и перезапуск компонентов практически невозможным. Как мы уже поняли, эту задачу берут на себя контейнеры с их легкой виртуализацией с помощью возможностей Linux (при необходимости можно запускать контейнеры и на других операционных системах). Время запуска контейнера практически неотличимо от обычного процесса Linux, а изоляция приложений, их файловых систем, и ограничение их ресурсов мало чем отличается от полноценной виртуальной машины.
Все содержимое (файлы и зависимости приложения или его части), необходимое для запуска контейнеров, упаковывается в образы (image). Важным свойством образа является его неизменность (immutability), для каждой отдельной метки, или версии, этого образа. Поменять помеченный определенным способом образ с известной контрольной суммой уже невозможно. С практической точки зрения это означает, что созданная когда-то система, настроенная и работающая с определенным набором микросервисов, упакованных в образы для запуска в виде контейнеров, теперь всегда может быть заново воспроизведена в любой необходимый момент. Это важное качество воспроизводимости (reproducibility) гарантирует уверенность в текущем состоянии сложной, составной системы. Мы можем быть уверены в том, что работающая система не была запущена давно потерянным и никому больше не известным набором эзотерических скриптов.
В главе про контейнеры мы подробнее узнаем историю виртуальных машин и контейнеров, чуть подробнее взглянем на механизмы их работы, и на основной инструмент разработчика для работы с контейнерами – Docker.
Эта книга для разработчиков, и для нас, после того как мы создаем серверное приложение или сервис, зачастую начинается довольно туманный период его реальной эксплуатации (production), на основных серверах компании. Классически управлением и запуском готового выпуска приложения заведуют администраторы, или операторы (operators), заведующие всеми деталями настройки и управления серверами. Операторы могут использовать совершенно отдельный от разработки процесс запуска, и свои собственные инструменты для управления настройками серверов.
Для разработчиков в подобном процессе эксплуатации исправление и анализ ошибок или нестандартных ситуаций может стать настоящей головной болью. Если управление эксплуатацией совершенно отделено от выпуска и тестирования новых версий, анализ и воспроизведение ошибок особенно сложны, так как настройки и версии операционных систем и их зависимостей могут значительно отличаться от тех, что используются при тестировании или локальной отладке.
Особенно тяжело управлять и анализировать поведение большой серверной системы в случае, если каждый сервер представляет собой уникальную «снежинку» (этот термин предложил Мартин Фаулер), то есть обладает уникальным набором настроек и конфигураций операционной системы и ее аппаратного обеспечения. В этом случае функциональность системы сливается с уникальностью сервера и становится очень трудно воспроизводимой, и довольно нестабильной.
Гораздо проще восстанавливать и копировать сервер, если он представляет собой «феникса», способного быстро восстановиться из заранее подготовленного образа («пепла», если выражаться в терминах легенды). Еще лучше, если этот образ не бинарная копия диска, а список четких инструкций, по шагам восстанавливающих состояние сервера из известных проверенных компонентов. Эта инструкция хранится в системе контроля версий с историей всех изменений. Примеры – известные инструменты Terraform и Ansible. Сервер, созданный по инструкции, всегда будет одинаковым, и таким образом, обеспечит неизменяемую инфраструктуру приложения (immutable infrastructure).
Если и разработчики, и операторы имеют доступ к легко читаемой, легко восстанавливаемой конфигурации своих серверных систем и кластеров, процесс передачи выпущенных сервисов из разработки в эксплуатацию становится прозрачным и легко поддерживаемым. Восстановление среды для тестирования или эксплуатации не представляет собой проблем. Слияние процессов разработки и управления иногда еще называют процессом DevOps (девопс, development + operations).
Облачные сервера как нельзя лучше подходят для реализации упомянутых выше «фениксов», проверенных, неизменяемых серверов c прозрачной историей. Публичные провайдеры облака, такие как Amazon AWS, Google GCP или Yandex.Cloud, создают свои виртуальные или реальные сервера из тщательно проверенных, безопасных версий известных операционных систем, которые не будут внезапно меняться в процессе работы сервера. Ваша команда DevOps затем может использовать подготовленные заранее инструкции для дополнительной автоматической настройки этих серверов.
В мире контейнеров все становится еще проще. Провайдеры облака как правило предоставляют оптимизированную операционную систему для запуска контейнеров (чаще всего это особая версия Linux). Все зависимости и дополнительные настройки вы производите уже внутри самого контейнера, и указываете их при создании его образа, помечая его версией. Эта версия затем может многократно запускаться в виде контейнера и уже никогда не меняется. Управление сложными серверными конфигурациями значительно упрощается, и по сути, любой член команды, работающей в формате DevOps, способен без особого труда построить и восстановить любую конфигурацию системы, от тестирования до реальной эксплуатации, просто используя доступное в системе контроля версий описание развертывания и запуска системы.
Наконец, основные провайдеры облака как правило обладают мощными центрами данных. При недостатке вычислительной мощности и росте популярности вашего приложения вы сможете динамично расширить свой кластер, добавить в него новые сервера, и запустить на них необходимое количество экземпляров ваших микросервисов. Автоматизирует этот процесс оркестратор Kubernetes.
Получив неизменную, эластичную инфраструктуру, и все преимущества изоляции и быстрого запуска контейнеров, необходим инструмент, обладающий достаточной мощью и гибкостью для управления ими. Оркестратор Kubernetes, созданный на основе проверенной годами в компании Google системы управления контейнерами Borg, обладает всем необходимым для запуска и управления сложными системами, развернутыми в облаке. Все основные коммерческие провайдеры облака, Google Cloud, AWS, Azure, российские Yandex.Cloud, #CloudMTS и остальные, в обязательном порядке предоставляют сервисы на основе Kubernetes.
Стандарт
О проекте
О подписке