Глава 1. Букварь построения сети Docker
Docker является технологией обладающих малым весом контейнеров, которая в последние годы привлекает пристальное внимание. Она аккуратно связывает различные свойства и функции ядра Linux, такие как имена пространств, cgroup, SELinux и профили AppAromor поверх совокупности файловых систем, таких как AUFS и BTFFS для того чтобы делать образы модулей. Такие образы обеспечивают среду виртуализации с высокой степенью настройки для приложений, которая следует в потоке написанное единожды работает везде. Приложение может состоять из одного работающего в своём собственном контейнере процесса или может быть выполнено из множества процессов, работающих в своих собственных контейнерах, которые способны реплицироваться по мере роста нагрузки. Более того, существует потребность в мощных элементах сетевой среды, которые могут поддерживать различные сложные варианты применения.
В этой главе мы изучим существенные компоненты построения сети Docker и того как строить и выполнять простые примеры контейнеров.
Данная глава охватит следующие темы:
-
Построение сетевой среды и Docker
-
Построение сетевого моста
docker0
-
Построение сетевой среды Docker OVS
-
Домены сетей Unix
-
Связывание контейнеров Docker
-
Что нового в построении сетей Docker
Docker получает в промышленности мощную тягу благодаря своей разумной производительности и воспроизводимости архитектуры, обеспечивая при этом четыре краеугольных основы современного развития:
-
Автономность
-
Децентрализацию
-
Параллелизм
-
Изолированность
Более того, широкомасштабное внедрение архитектуры микрослужб ThoughtWorks, или LOSA Lots of Small Applications, продолжает привносить потенциал в технологию Docker. В результате, крупные компании наподобие Google, VMWare и Microsoft уже портировали Docker в свою инфраструктуру, а импульс продолжается запуском бесчисленных стартапов Docker, а именно Tutum, Flocker, Giantswarm и тому подобных.
Поскольку Docker повсеместно воспроизводит своё поведение в любом месте, будь то ваша машина разработки, сервер с голым железом, виртуальная машина или центр обработки данных, разработчики приложений могут сосредоточить своё внимание на развитии, в то время как семантика выполнения остаётся за DevOps. Это делает команду рабочего потока модульной, эффективной и продуктивной. Docker не следует путать с Виртуальной машиной (ВМ, VM), несмотря на то, что обе являются технологиями виртуализации. В то время как Docker совместно использует OS обеспечивая достаточный уровень изоляции и безопасности работающим в контейнере приложениям, он далее полностью абстрагируется от ОС предоставляя сильную изоляцию и гарантии безопасности. Однако, отпечатки ресурса Docker очень незначительны по сравнению с ВМ и, следовательно, предпочтительнее с точки зрения экономичности и производительности. Тем не менее, он не может полностью заменить ВМ и поэтому они являются дополняющими друг друга технологиями. Следующая схема отображает архитектуру ВМ и Docker:
Содержание
Каждый контейнер Docker имеет свой собственный сетевой стек, причём это происходит благодаря пространству имён NET
ядра Linux, в котором для каждого контейнера конретизируется новое пространство имён
NET
и оно не может быть доступно снаружи контейнера или из других контейнеров.
Построение сетей Docker получает свою мощность от следующих сетевых компонентов и служб.
Это встроенный в ядро обучаемые коммутаторы L2/MAC, причём они должны применяться для переадресации.
Это усовершенствованный мост, который является программируемым и поддерживает туннелирование.
Конверторы сетевых адресов являются непосредственными объектами, выполняющими трансляцию IP адресов и портов (SNAT, DNAT и тому подобное).
Это механизм политик в вашем ядре, применяемый для управления пересылкой пакетов, межсетевого экранирования, а также функциональности NAT.
Здесь могут быть определены политики межсетевого экранирования для каждого приложения.
Для работы с Docker могут применяться различные сетевые компоненты, предоставляющие новые способы для доступа и использования служб на основе Docker. Как результат, мы видим большое число библиотек, которые следуют различным подходам построения сетей. Некоторыми из достойных упоминания являются Docker Compose, Weave, Kubernetes, Pipework, libnetwork и тому подобные. Следующий рисунок описывает ключевые идеи построения сети Docker:
Мост docker0
является сердцем построения сети по умолчанию. При запуске службы Docker, на машине
хоста создаётся мост Linux. Интерфейсы контейнера общаются с этим мостом, а сам мост выступает в качестве прокси внешнего мира. Множество
контейнеров на одном и том же хосте могут взаимодействовать друг с другом через этот мост Linux.
Обычно, docker0
может быть настроен флагами --net
в
четырёх режимах:
-
--net default
-
--net=none
-
--net=container:$container2
-
--net=host
В данном режиме мост по умолчанию применяется мостом для соединения контейнеров друг с другом.
В этом режиме созданные контейнеры полностью изолированы и не могут соединяться с сетевой средой.
При помощи данного флага данный контейнер создаёт в пространстве имён сети совместный ресурс с контейнером, именуемым
$container2
.
При данном режиме контейнер создаёт совместные ресурсы своего сетевого пространства имён с хостом.
Соответствие порта в контейнере Docker
В этом разделе мы увидим как порты контейнера приводятся в соответствие портам хоста. Такое соответствие может выполняться неявно механизмом Docker или может определяться в явном виде.
Мы создадим два контейнера с именами Container1
и
Container2
, причём оба назначим на IP адрес из частного адресного
пространства IP и к тому же соединённых с мостом docker0
,
как показано на следующей иллюстрации:
Оба рассматриваемых контейнера способны выполнять ping друг к другу а также выходить во внешний мир.
Для внешнего доступа их порт должен соответствовать порту хоста.
Как уже упоминалось в предыдущем разделе, контейнеры используют сетевые пространства имён. Когда создаётся первый контейнер, для этого
контейнера создаётся новое сетевое пространство имён. Между каждым контейнером и мостом Linux создаётся соединение (link) vEthernet.
Исходящий из eth0
трафик достигает моста хоста через интерфейс vEthernet и после этого выполняется
коммутация. Для отображения списка мостов Linux можно применить следующий код:
# show linux bridges
$ sudo brctl show
Вывод будет аналогичен приводимому ниже, причём будет приведено соответствие имени моста и интерфейсов veth
ваших контейнеров:
bridge name bridge id STP enabled interfaces
docker0 8000.56847afe9799 no veth44cb727
veth98c3700
Как получить доступ к контейнеру из внешнего мира?
Опять же, с помощью параметра iptables nat
на машине хоста устанавливается соответствие порта.
Open vSwitch является мощной абстракцией сетевой среды. Следующая иллюстрация показывает как OVS взаимодействует с ВМ, Гипервизором и Физическим Коммутатором. Каждая ВМ имеет связанную с ней vNIC. Каждый vNIC соединяется через VIF (также называемый виртуальным интерфейсом, virtual interface) со своим Виртуальным Коммутатором:
OVS применяет механизм туннелирования, например GRE, VXLAN или STT для создания виртуальных оверлеев вместо применения физического построения топологий и компонентов Ethernet. Следующий рисунок отображает то, как OVS может быть настроен для того, чтобы контейнеры могли взаимодействовать между множеством хостов с применением туннелей GRE:
В пределах одного хоста для взаимодействия между контейнерами также можно применять UNIX IPC механизм, в особенности сокеты домена UNIX или конвейеры (pipe):
$ docker run --name c1 –v /var/run/foo:/var/run/foo –d –I –t base /bin/bash
$ docker run --name c2 –v /var/run/foo:/var/run/foo –d –I –t base /bin/bash
Приложения в c1
и c2
могут взаимодействовать через следующие
адреса сокетов Unix:
struct sockaddr_un address;
address.sun_family = AF_UNIX;
snprintf(address.sun_path, UNIX_PATH_MAX, "/var/run/foo/bar" );
|
|
---|---|
|
|
В этом разделе мы введём понятие связывания двух контейнеров. Docker создаёт туннель между вашими контейнерами, который требуется для видимости всех портов внутри данного контейнера. Он применяет переменные среды как один из механизмов для передачи информации от вашего родительского контейнера к его дочернему контейнеру.
Помимо переменной окружения env
, Docker также добавляет запись хоста для контейнера источника
в файл /etc/hosts
. Далее приводится пример такого файла хостов:
$ docker run -t -i --name c2 --rm --link c1:c1alias training/webapp /bin/bash
root@<container_id>:/opt/webapp# cat /etc/hosts
172.17.0.1 aed84ee21bde
...
172.17.0.2 c1alaias 6e5cdeb2d300 c1
Присутствуют две записи:
-
первая является записью для вашего контейнера
c2
, которая применяет идентификатор контейнера Docker в качестве имени хоста. -
Вторая записиь,
172.17.0.2 c1alaias 6e5cdeb2d300 c1
использует псевдоним связи для ссылки на IP адрес вашего контейнераc1
.
Следующий рисунок показывает два контейнера, Container1 и
Container2, соединённые с использованием пар veth с мостом
docker0
с --icc=true
. Это означает, что два данные контейнера
могут осуществлять доступ друг к другу через этот мост:
Соединения (link) обеспечивают службу обнаружения для Docker. Они позволяют контейнерам обнаруживать друг друга и безопасно
взаимодействовать с применением флага -link name:alias
. При помощи этого флага, установленного в
значение false
, Container1 не
может получить доступ к Container2 пока он не будет дозволен в явном
виде через соединение. Это громадное преимущество для безопасности ваших контейнеров. Когда два контейнера соединены вместе, Docker создаёт
между ними взаимосвязь родитель- ребёнок, как продемонстрировано на следующей схеме:
Извне это выглядит следующим образом:
# start the database
$ sudo docker run -dp 3306:3306 --name todomvcdb \
-v /data/mysql:/var/lib/mysql cpswan/todomvc.mysql
# start the app server
$ sudo docker run -dp 4567:4567 --name todomvcapp \
--link todomvcdb:db cpswan/todomvc.sinatra
Изнутри это выглядит так:
$ dburl = ''mysql://root:pa55Word@'' + \ ENV[''DB_PORT_3306_TCP_ADDR''] +
''/todomvc''
$ DataMapper.setup(:default, dburl)
Построение сетей Docker находится на ранней стадии зарождения и существует множество интересных вкладов из сообщества разработчиков,
например, Pipework, Weave, Clocker и Kubernetes. Каждый из них отражает отличный аспект построения сетей Docker. Мы познакомимся с ними
в последующих главах. Помимо этого, Docker, Inc. объявило новый проект, в котором построение сетей приводится к стандарту.
Он называется libnetwork
libnetwork реализует модель сетевого контейнера (CNM, container network model), которая формализует этапы, необходимые для обеспечения построения сетей контейнеров путём предоставления абстракций, которые могут применяться для поддержки многих сетевых драйверов. CNM строится из трёх основных компонентов - песочницы (sandbox), терминала (endpoint) и сетевой среды (network).
Песочница (sandbox) содержит настройки сетевого стека контейнера. Они содержат управление интерфейсами контейнера, таблицу маршрутизации и установки DNS. Реализацией песочницы может быть сетевое пространство имён Linux, клета (jail) FreeBSD, либо другое аналогичное понятие. Песочница может содержать множество терминалов из многих сетевых сред.
Терминал (endpoint) соединяет песочницу с сетевой средой. Реализацией терминала может быть пара veth или внутренний порт Open vSwitch, или нечто подобное. Терминал может относиться только к одной сетевой среде, и при этом может относиться только к одной песочнице.
Сетевая среда является группой терминалов, которые способны напрямую взаимодействовать друг с другом. Реализацией сетевой среды может быть мост Linux, VLAN и тому подобное. Сетевая среда состоит из множества терминалов, как показано на следующей схеме:
CNM обеспечивает следующее соглашение между сетевыми средами и контейнерами:
-
Все контейнеры в одной и той же сетевой среде могут свободно взаимодействовать друг с другом
-
Множество сетевых сред является способом сегментации обмена между контейнерами и оно должно поддерживаться всеми драйверами
-
Множество терминалов на контейнер является способом объединения контейнеров во множество сетевых сред
-
Для обеспечения песочниц сетевой среды сетевой связностью добавляются терминалы
Мы обсудим подробности того, как реализуется CNM в Главе 6. ледующее поколение сетевого стека для Docker: libnetwork.
В этой главе мы изучили существенные компоненты построения сетей Docker, которые развиваются из сочетания простых абстракций Docker и мощных сетевых компонентов, таких как мосты Linux и Open vSwitch.
Мы узнали как контейнеры Docker могут быть созданы в различных режимах. В режиме по умолчанию соответствие портов осуществляется при помощи применения правил NAT iptable, делая возможным возникающий в хосте обмен доставлять контейнерам. Позже в этой главе мы охватили основы связывания контейнеров. Мы также обсудили следующее поколение построения сетей Docker, называемое libnetwork.