docker swarm: overlay network,routing mesh


Use overlay networks
Use swarm mode routing mesh

Overlay драйвер создаёт распределенную сеть между несколькими докер хостами. Эта сеть располагается поверх сетей хоста, позволяя контейнерам подключаться к ней для безопасного общения.
Когда инициализируется swarm или добавляется новый хост в уже существующий swarm кластер, то на данном хосте создаётся две новых сети:
— overlay сеть называемая ingress обрабатывающая управляющий трафик и трафик данных связанный с сервисами swarm. Данная сеть используется по умолчанию, если не указана другая сеть при создании сервисов.
— мост называемый docker_gwbridge, соединяющий отдельные докер демоны с другими демонами участвующих в swarm.

overlay сеть создается командой:

docker network create -d overlay ИМЯ_сети

Если необходимо создать overlay сеть, которая может использоваться для связи между серисами swarm(или отдельными контейнерами) и отдельными контейнерами, то используется ключ --attachable:

docker network create -d overlay --attachable ИМЯ_сети

В качестве примера создадим два сервиса drupal и postgres в отдельной overlay сети.

1. создаем новую сеть:
docker network create --driver overlay mydrupal
Данная сеть будет создатна на всех нодах swarm кластера.

Проверяем:
docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
51168766fca1        bridge              bridge              local
dbfab11055d1        docker_gwbridge     bridge              local
264f2aabb021        host                host                local
o63dqprsbnow        ingress             overlay             swarm
vbwuoqwemzkx        mydrupal            overlay             swarm
6dc0c3621ab8        none                null                local


2. запускаем postgres сервис:
docker service create --name psql --network mydrupal -e POSTGRESS_PASSWORD=mypass postgres

docker service  ls // смотрим запущенные сервисы
docker service  ps  psql //смотрим запущенные таски

3. запускаем drupal сервис:
docker service create --name drupal -p 80:80 --network mydrupal drupal

docker service  ls // смотрим запущенные сервисы
docker service  ps  drupal //смотрим запущенные таски

4. Теперь заходим на вебморду друпала, но при этом мы можем использовать любой ip ноды (см routing mesh) в кластаре.
В качестве данных для подключения к бд использовать эти:
Database name: postgres
Database username: postgres
Database password: mypass
Host: psql // указываем имя используемое при создании сервиса

Разделение трафика данных и управляющего трафика

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

Шифрование трафика в overlay сети

Весь управляющий трафик swarm сервисов шифруется по умолчанию с помощью AES в GCM режиме. Менеджер ноды каждые 12 часов сменяют сертификаты используемые для шифрования gossip трафика.
Для шифрования трафика данных необходимо использовать ключ --opt encrypted при создание сети. Это запускает IPSEC шифрование на уровне vxlan. Данное шифрование накладывает незначительные ограничения на производительность, поэтому перед вводом в продакшн лучше протестировать данную опцию.
Когда включается overlay шифрование, докер создает ipsec тунели между всеми нодами где запланирован запуск тасков сервиса подключенного к данной overlay сети. Данные туннели также используют AES в GCM режиме и менеджеры каждые 12 часов сменяют сертификат.

Routing mesh

В примере про postgres и drupal мы подошли к использованию докером routing mesh в swarm.
routing mesh позволяет каждой ноде в swarm кластере принимать соединение на порт для любого сервиса запущенного в swarm, даже если ни одного таска не запущено на данной ноде. routing mesh маршрутизирует все входящие запросы приходящии на порт на доступные ноды активных контейнеров.

1. создадим сервис nginx с одной репликой (в качестве примера не указываю какие порты мапить)
docker service create  --name web nginx

2. теперь модифицируем конфиг сервиса добавив порт
docker service  update web --publish-add 80:80
 
3. Хоть у нас и запущена только одна реплика сервиса, но если обратиться к ip ноды в браузере, 
где не запущен таск, нам все равно будет показана дефолтная страница nginx.

Отключение routing mesh

Есть возможность отключения routing mesh, чтоб при обращении к порту ноды отвечал именно экземпляр там запущенного контейнера, а не сервис запущенный в данном swarm. Делается это указанием host режима ключа mode.

1.Запускаем nginx в двух репликах в режиме host:
docker service create --publish published=80,target=80,mode=host --name web --replicas 2  nginx

2. Смотрим на каких нодах работают таски:
docker service  ps web 
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
m6poizn3yw5y        web.1               nginx:latest        node1               Running             Running 57 seconds ago                       *:80->80/tcp
jnj9c8b5nog8        web.2               nginx:latest        mainnode         Running             Running 35 seconds ago                       *:80->80/tcp

3. Проверяем в браузере - пробуем достучаться до всех наших трёх нод по 80 порту
Видим, что отвечает только две ноды из трёх.

4. На третей ноде, где не запущен таск запускаем отдельный контейнер(предварительно создав файл index.html в нужной папке с любым содержимым):
docker container run -d --name node2web --rm --mount type=bind,src=/home/Docker/nginx/index.html,dst=/usr/share/nginx/html/index.html -p 80:80  nginx

5. Проверяем в браузере -  пробуем достучаться по ip нашей третей ноды на 80 порт.
Видим,  что при ответе отдается index.html нашего отдельного контейнера  node2web.
При этом две первые ноды все еще отдают тот же дефолтный index.html запущенного сервиса web.

Конфигурирование внешнего балансировщика.

Мы можем настроить внешний балансировщик и совместить его с routing mech, либо отключить routing mech и использовать DNS Round Robin (DNSRR) для сервисов swarm.

C routing mech
К примеру использовать HAProxy, как балансировщик запросов на порты 8080 веб серверов(apache,nginx…)

В данном примере порты 8080 каждой из нод должны быть доступны балансеру. Swarm ноды могут находится в приватной сети и не быть доступны напрямую из вне.
Балансер распределят запросы между нодами даже если на ноде не имеется запущенно таска данного сервиса. Т.е. если приходит запрос на публичный ip адрес балансера на порт 80, то запрос переправляется на ноды swarm. А делаее вступает в игру routing mesh, который направит запрос на активную ноду.

Без routing mech
При создании сервиса использовать ключ --endpoint-mode=dnsrr. В этом случае создается DNS запись с необходимым кол-ом A записей равных кол-ву реплик сервиса. Нужно помнить то что DNS работает только в недефолтных сетях.

1. Нужно собрать образ с пакетом dnsutils(я собрал из debian) 
и закачать образ либо в свою приватную репу либо в Docker Hub, в общем разместить там, 
где все ноды swarm кластра смогут скачать данный образ. Иначе все реплики будут запускаться на одной ноде, 
для данного примера это не критично.
2. Создать свою overlay сеть
Пример:
 docker network create --driver=overlay myoverlaynetwork
3. Запустить серис mydnsrr1 с опциями --replicas 3 --endpoint-mode=dnsrr в дефолтной overlay сети ingress
Пример:
 docker service create --name mydnsrr1 --endpoint-mode=dnsrr --replicas 3 mydnsutils tail -f /dev/null
Зайти на ноду, где запущен один из тасков данного сервиса и убедиться что DNS не работает
Пример:
 docker container exec ИМЯ/ID_КОНТЕЙНРА dig mydnsrr1
4. Запустить сервис mydnsrr2 с опциями --replicas 3 --endpoint-mode=dnsrr 
в ранее созданной сети myoverlaynetwork
Пример:
 docker service create --name mydnsrr2 --endpoint-mode=dnsrr --network myoverlaynetwork --replicas 3 mydnsutils tail -f /dev/null
Зайти на ноду, где запущен один из тасков данного сервиса и убедиться что DNS работает
Пример:
 docker container exec ИМЯ/ID_КОНТЕЙНРА dig  mydnsrr2
mydnsrr2.		600	IN	A	10.0.1.54
mydnsrr2.		600	IN	A	10.0.1.64
mydnsrr2.		600	IN	A	10.0.1.63
5. Запустить сервис myvip1 с опциями --replicas 3 --endpoint-mode=vip (<- данная опция дефолтна, указал в качестве примера) 
в ранее созданной сети myoverlaynetwork
Пример:
 docker service create --name myvip1 --endpoint-mode=vip --network myoverlaynetwork --replicas 3 mydnsutils tail -f /dev/null
Зайти на ноду, где запущен один из тасков данного сервиса myvip1 и убедиться что DNS отдаёт A запись с VIP
Пример:
 docker container exec ИМЯ/ID_КОНТЕЙНРА dig  myvip1
myvip1.		600	IN	A	10.0.1.65
На этой же ноде проверяем резолвится ли mydnsrr2
 docker container exec ИМЯ/ID_КОНТЕЙНРА dig  mydnsrr2
mydnsrr2.		600	IN	A	10.0.1.54
mydnsrr2.		600	IN	A	10.0.1.64
mydnsrr2.		600	IN	A	10.0.1.63
Видим, что резолвится.
Далее на этой же ноде проверяем работу dnsrr

Пример:
Выполним команду три раза:
docker container exec -it ИМЯ/ID_КОНТЕЙНРА ping -n -c 1 mydnsrr2
PING mydnsrr2 (10.0.1.64) 56(84) bytes of data.
64 bytes from 10.0.1.64: icmp_seq=1 ttl=64 time=0.045 ms

--- mydnsrr2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.045/0.045/0.045/0.000 ms

PING mydnsrr2 (10.0.1.54) 56(84) bytes of data.
64 bytes from 10.0.1.54: icmp_seq=1 ttl=64 time=0.047 ms

--- mydnsrr2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.047/0.047/0.047/0.000 ms

PING mydnsrr2 (10.0.1.63) 56(84) bytes of data.
64 bytes from 10.0.1.63: icmp_seq=1 ttl=64 time=0.045 ms

--- mydnsrr2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.045/0.045/0.045/0.000 ms

Как видим все три раза пинговали разные ip.

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

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