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

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

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

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

Для получения преимуществ от использования платформы Docker были разработаны несколько технологий. С прицелом на использование Docker была разработана очень интересная операционная система CoreOS. Это урезанная до минимума операционная система Linux, предоставляющая только важнейшие службы, позволяющие работать платформе Docker. Это означает, что она потребляет меньше ресурсов, чем другие операционные системы, позволяя выделять используемой машине еще больше ресурсов для наших контейнеров. Вместо использования диспетчера пакетов, подобного deb- или RPM-диспетчерам, все программы устанавливаются как независимые Docker-приложения, каждое из которых запускается в собственном контейнере.

Сам Docker всех проблем за нас не решает. Его нужно представлять в качестве простой PaaS-платформы, работающей на одной машине. Если требуется инструментарий, помогающий управлять сервисами, разбросанными по нескольким Docker-экземплярам и нескольким машинам, нужно поискать другие программы, добавляющие такие возможности. К основным потребностям относится уровень диспетчеризации, позволяющий запрашивать контейнер, после чего он находит Docker-контейнер, который может запустить для вас. Оказать помощь в этой области могут принадлежащая Google недавно разработанная технология с открытым кодом Kubernetes и имеющиеся в CoreOS кластерные технологии. И похоже, что новички в этой области появляются чуть ли не каждый месяц. Еще одним интересным средством на основе Docker является Deis. Оно пытается предоставить поверх Docker PaaS-платформу, похожую на Heroku.

Ранее я уже говорил о PaaS-решениях. Я всегда вел борьбу с ними из-за того, что они довольно часто неправильно понимают уровень абстракции, а самостоятельно принимаемые решения существенно отстают от таких уже принятых решений, как Heroku. Docker получает намного больше прав, и резкий подъем интереса в этой области означает, как я предполагаю, что это средство через несколько лет станет намного более жизнеспособной платформой для всех разновидностей развертываний и всех разнообразных вариантов применения. Во многих отношениях Docker с соответствующим уровнем диспетчеризации располагается между решениями IaaS и PaaS, и для его описания уже использовался термин «контейнеры в качестве сервиса» (Containers as a Service (CaaS)).

Docker используют в производственном режиме несколько компаний. Он совместно со средствами, помогающими исключить многие недостатки, обеспечивает множество преимуществ, присущих облегченным контейнерам, в показателях эффективности и скорости предоставления контейнеров. Если вас интересуют альтернативные платформы развертывания, то я настоятельно советую присмотреться к Docker.

Интерфейс развертывания

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

Проработав в этой области много лет, я убежден, что наиболее разумным способом запуска любого развертывания является единый вызов инструкции командной строки с указанием нужных параметров. Инструкция может вызываться из сценария, ее выполнение может инициироваться вашим CI-средством, или же она может набираться вручную. Для выполнения этой работы я создавал сценарии-оболочки в различных технологических стеках, от пакетных файлов Windows до bash, а также до Python Fabric-сценариев и т. д., но все инструкции командной строки использовали один и тот же основной формат.

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

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

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

$ deploy artifact=catalog environment=local version=local

После того как будет проведена проверка, CI-сборка сервиса получает изменение и создает новый сборочный артефакт, присваивая сборке номер b456 в соответствии со стандартом, принятым в большинстве CI-средств. Это значение проводится по всему конвейеру. Когда запускается наша стадия тестирования, при выполнении CI-стадии может быть написано следующее:

$ deploy artifact=catalog environment=ci version=b456

Тем временем контролю качества потребовалось поместить последнюю версию сервиса каталога в интегрированную тестовую среду для выполнения исследовательского тестирования и оказания помощи в оформлении проспекта. Эта команда написала следующую инструкцию:

$ deploy artifact=catalog environment=integrated_qa version=latest

Чаще всего для этого я пользуюсь Fabric, библиотекой языка Python, предназначенной для отображения вызовов командной строки на функции, наряду с такой хорошей поддержкой задач обработки на удаленных машинах, как SSH. Соедините это с такой клиентской библиотекой AWS, как Boto, и у вас будет все необходимое для полной автоматизации очень крупных сред AWS. Для Ruby в некотором роде аналогом Fabric может послужить Capistrano, а для Windows можно воспользоваться PowerShell.

Определение среды. Разумеется, чтобы все это заработало, нужен способ определения того, на что похожа наша среда и на что похож наш сервис в заданной среде. Определение среды можно представить себе как отображение микросервиса на вычислительные ресурсы, сетевые ресурсы или ресурсы хранилища. Раньше я делал это с помощью YAML-файлов и для помещения в них данных использовал свои сценарии. В примере 6.1 показана упрощенная версия той работы, которую я делал года два назад для проекта, использующего AWS.


Пример 6.1. Пример определения среды

development:

nodes:

—ami_id: ami-e1e1234

size: t1.micro (1)

credentials_name: eu-west-ssh (2)

services: [catalog-service]

region: eu-west-1

production:

nodes:

—ami_id: ami-e1e1234

size: m3.xlarge (1)

credentials_name: prod-credentials (2)

services: [catalog-service]

number: 5 (3)

1. Размер используемых экземпляров варьируется с целью получения более высокого экономического эффекта. Для исследовательского тестирования не нужна 16-ядерная стойка с 64 Гбайт оперативной памяти!

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

3. Мы решили, что по умолчанию, если у сервиса имелось более одного сконфигурированного узла, для него будет автоматически создаваться система обеспечения сбалансированности нагрузки.

Некоторые детали для краткости были удалены.

Информация о сервисе каталога была сохранена в другом месте. Как видно из примера 6.2, от среды к среде она не изменяется.


Пример 6.2. Пример определения среды

catalog-service:

puppet_manifest: catalog.pp (1)

connectivity:

—protocol: tcp

ports: [8080, 8081]

allowed: [WORLD]

4. Это было имя запускаемого Puppet-файла. Так уж получилось, что в данной ситуации мы использовали только Puppet, но теоретически могли бы воспользоваться и поддержкой альтернативных систем управления настройками.

Вполне очевидно, что многие моменты поведения были основаны на соглашениях. Например, мы решили нормализовать используемые сервисом порты, где бы он ни запускался, и автоматически настроили систему обеспечения сбалансированности нагрузки в том случае, если у сервиса имеется более одного экземпляра (в AWS с этим довольно легко справляется ELB).