Создание микросервисов — страница 32 из 69

Итак, мы можем создать образы виртуальной машины с зафиксированными зависимостями для ускорения отдачи, но стоит ли на этом останавливаться? Можно ведь пойти дальше и зафиксировать сервис в самом образе, приспособить модель артефакта сервиса в качестве образа. Теперь, запуская образ, мы получаем готовый к работе сервис. Этот действительно быстрый способ подготовки к работе является причиной того, что в Netflix была принята модель фиксирования его собственных сервисов в качестве AWS AMI-образов.

Как и в случае применения пакетов, характерных для конкретной операционной системы, эти VM-образы становятся отличным способом абстрагирования от различий в технологических стеках, используемых для создания сервисов. Разве нас волнует, что сервис, запущенный в образе, написан на Ruby или Java и использует gem-пакет или JAR-файл? Нам интересно только то, что все это работает. Тогда мы можем сконцентрировать усилия на автоматизации создания и развертывания этих образов. К тому же это становится отличным способом реализации другой концепции развертывания — неизменяемого сервера.

Неизменяемые серверы

При хранении всех наших настроек в системе управления версиями мы стремимся обеспечить возможность автоматизированного воспроизводства сервисов и, надеюсь, при желании — всей среды. Но что случится, если мы запустили процесс развертывания, а кто-то войдет в систему и внесет изменения независимо от того, что находится в системе управления версиями? Эту проблему часто называют дрейфом конфигурации — код в системе управления версиями больше не является отражением конфигурации на работающем хосте.

Во избежание этого можно обеспечить невозможность внесения изменений в работающий сервис. Любое, даже самое незначительное, изменение должно пройти через сборочный конвейер, чтобы была создана новая машина. Эту схему можно реализовать без использования развертывания на основе образа, но оно также является логическим расширением использования образов в качестве артефактов. Например, в ходе создания образа можно отключить SSH, гарантируя тем самым, что никто не сможет даже войти в систему для внесения какого-либо изменения!

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

Среды

При проходе программы через стадии CD-конвейера она также будет развернута в средах различных типов. Если обратиться к примеру сборочного конвейера (см. рис. 6.4), то нужно, наверное, рассмотреть как минимум четыре различные среды: для запуска медленных тестов, тестирования на приемлемость для пользователя, тестирования на производительность и работы в производственном режиме. Наш микросервис должен быть везде одинаков, но среды будут разными. По крайней мере, они должны быть обособленными, с отдельными наборами конфигураций и хостов. Но зачастую они могут отличаться друг от друга еще значительнее. Например, среда, предназначенная для работы сервиса в производственном режиме, может состоять из нескольких сбалансированных по нагрузке хостов, разбросанных по двум дата-центрам, а все компоненты среды, предназначенной для тестирования, могут быть запущены всего на одном хосте. Такие различия в средах могут вызвать ряд проблем.

Мне приходилось испытывать это на себе много лет назад. Мы развертывали веб-сервис Java в производственном кластерном контейнере WebLogic-приложения. Этот WebLogic-кластер реплицировал состояние сессии между несколькими узлами, обеспечивая некоторую степень устойчивости при сбое отдельного узла. Но лицензии на использование WebLogic, под которыми было развернуто приложение, а также машины, на которых оно было развернуто, обходились довольно дорого. Поэтому среда для тестирования и программы были развернуты на одной машине в некластерной конфигурации.

И во время одного из выпусков это обстоятельно нанесло нам существенный вред. Чтобы у WebLogic была возможность копировать состояние сессии между узлами, данные сессии должны поддаваться сериализации. К сожалению, одна из наших фиксаций разрушала этот процесс, поэтому при развертывании для работы в производственном режиме репликация сессии дала сбой. В итоге мы решили проблему, приложив большие усилия для имитации кластеризованной настройки в нашей среде тестирования.

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

По мере перехода с ноутбука на сборочный сервер, с него — в среду тестирования на приемлемость для пользователя, а дальше — в производственную среду нужно обеспечивать, чтобы среды постепенно приобретали все больше и больше свойств производственной среды, чтобы можно было отловить проблемы, связанные с разницей этих сред, как можно раньше. Этот баланс будет носить постоянный характер. Иногда затраты времени и средств на воспроизводство сред, сходных с производственными, бывают непомерно высокими, поэтому приходится идти на компромиссы. Кроме того, иногда использование сред, сходных с производственными, может замедлить циклы получения ответных результатов, поскольку ожидание того, пока на 25 машинах установится ваша программа в AWS, может быть намного продолжительнее простого развертывания сервиса, к примеру на локальном Vagrant-экземпляре.

Баланс между средами, подобными производственной среде, и быстрым получением ответных результатов не будет статичным. Следите за количеством ошибок, выявляемых по мере прохождения сред, и за показателями сроков получения обратных ответов и перенастраивайте этот баланс по мере необходимости.

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

Конфигурация сервиса

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

Следовательно, если у нас есть некая настройка для сервиса, изменяющаяся от одной среды к другой, как мы можем справиться с этим как с частью процесса развертывания? Одним из вариантов является создание по одному артефакту для каждой среды с конфигурацией внутри самого артефакта. Поначалу этот вариант представляется весьма разумным. Конфигурация встроена, нужно лишь развернуть артефакт, и все будет работать. Но так ли это? Не так-то все просто. Вспомните о концепции непрерывной доставки. Нам нужно создать артефакт, представляющий сдаточную версию, и провести его по конвейеру, убеждаясь, что он вполне подходит для передачи в производство. Представим, что мною созданы артефакты для тестирования клиентской службы — Customer-Service-Test и для ее работы в производственном режиме — Customer-Service-Prod. Если артефакт Customer-Service-Test пройдет тесты, а я фактически развертываю артефакт Customer-Service-Prod, могу ли я быть уверенным в том, что проверена была программа, которая окажется в производстве?

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

Более подходящим подходом будет создание одного-единственного артефакта и раздельное управление конфигурацией. Это могут быть файл свойств, имеющийся для каждой среды, или различные параметры, передаваемые в процесс установки. Еще одним широко распространенным вариантом, особенно при работе с большим количеством микросервисов, является использование для предоставления конфигурации специально выделенной системы, которая подробнее исследуется в главе 11.

Отображение сервиса на хост

Когда речь заходит о микросервисах, в самом начале возникает вопрос: «А сколько сервисов может быть на каждой машине?» Перед тем как дать ответ, нужно подобрать более подходящее понятие, чем «машина» или даже использованное мною ранее более универсальное понятие «стойка». В нашу эру виртуализации отображение между отдельно взятым хостом, на котором работает операционная система, и используемой физической инфраструктурой может варьироваться в самых широких пределах. Я, например, склонен говорить о хостах, используя их как универсальную единицу изолированности, а именно как операционную систему, под управлением которой могу установить и запустить свои сервисы. Если развертывание ведется вами непосредственно на физические машины, тогда один физический сервер отображается на один хост (что, возможно, будет не вполне корректной терминологией в данном контексте, но за неимением лучшей может считаться подходящей). Если используется виртуализация, то отдельная физическая машина может отображаться на несколько независимых хостов, каждый из которых может содержать один сервис и более.