Цель этой статьи — изучить новые сетевые функции Docker, представленные в версии 1.9. Мы применим их к кластеру Docker Swarm. В практических целях мы будем развертывать контейнеры в кластере Swarm, созданном локально с помощью Vagrant и использующим Consul в качестве реестра служб и Registrator в качестве инструмента, который будет отслеживать демоны Docker и регистрировать / отменять регистрацию контейнеров, которые мы запускаем / останавливаем. В совокупности Консул и Регистратор будут действовать как обнаружение службы в нашем кластере. Я не буду вдаваться в подробности того, как работает Docker Swarm или служба обнаружения. Вы можете найти больше информации об этом предмете в следующих статьях.
- Обнаружение службы: Zookeeper vs etcd vs Consul
- Сравнение инструментов кластеризации Docker: Кубернетес против Docker Swarm
- Масштабирование до бесконечности с помощью Docker Swarm, Docker Compose и Consul
Мы сразу перейдем к сетевым функциям Docker, используемым в кластере Swarm.
Настройка кластера
Обо всем по порядку. Давайте создадим три виртуальные машины, которые мы будем использовать в качестве тренировочного поля. Главный узел swarm будет действовать как главный, а две другие виртуальные машины будут представлять наш кластер, состоящий из двух узлов. Все три виртуальные машины будут работать под управлением Ubuntu и будут созданы с использованием VirtualBox и Vagrant . Пожалуйста, убедитесь, что оба установлены. Вам также понадобится Git для клонирования кода, который будет использоваться в этой статье. Если вы пользователь Windows, пожалуйста, следуйте инструкциям, описанным в разделе Запуск виртуальных машин Linux в Windows, прежде чем углубляться в описанные ниже.
Давайте начнем с создания виртуальных машин, которые будут моделировать наш кластер Swarm.
1
2
3
4
5
6
7
|
git clone https: //github .com /vfarcic/docker-swarm-networking .git cd docker-swarm-networking vagrant up swarm-master swarm-node-1 swarm-node-2 vagrant ssh swarm-master |
Теперь, когда виртуальные машины созданы, и мы находимся внутри Swarm-Master , давайте предоставим виртуальным машинам Docker, Docker Compose, Consul, Registrator и Swarm. Мы сделаем это через Ansible . Если вы новичок в Ansible, вы найдете множество примеров в этом блоге.
1
2
|
ansible-playbook /vagrant/ansible/swarm .yml \ -i /vagrant/ansible/hosts/prod |
Playbook swarm.yml убедился, что Docker запущен и настроен для поддержки Swarm. Он также предоставил серверам Docker Compose, Consul, Swarm и Registrator.
Давайте дважды проверим, что все работает как положено.
1
2
3
4
5
|
export DOCKER_HOST=tcp: //localhost :2375 docker info curl localhost:8500 /v1/catalog/nodes | jq '.' |
Переменная DOCKER_HOST указывает Docker отправлять команды ведущему Swarm, работающему через порт 2375 . За этим последовала docker info
о docker info
которая показала, что в кластере Swarm есть два узла. Наконец, последняя команда запросила список всех узлов, зарегистрированных в Консуле, и получила все три виртуальные машины (один Swarm-мастер и два Swarm-узла) в качестве ответа.
На данный момент у нас запущен и работает кластер Swarm, и мы можем начать играть с сетью Docker. Однако прежде чем мы продолжим с практическими примерами, давайте быстро рассмотрим идею, лежащую в основе.
Развертывание с помощью Docker Swarm и Docker Networking
Недавно Docker представил новую версию 1.9. Это, без сомнения, самый важный выпуск с версии 1.0. Это дало нам две долгожданные функции; многоузловая сеть и постоянные тома. Сеть делает связывание устаревшим и является функцией, которая нам нужна для соединения контейнеров между несколькими хостами. Больше не нужно, чтобы прокси связывал несколько контейнеров, которые составляют сервис. Это не означает, что прокси-сервер бесполезен, но мы должны использовать его в качестве открытого интерфейса для наших служб и сетей для соединения контейнеров, которые образуют логическую группу. Новые сетевые и прокси-сервисы Docker имеют разные преимущества и должны использоваться для разных случаев использования. Среди прочего, прокси-сервисы обеспечивают балансировку нагрузки и могут контролировать доступ к нашим сервисам. Сеть Docker — это удобный способ подключения отдельных контейнеров, которые образуют единый сервис и находятся в одной сети. Распространенным вариантом использования Docker-сетей может быть служба, требующая подключения к базе данных. Мы можем соединить эти два через сеть. Более того, может потребоваться масштабирование самой службы и запуск нескольких экземпляров. Прокси-сервис с балансировщиком нагрузки должен соответствовать этому требованию. Наконец, другие службы могут нуждаться в доступе к этой услуге. Поскольку мы хотим использовать преимущества балансировки нагрузки, этот доступ также должен осуществляться через прокси-сервер.
Эта цифра представляет один общий случай использования. У нас есть масштабированная служба с двумя экземплярами, работающими на узлах 1 и 3. Вся связь с этими службами осуществляется через прокси-службу, которая заботится о балансировке нагрузки и безопасности. Любой другой сервис (будь то внешний или внутренний), который хочет получить доступ к нашему сервису, должен пройти через прокси. Внутренне служба использует базу данных. Связь между службой и базой данных является внутренней и осуществляется через сеть с несколькими узлами. Этот параметр позволяет нам легко масштабировать внутри кластера, сохраняя при этом всю связь между контейнерами, которые составляют один внутренний сервис. Другими словами, вся связь между контейнерами, составляющими сервис, осуществляется через сеть, тогда как связь между различными сервисами осуществляется через прокси.
Существуют разные способы создания многоузловой сети. Мы можем настроить сеть вручную.
1
2
3
|
docker network create my-network docker network ls |
Вывод команды network ls
выглядит следующим образом.
01
02
03
04
05
06
07
08
09
10
|
NETWORK ID NAME DRIVER f8a50a3c9c13 swarm-node-1 /host host 8ae6cefc3957 swarm-node-2 /host host 5f68a88668f6 swarm-node-2 /bridge bridge 397107ba0daf swarm-node-2 /none null b655577f0030 swarm-node-1 /bridge bridge efb02b0fa9b9 swarm-node-1 /docker_gwbridge bridge eb5ff0f0136a swarm-node-1 /none null 71b80ae02620 my-network overlay ac4261d5e27a swarm-node-2 /docker_gwbridge bridge |
Вы можете видеть, что одной из сетей является my-network, которую мы создали ранее. Он охватывает весь Рой кластер. Мы можем использовать эту сеть с аргументом –net .
1
2
3
4
5
6
7
8
9
|
docker run -d --name books-ms-db \ --net my-network \ mongo docker run -d --name books-ms \ --net my-network \ -e DB_HOST=books-ms-db \ -p 8080 \ vfarcic /books-ms |
Прежде чем мы продолжим, давайте подтвердим, что Swarm распределил контейнеры внутри кластера.
1
|
docker ps --filter name=books -- format "table {{.Names}}" |
Вывод в моем случае следующий.
1
2
3
|
NAMES swarm-node-2 /books-ms swarm-node-1 /books-ms-db |
Вы можете видеть, что каждый контейнер был развернут на другом узле. Это главная цель Docker Swarm; распределить контейнеры по кластеру. Вопрос в том, как эти контейнеры могут взаимодействовать друг с другом, если они находятся на отдельных узлах?
Мы запустили два контейнера, которые составляют один сервис; books-ms — это API, который связывается с books-ms-db, который действует как база данных. Поскольку оба контейнера имеют аргумент -net my-network , они оба принадлежат сети my- network. В результате Docker обновил файл hosts, предоставив каждому контейнеру псевдоним, который можно использовать для внутренней связи.
Давайте войдем в контейнер books-ms и посмотрим на файл hosts.
1
|
docker exec -it books-ms cat /etc/hosts |
Вывод команды exec выглядит следующим образом.
1
2
3
4
5
6
7
8
9
|
10.0.0.2 3166318f0f9c 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 10.0.0.2 books-ms-db 10.0.0.2 books-ms-db.my-network |
Интересной частью файла hosts являются последние две записи. Докер обнаружил, что контейнер books-ms-db использует ту же сеть, и обновил файл hosts , добавив books-ms-db (имя контейнера DB) и books-ms-db.my-network (имя контейнера DB плюс название сети) псевдонимы. Если используется какое-то соглашение, тривиально кодировать наши сервисы так, чтобы они использовали псевдонимы, подобные этому, для связи с ресурсами, расположенными в отдельном контейнере (в данном случае с базой данных).
Мы также передали переменную окружения DB_HOST в книгу-мс . Это указывает нашему сервису, какой хост использовать для подключения к базе данных. Мы можем видеть это, выводя среды контейнера.
1
|
docker exec -it books-ms env |
Вывод команды следующий.
1
2
3
4
5
6
|
PATH= /usr/local/sbin : /usr/local/bin : /usr/sbin : /usr/bin : /sbin : /bin HOSTNAME=eb3443a66355 DB_HOST=books-ms-db DB_DBNAME=books DB_COLLECTION=books HOME= /root |
Как видите, одной из переменных среды является DB_HOST со значением books-ms-db .
Сейчас у нас есть сеть Docker, которая создала псевдоним hosts -ms-db, указывающий на IP сети, созданной Docker. У нас также есть переменная окружения DB_HOST со значением books-ms-db . Код службы использует эту переменную для подключения к базе данных. Вы можете использовать другую логику. Важной частью является то, что Docker обновил файл hosts с помощью псевдонимов, которые можно использовать для доступа к любому другому контейнеру, который принадлежит той же сети наложения .
Существует даже лучший способ создать сеть, чем запуск команды create network . Прежде чем мы попробуем это, давайте остановим эти два контейнера и удалим сеть.
1
2
3
|
docker rm -f books-ms books-ms-db docker network rm my-network |
На этот раз мы будем запускать контейнеры через Docker Compose. Хотя мы могли бы использовать аргумент net внутри docker-compose.yml и, таким образом, выполнять точно такой же процесс, как мы делали ранее, лучше использовать новый аргумент Docker Compose — x-network .
1
2
3
|
cd /vagrant/booksms docker-compose --x-networking up -d db app |
Вывод команды, которую мы только что выполнили, следующий.
1
2
3
|
Creating network "booksms" with driver "None" Creating booksms_app_1 Creating books-ms-db |
Перед созданием приложения служб и базы данных Docker создал новую сеть под названием booksms . Имя сети совпадает с именем проекта (по умолчанию используется имя каталога).
Мы можем подтвердить, что сеть была создана с помощью команды docker network ls
.
1
|
docker network ls |
Вывод следующий.
01
02
03
04
05
06
07
08
09
10
|
NETWORK ID NAME DRIVER 6e5f816d4800 swarm-node-1 /host host aa1ccdaefd70 swarm-node-2 /docker_gwbridge bridge cd8b1c3d9be5 swarm-node-2 /none null ebcc040e5c0c swarm-node-1 /bridge bridge 6768bad8b390 swarm-node-1 /docker_gwbridge bridge 8ebdbd3de5a6 swarm-node-1 /none null 58a585d09bbc booksms overlay de4925ea50d1 swarm-node-2 /bridge bridge 2b003ff6e5da swarm-node-2 /host host |
Как видите, наложенные сетевые книги были созданы.
Мы также можем проверить, что файл hosts внутри контейнеров был обновлен.
1
|
docker exec -it booksms_app_1 cat /etc/hosts |
Вывод следующий.
1
2
3
4
5
6
7
8
9
|
10.0.0.2 3166318f0f9c 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 10.0.0.3 books-ms-db 10.0.0.3 books-ms-db.my-network |
Наконец, давайте посмотрим, как Swarm распространял наши контейнеры.
1
|
docker ps --filter name=books -- format "table {{.Names}}" |
Вывод следующий.
1
2
3
|
NAMES swarm-node-2 /books-ms-db swarm-node-1 /booksms_app_1 |
Swarm развернул контейнер приложения в swarm-node-1, а контейнер db — в swarm-node-2 .
Наконец, давайте проверим, правильно ли работает сервис book-ms . Мы не знаем, на каком сервере Swarm развернут контейнер или какой порт открыт. Поскольку у нас нет (пока) прокси-сервера, мы получим IP-адрес и порт службы от Consul, отправим запрос PUT для сохранения некоторых данных в базе данных, находящейся в другом контейнере, и, наконец, отправим запрос GET чтобы проверить, можем ли мы получить запись. Поскольку у нас нет прокси-службы, которая бы обеспечивала перенаправление запросов на правильный сервер и порт, нам придется получить адрес и порт от Consul. Для получения дополнительной информации о том, как настроить прокси-сервис, пожалуйста, обратитесь к статьям Scaling To Infinity с Docker Swarm, Docker Compose и Consul .
01
02
03
04
05
06
07
08
09
10
11
12
|
ADDRESS=`curl \ localhost:8500 /v1/catalog/service/books-ms \ | jq -r '.[0].ServiceAddress + ":" + (.[0].ServicePort | tostring)' ` curl -H 'Content-Type: application/json' -X PUT -d \ '{ "_id" : 2, "title" : "My Second Book" , "author" : "John Doe" , "description" : "A bit better book" }' \ $ADDRESS /api/v1/books | jq '.' curl $ADDRESS /api/v1/books | jq '.' |
Последний вывод команды выглядит следующим образом.
1
2
3
4
5
6
7
|
[ { "author" : "John Doe" , "title" : "My Second Book" , "_id" : 2 } ] |
Если бы служба не могла обмениваться данными с базой данных, расположенной в другом узле, мы не смогли бы ни поместить, ни получить данные. Сеть между контейнерами, развернутыми на отдельных серверах, работала! Все, что нам нужно сделать, это использовать дополнительный аргумент с Docker Compose ( –x-network ) и убедиться, что код службы использует информацию из файла hosts.
Другое преимущество работы с сетями Docker заключается в том, что если один контейнер перестает работать, мы можем повторно развернуть его (возможно, на отдельном сервере) и, предполагая, что сервисы, использующие его, могут обрабатывать временную потерю соединения, продолжать использовать его, как будто ничего не произошло.
Сеть Docker была долгожданной функцией, которая позволяет нам распределять контейнеры, не опасаясь, смогут ли они общаться друг с другом. Наконец, мы можем распространять контейнеры без ограничений, введенных ссылками (связанный контейнер должен был работать на том же сервере). Больше нет необходимости в обходных решениях, которые некоторым из нас приходилось использовать в прошлом. Это захватывающая функция, которая, несомненно, позволит Docker Swarm перейти на следующий уровень.
Попробуй сам. Изучите другие варианты представленных сетей Docker. Когда вы закончите, вы, вероятно, захотите остановить виртуальные машины, которые мы создали, чтобы освободить ресурсы для других задач.
1
2
3
|
exit vagrant halt |
Ссылка: | Развертывание контейнеров с помощью Docker Swarm и Docker Networking от нашего партнера по JCG Виктора Фарчича в блоге технологических бесед . |