При создании сервиса в Docker Swarm ему по умолчанию присваивается виртуальный ip-адрес. И при этом не важно сколько контейнеров (task) внутри сервиса, у каждого контейнера также свой ip-адрес.
Встаёт вопрос если у контейнера в сервисе итак есть ip-адрес зачем тогда еще присваивать ip-адрес самому сервису. Ответ очень банален, так как в сервисе может быть куча контейнеров, да и при пересоздании этих контейнеров их ip-адреса могут меняться логичнее будет обращаться к ip-адресу самого сервиса.
Дело в том, что сервис в Docker Swarm сам занимается балансировкой нагрузки. Т.е. запрос, отправленный на ip-адрес или dns имя сервиса автоматически отправляется на один из контейнеров (task) сервиса. При этом каждый следующий запрос уже уходит на другой контейнер. Получается, что при использовании сервиса балансировка более точная чем у dns round robin, который я рассматривал тут. При использовании dns round robin запросы зачастую могут обрабатываться одним и тем же контейнером несколько раз подряд.
Для примера я создам сеть backend_net и запущу в нём сервис web с тремя репликами. Контейнеры из образа nginxdemos/hello при обращении на порт 80 выводят имя контейнера и его ip-адрес, как раз то что необходимо.
docker network create -d overlay backend_net
docker service create --name web --network backend_net nginxdemos/hello
docker service scale replicas=3 web
Теперь когда у меня есть сервис я проверю его виртуальный ip-адрес, хотя в целом это можно и не делать ведь всё равно правильнее будет обращаться к сервису по его имени, а не ip-адресу. Но я выполню этот запрос для того, чтобы показать как получить ip-адрес сервиса.
docker service inspect web --format '' | jq
[
{
"NetworkID": "vvapjnzz507fpgu0l463purkc",
"Addr": "10.0.1.2/24"
}
]
Проверка балансировки
Для того чтобы продемонстрировать работоспособность балансировки сервисом я буду использовать контейнер с образа curlimages/curl. Обращаю внимание что этот контейнер должен быть в той же сети что и сам сервис web, иначе доступа у создаваемого контейнера к сервису не будет.
docker run -it --rm --network backend_net curlimages/curl sh
Но тут я получу ошибку: docker: Error response from daemon: failed to set up container networking: Could not attach to network backend_net: rpc error: code = PermissionDenied desc = network backend_net not manually attachable.
Дело в том что по умолчанию сеть создаваемая для swarm (-d overlay) по умолчанию защищена от добавления в неё контейнеров создаваемых пользователем в ручную. Если вдруг необходимо всё же создать сеть, в которую можно добавить и сервис и свои контейнеры используется опция --attachable, например docker network create -d overlay backend_net --attachable. Но я так делать не рекомендую, поэтому просто создам еще один сервис в сети backend_net. Но я меняю образ curlimages/curl на nginx так как в сервисе одноразовые контейнеры нельзя запустить.
docker service create --name curl --network backend_net nginx
docker serivce ps curl
docker exec -it curl.1.z00ox4hiojz7cd18nuc5bi0dn bash
Теперь находясь внутри контейнера я несколько раз запущу команду curl -s http://web | grep Server.
<p><span>Server address:</span> <span>10.0.1.5:80</span></p>
<p><span>Server name:</span> <span>ed97410e2761</span></p>
<p><span>Server address:</span> <span>10.0.1.6:80</span></p>
<p><span>Server name:</span> <span>443e6d24fa4b</span></p>
<p><span>Server address:</span> <span>10.0.1.3:80</span></p>
<p><span>Server name:</span> <span>e1939cbd1ed6</span></p>
Из вывода видно что каждый контейнер обработал по одному запросу, что доказывает работу балансировки сервисом.


Комментарии