babd31d7c5640845003a221d725ce0a1ff83f9827f839781372b1fcc629009cb
essh@kubernetes-master:~/consul$ docker exec -t dev-consul consul members
Node Address Status Type Build Protocol DC Segment
53cd8748f031 172.17.0.5:8301 left server 1.6.1 2 dc1 < all>
8ec88680bc63 172.17.0.5:8301 alive server 1.6.1 2 dc1 < all>
babd31d7c564 172.17.0.6:8301 alive server 1.6.1 2 dc1 < all>
essh@kubernetes-master:~/consul$ curl -X PUT -d 'value1' 172.17.0.4:8500/v1/kv/group1/key1
true
essh@kubernetes-master:~/consul$ curl $(docker inspect dev-consul | jq -r ' .[] | .NetworkSettings.Networks.bridge.IPAddress'):8500/v1/kv/group1/key1
[
{
"LockIndex": 0,
"Key": "group1/key1",
"Flags": 0,
"Value": "dmFsdWUx",
"CreateIndex": 277,
"ModifyIndex": 277
}
]
essh@kubernetes-master:~/consul$ firefox $(docker inspect dev-consul | jq -r ' .[] | .NetworkSettings.Networks.bridge.IPAddress'):8500/ui
С определением местоположения контейнеров необходимо обеспечить авторизацию, для этого используются хранилища ключей.
dockerd -H fd:// cluster-store=consul://192.168.1.6:8500 cluster-advertise=eth0:2376
* cluster-store можно получать данные о ключах
* cluster-advertise можно сохранять
docker network create driver overlay subnet 192.168.10.0/24 demo-network
docker network ls
Простая кластеризация
В данной стать мы не будем рассматривать как создать кластер вручную, а воспользуемся двумя инструментами: Docker Swarm и Google Kubernetes наиболее популярные и наиболее распаренные решения. Docker Swarm проще, он является частью Docker и поэтому, имеет наибольшую аудиторию (субъективно), а Kubernetes предоставляет гораздо большие возможности, большее число интеграций с инструментами (например, распределённое хранилище для Volume), поддержка в популярных облаках и более просто масштабируемый для больших проектов (большая абстракция, компонентный подход).
Рассмотрим, что такое кластер и что он нам хорошего принесёт. Кластер это распределённая структура, которая абстрагирует независимые сервера в одну логическую сущность и автоматизирует работу по:
* случае падения одного сервера, переброс контейнеров (создания новых) на другие сервера;
* равномерное распределение контейнеров по серверам для отказоустойчивости;
* создание контейнера на сервере, подходящем по свободным ресурсам;
* Разворачивание контейнера, в случае выхода его из строя;
* единый интерфейс управления из одной точки;
* выполнения операций с учётом параметров серверов, например, размера и типа диска и особенностей контейнеров, заданных администратором, например, связанные контейнера единым точкой монтирования размещаются на данном сервере;
* унификация разных серверов, например, на разных ОС, облачных и не облачных.
Теперь мы перейдём от рассмотрения Docker Swarm к Kubernetes. Обе эти системы системы оркестрации, обе работаю с контейнерами Docker (Kubernetes также поддерживает RKT и Containerd), но взаимодействий между контейнерами принципиально другое из-за дополнительного уровня абстракции Kubernetes POD. И Docker Swarm, и Kubernetes управляют контейнерами на основе IP адресов и распределяют их по нодам, внутри которых всё работает через localhost, проксируемый мостом, но в отличии от Docker Swarm, который работает для пользователя с физическими контейнерами, Kubernetes для пользователя работает с логическими POD. Логический контейнер Kubernetes состоит из физических контейнеров, сетевое взаимодействие, между которыми происходит через их порты, поэтому они не дублируются.
Обе системы оркестрации используют оверлейную сеть (Overlay Network) между нодами хостами для эмуляции нахождения управляемых единиц в едином локальном сетевом пространстве. Данный тип сети является логическим типом, который использует для транспорта обычные сети TCP/IP и призвана эмулировать нахождение нод кластера в единой сети для управления кластером и обмена информации между его нодами, тогда как на уровне TCP/IP они не могут быть связанны. Дело в том, что, когда разработчик разрабатывает кластер, он может описать сеть только для одной ноду, а при развёртывании кластера создаётся несколько его экземпляров, причём их количество может динамически меняться, а в одной сети не может существовать трёх нод с одним IP адресами и подсетями (например, 10.0.0.1), а требовать от разработчика указывать IP адреса неправильно, поскольку не известно, какие адреса свободны и сколько их потребуется. Данная сеть берёт на себя отслеживания реальных IP адресов узлов, которые могут выделяться из свободных рандомно и меняться по мере пересоздания нод в кластере, и предоставляет возможность обращаться к ним через ID контейнеров/ POD. При таком подходе пользователь обращается к конкретным сущностям, а не динамики меняющимся IP адресам. Взаимодействие осуществляется с помощью балансировщика, который для Docker Swarm логически не выделен, а в Kubernetes он создаётся отдельной сущностью для выбора конкретной реализации, как и другие сервисы. Подобный балансировщик должен присутствовать в каждом кластере и, но называется в рамках экосистемы Kubernetes сервисом (Service). Его можно объявить, как отдельно как Service, так и в описании с кластером, например, как Deployment. К сервису можно обратиться по его IP-адресу (посмотреть в его описании) или по имени, которое регистрируется как домен первого уровня во встроенном DNS сервере, например, если имя сервиса, заданного в метаданных my_service, то к кластеру можно обратиться через него так: curl my_service;. Это является довольно стандартным решением, когда компоненты системы вместе с их IP адресами меняются со временем (пересоздаются, добавляются новые, удаляются старые) направлять трафик через прокси сервер, IP или DNS адреса для внешней сети остаются постоянными, а внутренние могут меняться, оставляя заботу согласование их на прокси сервере.
Обе системы оркестрации использую оверлейную сеть Ingress для предоставления к себе доступа из внешней сети через балансировщик, который согласует внутреннею сеть с внешней на основе таблиц соответствия IP адресов ядра Linux (iptalbes), разделяя их и позволяя обмениваться информацией, даже при наличии одинаковых IP адресов во внутренней и внешней сети. А, вот, для поддержания соединения между этими потенциально конфликтными на IP уровне сетями используется оверлейная Ingress сеть. Kubernetes предоставляет возможность создать логическую сущность контроллер Ingress, который позволит настроить сервис LoadBalancer или NodePort в зависимости от содержимого трафика на уровне выше HTTP, например, маршрутизацию на основе путей адресов (application router) или шифрование трафика TSL/HTTPS, как это делаю GCP и AWS.
Kubernetes результат эволюции через внутренне проекты Google через Borg, затем через Omega, на полученном опыте от экспериментов сложилась довольно масштабируемая архитектура. Выделим основные типы компонентов:
* POD обычный POD;
* ReplicaSet, Deployment масштабируемые POD;
* DaemonSet в каждой ноде кластера он создаётся;
* сервисы (отсортированы по мере важности): ClusterIP (по умолчанию, базовый для остальных), NodePort (перенаправляет порты, открытые в кластере, у каждого POD, на порты из диапазона 3000032767 для обращения к конкретным POD из внешней), LoadBalancer (NodePort с возможностью создания публичного IP-адреса для доступа в интернет в таких публичных облаках, как AWS и GCP), HostPort (открывает порты на хостовой машине соответствующие контейнеру, то есть если в контейнере открыт порт 9200, он будет открыт и на хостовой машине для прямого перенаправления трафика) и HostNetwork (контейнеры в POD будут находиться в сетевом пространстве хоста).
Мастер как минимум содержит: kube-APIserver, kube-sheduler и kube-controller-manager. Состав слейва:
* kubelet проверка работоспособности компонента системы (ноды), создание и управление контейнерами. Он находится на каждой ноде, обращается к kube-APIserver и приводит в соответствие ноду, на которой расположен.
* cAdviser мониторинг ноды.
Допустим у на есть хостинг, и мы создали три AVS сервера. Теперь необходимо на каждый сервер установить Docker и Docker-machine, о том, как это сделать было рассказано выше. Docker-machine сама является виртуальной машиной для Docker контейнеров, мы соберём лишь внутренний для неё драйвер VirtualBox чтобы не устанавливать дополнительные пакеты. Теперь, из операций, которые должны быть выполнены на каждом сервере останется создать Docker машины, остальные же операции по настройки и созданию контейнеров на них можно выполнять из master-ноды, а они буду автоматически запущены на свободных нодах и перераспределяться при изменении их количества. Итак, запустим Docker-machine на первой ноде:
docker-machine create driver virtualbox virtualbox-cpu-count "2" virtualbox-memory "2048" virtualbox-disk-size "20000" swarm-node-1
docker-machine env swarm-node-1 // tcp://192.168.99.100:2376
eval $(docker-machine env swarm-node-1)
Запускаем вторую ноду:
docker-machine create driver virtualbox virtualbox-cpu-count "2" virtualbox-memory "2048" virtualbox-disk-size "20000" swarm-node-2
docker-machine env swarm-node-2
eval $(docker-machine env swarm-node-2)
Запускаем третью ноду:
docker-machine create driver virtualbox virtualbox-cpu-count "2" virtualbox-memory "2048" virtualbox-disk-size "20000" swarm-node-3
eval $(docker-machine env swarm-node-3)
Подключимся к первой ноде инициализируем в ней распределённое хранилище и передаём ему адрес ноды менеджера (лидера):
docker-machine ssh swarm-node-1
docker swarm init advertise-addr 192.168.99.100:2377
docker node ls // выведет текущий
docker swarm join-token worker
Если токены будут забыты, их можно получить, выполнив в ноде с распределённым хранилищем команды docker swarm join-token manager и docker swarm join-token worker.
Для создания кластера необходимо зарегистрировать (присоединить) все его будущие ноды командой Docker swarm join token 192.168.99.100:2377, для аутентификации используется токен, для их обнаружения необходимо, чтобы они находились в одной подсети. Посмотреть все сервера можно командой docker node info
Команда docker swarm init создаст лидера кластера, пока одинокого, но в полученном ответе будет на неё будет придана команда, необходимая для подключение других нод к этому кластеру, важная информация в котором токен, например, docker swarm join token 192.168.99.100:2377. Подключимся к оставшимся нодам по SSH командой docker-machine SSH name_node и выполним её.
Для взаимодействия контейнеров используется сеть bridge, которая является свитчем. Но для работы нескольких реплик нужна подсеть, так как все реплики будут с одинаковыми портами, а проксирование производится по ip с помощью распределённого хранилища, при этом не имеет значение физически они расположены на одном сервере или разных. Следует сразу заметить, что балансировка осуществляется по правилу roundrobin, то есть поочерёдно к каждой реплике. Важно создать сеть типа overlay для создания DNS по верх неё и возможности обращаться к репликам по им именам. Создадим подсеть: