Вступление
Docker Swarm превращает ваши отдельные серверы в кластер компьютеров; облегчение масштабирования, высокой доступности и балансировки нагрузки. Балансировщик нагрузки Swarm реализует стратегию балансировки нагрузки с циклическим перебором, и это может помешать правильному функционированию (устаревших) приложений с сохранением состояния, которым требуется нек��торая форма липких сессий, чтобы обеспечить высокую доступность установки с несколькими экземплярами. Docker Enterprise Edition поддерживает липкий сеанс Layer-7, но в этом руководстве мы сосредоточимся на бесплатной (CE) версии Docker. Для реализации липких сессий мы будем использовать Traefik.
Предпосылки
	- По крайней мере два недавно развернутых и обновленных экземпляра Debian 9 в одной подсети с включенной частной сетью
- Docker CE установлен на этих экземплярах
- Экземпляры должны быть частью одного Swarm и должны иметь возможность общаться друг с другом через частную сеть.
- Предварительные знания Docker и Docker Swarm
- Пользователь без полномочий root с sudoправами (необязательно, но настоятельно рекомендуется не использовать пользователя root)
В этом уроке мы будем использовать два экземпляра Vultr с частными IP-адресами 192.168.0.100и 192.168.0.101. Оба они являются узлами менеджера Docker Swarm (что не идеально для производства, но достаточно для этого урока).
Кто я
Этот учебник использует jwilder/whoamiобраз докера в качестве демонстрационного приложения. Этот простой контейнер будет отвечать на вызов REST с именем отвечающего контейнера, что позволяет очень легко проверить, работают ли липкие сеансы. Это изображение, очевидно, используется только в демонстрационных целях и должно быть заменено изображением вашего собственного приложения.
Whoami-сервис настроен следующим образом:
sudo docker network create whoaminet -d overlay
sudo docker service create --name whoami-service --mode global --network whoaminet --publish "80:8000"  jwilder/whoami
sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
Если впоследствии мы увидим curlконечную точку REST whoami в http://192.168.0.100/, мы увидим циклическое распределение нагрузки Docker Swarm:
curl http://192.168.0.100
I'm a6a8c9294fc3
curl http://192.168.0.100
I'm ae9d1763b4ad
curl http://192.168.0.100
I'm a6a8c9294fc3
curl http://192.168.0.100
I'm ae9d1763b4ad
curl http://192.168.0.100
I'm a6a8c9294fc3
Бесполезно тестировать это с современными браузерами, такими как Chrome или Firefox, потому что они предназначены для поддержки соединений, а балансировщик нагрузки Docker Swarm будет переключаться на другой контейнер только при каждом новом подключении. Если вы хотите проверить это с помощью браузера, вам придется подождать не менее 30 секунд, чтобы соединение закрылось, прежде чем обновлять снова.
Настройка Traefik
Traefik изначально поддерживает Docker Swarm, он может обнаруживать и регистрировать или отменять регистрацию контейнеров на лету, а также связываться с вашим приложением через внутреннюю оверлейную сеть. Traefik требуется некоторая информация о вашем приложении, прежде чем он сможет начать обработку запросов к нему. Эта информация предоставляется Traefik путем добавления ярлыков к вашему сервису Swarm:
sudo docker service update --label-add "traefik.docker.network=whoaminet" --label-add "traefik.port=8000" --label-add "traefik.frontend.rule=PathPrefix:/" --label-add "traefik.backend.loadbalancer.stickiness=true" whoami-service
Следующий список описывает, что означает каждая метка:
	- traefik.docker.network: Оверлейная сеть Docker, по которой Traefik будет взаимодействовать с вашим сервисом
- traefik.port: Порт, который прослушивает ваша служба (это внутренний порт, а не опубликованный порт)
- traefik.frontend.rule:- PathPrefix:/привязывает корень контекста '- /' к этому сервису
- traefik.backend.loadbalancer.stickiness: Включает липкие сессии для этого сервиса
Теперь, когда whoami-serviceнастроены необходимые метки, мы можем добавить сервис Traefik в рой:
sudo docker service create --name traefik -p8080:80 -p9090:8080 --mount type=bind,source=/var/run/docker.sock,destination=/var/run/docker.sock --mode=global --constraint 'node.role == manager' --network whoaminet traefik --docker --docker.swarmmode --docker.watch --web --loglevel=DEBUG
Эта команда делает много вещей одновременно, как показано в следующем списке:
	- --name traefik: Наш новый сервис Docker называется Traefik
- -p8080:80: Мы публикуем порт Traefik- 80в порт,- 8080потому что порт- 80уже используется нашим whoami-сервисом
- -p9090:8080: Мы публикуем собственный веб-интерфейс Traefik для порта- 9090
- --mount ...: Мы монтируем Docker Socket в контейнер, чтобы Traefik мог получить доступ к среде выполнения Docker хоста
- --global: Мы хотим контейнеры Traefik на каждом узле менеджера по причинам высокой доступности
- --constraint 'node.role == manager': Мы хотим, чтобы Traefik работал только на узлах менеджера, потому что рабочие узлы не могут предоставить Traefik необходимую информацию. Например,- docker service lsна рабочем узле не работает, поэтому Traefik даже не сможет узнать, какие службы запущены
- --network whoaminet: Подключите Traefik к той же сети, что и наша- whoami-service, иначе он не сможет подключиться к ней. Ранее мы сказали Traefik подключиться к нашему сервису через эту сеть с- traefik.docker.networkметкой
- traefik: Сказать докеру использовать последнюю версию образа док-станции Traefik для этого сервиса
- --docker --docker.swarmmode --docker.watch --web --loglevel=DEBUG: Аргументы командной строки передаются непосредственно в Traefik, чтобы он мог работать в режиме роя Docker.- DEBUGздесь необязательно, но интересно во время настройки и для этого урока
Осталось только открыть необходимые порты в брандмауэре Debian:
sudo iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT
sudo iptables -I INPUT 1 -p tcp --dport 9090 -j ACCEPT
Как это работает
Как только Traefik запускается, вы можете увидеть в журналах, что Traefik обнаруживает два whoamiконтейнера. Он также выводит имя куки, которое он будет использовать для обработки липкой сессии:
time="2018-11-25T13:17:30Z" level=debug msg="Configuration received from provider docker: {\"backends\":{\"backend-whoami-service\":{\"servers\":{\"server-whoami-service-1-a179b2e38a607b1127e5537c2e614b05\":{\"url\":\"http://10.0.0.5:8000\",\"weight\":1},\"server-whoami-service-2-df8a622478a5a709fcb23c50e689b5b6\":{\"url\":\"http://10.0.0.4:8000\",\"weight\":1}},\"loadBalancer\":{\"method\":\"wrr\",\"stickiness\":{}}}},\"frontends\":{\"frontend-PathPrefix-0\":{\"entryPoints\":[\"http\"],\"backend\":\"backend-whoami-service\",\"routes\":{\"route-frontend-PathPrefix-0\":{\"rule\":\"PathPrefix:/\"}},\"passHostHeader\":true,\"priority\":0,\"basicAuth\":null}}}"
time="2018-11-25T13:17:30Z" level=debug msg="Wiring frontend frontend-PathPrefix-0 to entryPoint http"
time="2018-11-25T13:17:30Z" level=debug msg="Creating backend backend-whoami-service"
time="2018-11-25T13:17:30Z" level=debug msg="Adding TLSClientHeaders middleware for frontend frontend-PathPrefix-0"
time="2018-11-25T13:17:30Z" level=debug msg="Creating load-balancer wrr"
time="2018-11-25T13:17:30Z" level=debug msg="Sticky session with cookie _a49bc"
time="2018-11-25T13:17:30Z" level=debug msg="Creating server server-whoami-service-1-a179b2e38a607b1127e5537c2e614b05 at http://10.0.0.5:8000 with weight 1"
time="2018-11-25T13:17:30Z" level=debug msg="Creating server server-whoami-service-2-df8a622478a5a709fcb23c50e689b5b6 at http://10.0.0.4:8000 with weight 1"
time="2018-11-25T13:17:30Z" level=debug msg="Creating route route-frontend-PathPrefix-0 PathPrefix:/"
time="2018-11-25T13:17:30Z" level=info msg="Server configuration reloaded on :80"
time="2018-11-25T13:17:30Z" level=info msg="Server configuration reloaded on :8080"
Если мы свернемся, http://192.168.0.100:8080то увидим, что был установлен новый файл cookie _a49bc:
curl -v http://192.168.0.100:8080
* About to connect() to 192.168.0.100 port 8080 (#0)
*   Trying 192.168.0.100...
* Connected to 192.168.0.100 (192.168.0.100) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 192.168.0.100:8080
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 17
< Content-Type: text/plain; charset=utf-8
< Date: Sun, 25 Nov 2018 13:18:40 GMT
< Set-Cookie: _a49bc=http://10.0.0.5:8000; Path=/
<
I'm a6a8c9294fc3
* Connection #0 to host 192.168.0.100 left intact
Если при последующих вызовах мы отправим этот файл cookie в Traefik, мы всегда будем перенаправлены в один и тот же контейнер:
curl http://192.168.0.100:8080 --cookie "_a49bc=http://10.0.0.5:8000"
I'm a6a8c9294fc3
curl http://192.168.0.100:8080 --cookie "_a49bc=http://10.0.0.5:8000"
I'm a6a8c9294fc3
curl http://192.168.0.100:8080 --cookie "_a49bc=http://10.0.0.5:8000"
I'm a6a8c9294fc3
curl http://192.168.0.100:8080 --cookie "_a49bc=http://10.0.0.5:8000"
I'm a6a8c9294fc3
Файл cookie содержит только внутренний IP-адрес контейнера, в который Traefik должен отправить запрос. Если вы измените значение cookie на http://10.0.0.4:8000, то запрос будет эффективно перенаправлен в другой контейнер. Если файл cookie никогда не будет повторно отправлен в Traefik, то липкий сеанс не будет работать, и запросы будут сбалансированы между контейнерами приложения и контейнерами Traefik.
Это все, что нужно для настройки липких сессий уровня 7 в Docker CE на Debian 9.