Краткое введение в Docker Swarm mode

docker swarmDocker — прекрасен. С ним можно упаковать приложение по контейнерам, забросить их на случайный хост, и всё будет просто работать. Но на одном хосте особо не отмасштабируешься. Да и если хост прикажет долго жить, всё приложение отправится на тот свет вместе с ним. Конечно, для масштабирования можно завести сразу несколько хостов, объединить их при помощи overlay сети, так что и места больше будет, и возможность для контейнеров общаться останется.

Но опять же, как всем этим управлять? Хосты всё ещё могут отмирать. Как быстро определить, какой именно? Какие контейнеры на нём были? Куда теперь их переносить?

Начиная с версии 1.12.0 Docker может работать в режиме Swarm («Рой». В старых версиях был просто Docker Swarm, но тот работал по-другому), и потому способен решать все эти проблемы самостоятельно.

Что такое режим Swarm

Docker в Swarm режиме это просто Docker Engine, работающий в кластере. Кроме того, что он считает все кластерные хосты единым контейнерным пространством, он получает в нагрузку несколько новых команд (вроде docker node и docker service) и концепцию сервисов.

Сервисы — это ещё один уровень абстракции над контейнерами. Как и у контейнера, у сервиса будет имя, базовый образ, опубликованные порты и тома (volumes). В отличие от контейнера, сервису можно задать требования к хосту (constraints), на которых его можно запускать. Да и вообще, сервис можно масштабировать прямо в момент создания, указав, сколько именно контейнеров для него нужно запустить.

Но важно понимать одну большую разницу. Сама по себе команда docker service create не создаёт никаких контейнеров. Она описывает желаемое состояние сервиса, а дальше уже Swarm менеджер будет искать способы это состояние достигнуть. Найдёт подходящие хосты, запустит контейнеры, будет следить, чтобы с ними (и хостами под ними) всё было хорошо, и перезапустит контейнер, если «хорошо» закончится. Иногда желаемое состояние сервиса так и не будет достигнуто. Например, если в кластере закончились доступные хосты. В таком случае сервис будет висеть в режиме ожидания до тех пор, пока что-нибудь не изменится.

План на сегодня

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

Что понадобится

Нам понадобится установленный Docker версии 1.12.0 и новее, docker-machine и VirtualBox. Первые два обычно устанавливаются вместе c Docker Toolbox на Маке и Windows. На Linux, ЕМНИП, docker-machine устанавливается отдельно, но всё ещё достаточно понятно. С установкой же VirtualBox проблем вообще не бывает. Обычно.

Я буду использовать Docker 17.03.1-ce для Mac и VirtualBox 5.1.20

Шаг 0. Создаём три виртуальные машины

Создавать машины при помощи именно docker-machine  имеет смысл хотя бы потому, что они сразу будут идти с предустановленным Docker. Из трёх хостов на одном мы поселим менеджера Swarm, а на двух других — обычных рабочих. Собственно, создание виртуальных машин — удивительно безболезненное занятие:

Шаг 1. Создаём Swarm

Есть две команды, которые подойдут для того, чтобы превратить одинокий Docker Engine в участника кластера: docker swarm init для новых кластеров и  docker swarm join для уже существующих. Кластера у нас ещё нет, так что заходим по ssh в sw-master и делаем из него кластер:

Первый хост кластера стал к тому же и менеджером — больше ведь нет никого. Сама по себе команда создания кластера оказалась настолько любезной, что даже вернула в ответ другую команду (строки 7-9), при помощи которой можно подключить к кластеру остальные хосты.  --token параметр в ней — секретный ключ, в который кроме секретов забито, в какой роли новые хосты будут входить в кластер (обычные работяги). Если токен потерять, или вместо рабочего хоста мы хотим добавить ещё одного менеджера, то получить новый токен можно через docker swarm join-token [manager].

Кстати, из-за того, что в виртуалках, созданных VirtualBox, есть аж два сетевых интерфейса и, соответственно, две айпишки, мне пришлось явно указать кластеру, на какую из них вешаться: --advertise-addr.

Теперь выходим из машины, и заходим поочерёдно в другие хосты и тоже подключаем их к кластеру той самой командой, которую вывел docker swarm init.

Верьте или нет — кластер абсолютно и бесповоротно готов. Если выйти из виртуальной машины и подключить локального докер клиента к Swarm менеджеру ( eval $(docker-machine env sw-manager ) ), то можно даже попробовать какую-нибудь из новых команд. Например, docker node ls:

Шаг 2. Создаём сервис визуализации кластера

У Docker, оказывается, есть публичный образ visualizer для отрисовки кластера. На его примере можно и показать, как создавать сервис, так и протаращиться на красивую картинку. Итак, команда (я потом всё объясню):

Что именно она делает, построчно:

  1. docker service create — всё просто, создаём сервис. На самом деле, команда очень, очень похожа на docker run и в большинстве случаев она тоже приводит к запущенному контейнеру.
  2. --name=viz — имя сервиса. Один-в-один как в docker run.
  3. --publish=8080:8080 — это старая добрая команда привязки портов контейнера к портам хоста, как и -p в docker run. Просто в полной форме.
  4. --constraint=node.role==manager — этот параметр говорит, что запускать сервис можно только на хостах-менеджерах. Это нужно для того, чтобы  visualizer‘у было у кого запрашивать данные о состоянии кластера.
  5. --mount=... — хотя это самая длинная строка-параметр, она вполне простая. /var/run/docker.sock — это сокет, через который Docker может принимать команды извне. Мы просто пробрасываем его в контейнер (src, dst), чтобы тот мог по нему общаться. Вот и всё. В принципе, mount делает всё то же самое, что и -v (volume) в docker run.
  6. dockersamples/visualizer — старое доброе имя образа, из которого потом будут делаться контейнеры.

Пока команда выполняется, у нас будет шанс позапрашивать состояние сервиса при помощи docker service ls (состояние сервиса) и docker service ps (состояние связанных с ним задач). Мне удалось поймать «промежуточное» состояние, когда сервис ещё не готов (current state: preparing):

Айпишка моего Swarm менеджера — 192.168.99.101 (docker-machine ip sw-master), так что по ней и порту 8080 можно посмотреть на работу visualizer сервиса:

visualizer: one service

Красота.

Шаг 3. Маштабируем сервис и замеряем его производительность

По умолчанию Swarm будет размещать контейнеры нового сервиса в самом пустом на данный момент хосте, поэтому в реалиях нашего кластера команда  docker service create --name=web --publish=80:80 nginx запустит новый web сервис на одном из двух обычных рабочих хостов:

nginx service

Но это не самая интересная часть. Самая интересная часть заключается в том, что web сервис всё ещё можно запрашивать по айпишке хоста-менеджера — 192.168.99.101. Да что там, его можно запросить вообще на любом хосте кластера:

nginx at master

Прикол в том, что открытие порта в сервисе/контейнере в Swarm кластере открывает его на всех машинах. Это очень удобно, когда мы масштабируем сервис. То есть запускаем сразу несколько его копий (реплик). При таком сценарии Swarm начинает работать ещё и как балансировщик нагрузки и равномерно распределяет запросы по контейнерам, с какой бы стороны кластера они не поступали. С этой фичей мы сейчас и поиграем.

Во-первых, отмасштабируем web сервис. Двух реплик для начала будет достаточно.

nginx: two replicas

Если Swarm действительно работает как балансировщик нагрузки, то по идее мы сможем заметить рост пропускной способности web и даже её замерить. У меня каким-то образом завалялся Apache Bench, который для таких целей вполне сгодится, и я попробую нагрузить сервис десятью тысячами запросов в пятидесяти потоках и посмотрю, сколько запросов в секунду он может переварить. Затем оставлю только одну копию web, и ещё раз замерю его пропускную способность.

nginx scaled down

Прикольно. Две реплики web сервиса были даже больше чем в два раза производительнее, чем одна — 1925 запросов в секунду против 745. Скорее всего, если бы я сделал хотя бы по 10 замеров, числа были бы более правдоподобными, но всё равно тенденция понятна: больше реплик — больше вычислительных способностей.

Шаг 4. Проверка на живучесть

Пост получился очень большим, но я не могу поставить точку без последнего, простенького теста. Оставшийся web сервис теперь живёт на sw-worker-2. Что с ним произойдёт, если хост отойдёт в лучший из миров? Будем проверять.

Не особо удивительно, что через несколько секунд после эвтаназии sw-worker-2 web сервис реинкарнировался на sw-worker-1.  Swarm менеджер заметил, что заявленная конфигурация сервиса больше не выполняется — вместо одного запущенного контейнера есть ноль — и восстановил баланс сил на новом хосте.

nginx-resurrect

Мораль

Если Докер просто классный, то Swarm — восхитительно прекрасен. Кластер делается элементарно, он автоматом идёт с балансировкой нагрузки, проверкой контейнерной смертности и масштабируемостью. И это далеко не все его фичи. Лично я собираюсь использовать Swarm даже на одиночных машинах. Хотя бы потому, что он сам будет следить, чтобы контейнеры были перманентно живыми.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *