В Docker, среди его разнообразия типов сетей, есть один особенно интересный — overlay. Overlay сеть может охватывать сразу несколько хостов таким образом, что, например, контейнер веб-приложения на хосте 1 может общаться по имени с контейнером базы данных на хосте 2, как если бы они были на одной машине.
Но просто так создать такую сеть нельзя. Докер-хосты ведь могут добавляться и исчезать, и непонятно, как им находить друг друга, кто будет хранить список участвующих хостов, и т. п. Нужен какой-то сторонний компонент, который будет этой координацией заниматься.
Конечно, Докер можно запустить в Swarm режиме, и тогда проблема исчезнет сама собой. Но и без Swarm, как оказалось, это очень легко устроить.
Что нам понадобится
Так как для сети нам нужно сделать хотя бы несколько хостов, нужно обзавестись парочкой дополнительных инструментов:
- VirtualBox, чтобы запускать виртуальные хосты.
- docker-machine, чтобы их создавать и конфигурировать.
Если Docker устанавливался на Мак или Windows, то почти наверняка он пришёл в комплекте с docker-machine. Если это не так, или Docker установлен на Linux, есть достаточно простая инструкция по его установке.
Как сделать overlay сеть
Как я уже упоминал, чтобы несколько хостов с Docker знали друг о друге, им нужен какой-то координатор. Докер о координаторах в курсе и из коробки может работать с Consul, ZooKeeper или Etcd. Для сегодняшнего эксперимента Consul вполне подойдёт.
Мы создадим три хоста: один с Consul и два с Docker. В настройках Docker мы укажем, чтобы он использовал Consul для координации, и, если инструкция не врёт, после этого можно будет создать overlay сеть, которая сразу станет доступна на обоих хостах этого мини-кластера.
Подготовка координатора
Итак, первым делом нам нужен новый виртуальный хост и Consul на нём. Легкотня. Во-первых, сам хост:
1 |
docker-machine create -d virtualbox keyvalue |
Этой командой docker-machine
создаст виртуальную машину при помощи VirtualBox и назовёт её keyvalue
.
Во-вторых, на созданных docker-machine
хостах сразу есть полноценный Докер, так что для установки Consul мы просто может взять официальный Докер-образ и запустить его с дефолтными настройками.
Да, и ещё один маленький кусочек магии. Чтобы запустить контейнер в keyvalue
нужно же сначала в keyvalue
зайти, чему мог бы помочь, например, docker-machine ssh keyvalue
. Но есть более прикольный способ.
docker
ведь на самом деле всего-лишь клиент, который передаёт команды Docker engine, а тот уже делает всю грязную работу. Так вот, этому клиенту можно сказать общаться с другим engine. Знать бы настройки.
А docker-machine config keyvalue
эти настройки знает. Если передать выход команды докеру-клиенту, то этого хватит для того, чтобы с локальной машины манипулировать докером в виртуальной. При помощи этой хитрости мы можем запустить Consul в keyvalue
в одну команду:
1 2 |
docker $(docker-machine config keyvalue) \ run -d -p 8500:8500 progrium/consul -server -bootstrap |
А если узнать айпишку этой машины, то можно натравить браузер на порт 8500 и посмотреть, что же из себя Consul представляет:
1 2 |
docker-machine ip keyvalue #192.168.99.104 |
Конфигурируем Docker-хосты
Теперь нам нужно создать еще два хоста с докерами внутри, и научить последних дружить друг с другом.
В Docker есть две опции, отвечающие за работу в кластере:
cluster-store
, которая указывает на координатора, иcluster-advertise
, которая определяет, на каком интерфейсе и порту Докер будет ждать входящие соединения. В хостах, созданных при помощи docker-machine, обычно используютeth1:2376
.
В общем случае мы бы пошли в файл настроек Docker, указали бы эти значения, сохранили, и т.п. Но опять же, так как хосты создаёт docker-machine, эти опции можно передать прямо через него:
1 2 3 4 |
docker-machine create -d virtualbox \ --engine-opt="cluster-store=consul://$(docker-machine ip keyvalue):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ node-0 |
И второй Docker-хост:
1 2 3 4 |
docker-machine create -d virtualbox \ --engine-opt="cluster-store=consul://$(docker-machine ip keyvalue):8500" \ --engine-opt="cluster-advertise=eth1:2376" \ node-1 |
Первый кусок магии
Итак, машины сконфигурированы, время веселится. Зайдём в первый Докер-хост и создадим там overlay сеть:
1 2 3 4 |
docker-machine ssh node-0 #.... docker@node-0:~$ docker network create -d overlay multi-host-net #e1d516c32c3c525d5e8a9a73663e4ec7dd951ecbb8e5faab657c0eb957220d5a |
После того, как сеть с названием multi-host-net
создана, набираем exit
и идём прямиком во второй хост проверять, видна ли эта сеть оттуда. :
1 2 3 4 5 6 7 8 |
docker-machine ssh node-1 #... docker@node-1:~$ docker network ls #NETWORK ID NAME DRIVER SCOPE #42131dca03d6 bridge bridge local #46793b96eaef host host local #e1d516c32c3c multi-host-net overlay global #c68e3ec2231b none null local |
Видна! Через какую-то непонятную чёрную магию multi-host-net
стала доступна на обоих машинах.
Второй кусок магии
Попробуем ещё одну вещь. Пока мы сидим на хосте node-1
, запустим-ка там nginx контейнер и подключим его к только что созданной оверлейной сети:
1 |
docker run -d -p80:80 --net=multi-host-net --name=webserver nginx |
Для определённости, пусть контейнер зовут webserver
. Просто для того, чтобы убедиться, что nginx работает, отправим в localhost HTTP запрос, и, увидев, что сервер отвечает, идём назад в node-0
:
1 2 3 4 5 6 |
docker@node-1:~$ curl localhost #... #<title>Welcome to nginx!</title> #... docker@node-1:~$ exit $ docker-machine ssh node-0 |
Я думаю запустить на первом хосте обычную убунту, на которой затем поставлю простейший браузер для командной строки, и проверю, можно ли зайти через него на адрес http://webserver:
1 2 3 |
docker@node-0:~$ docker run -ti --net=multi-host-net ubuntu bash $ apt-get update && apt-get install -y elinks $ elinks |
Барабанная дробь…
Вот так-то! Контейнер, запущенный на хосте node-0
смог отправить запрос контейнеру на хосте node-1
, зная лишь его имя.
Итог
Сегодня мы посмотрели, как можно создать overlay сеть в Docker, без Docker Swarm. Оказалось, что можно, и довольно-таки просто. Понадобилось всего лишь запустить сервис-координатор, показать Docker engine, где тот лежит, и всё, дальше оно работало само. Можно создавать сеть и дружить контейнеры друг с другом, совсем не вдаваясь в подробности, где они физически находятся.
Можно ли без docker-machine связать в сеть 2 сервера с docker-engine?
Можно, но скорее всего только через swarm — https://docs.docker.com/network/overlay/. В принципе, я теперь думаю, что даже мои манипуляции с docker-machine к тому же swarm всё и сводили, просто менее очевидным путём.