Глава 2. Построение сети Docker взгляд вовнутрь

Данная глава подробно обсудит семантику и синтаксис построения сетей Docker, обнажая преимущества и недостатки текущей парадигмы сетевой среды Docker.

Она охватывает следующие темы:

  • Настройку стека IP для Docker

    • Поддержка IPv4

    • Проблемы управления адресами IPv4

    • Поддержка IPv6

  • Настройку DNS

    • Основы DNS

    • Групповой DNS

  • Настройку моста Docker

  • Оверлейные сетевые среды и подстилающие сетевые среды

    • Что это такое?

    • Как Docker применяет их?

    • В чём их некоторые преимущества?

 Настройка стека IP для Docker

Для взаимодействия с внешним миром Docker применяет стек IP, используя TCP или UDP. Он поддерживает инфраструктуры адресации IPv4 и IPv6, которые объясняются в следующих подразделах.

  Поддержка IPv4

По умолчанию Dockeer обеспечивает адресацию IPv4 каждому контейнеру, который подключён к мосту по умолчанию docker0. Диапазон адресов IP может быть определён при запуске демона Docker при помощи флага --fixed-cidr, как показано в следующем коде:


$ sudo docker –d --fixed-cidr=192.168.1.0/25
	   

Более подробно мы обсудим это в разделе Настройка моста Docker.

Помимо сокета Unix, демон Docker может включаться в список терминала IPv4 TCP:


$ sudo docker -H tcp://127.0.0.1:2375 -H unix:///var/run/docker.sock -d &
	   

  Поддержка IPv6

IPv4 и IPv6 могут работать совместно; это называется сдвоенным стеком (dual stack). Такая поддержка сдвоенного стека делается возможной при выполнении демона Docker с флагом --ipv6. Docker установит мост docker0 с локальной связью IPv6 fe80::1. Все совместно используемые между контейнерами пакеты будут проходить через такой мост.

Для назначения маршрутизируемых адресов IPv6 адресов вашим контейнерам вы должны определить подсеть IPv6, откуда вы сможете выбирать нужные адреса.

Следующие команды при помощи параметра --fixed-cidr-v6 устанавливают подсеть IPv6 при запуске демона Docker и кроме того добавляют новый маршрут в таблицу маршрутизации:


# docker –d --ipv6 --fixed-cidr-v6="1553:ba3:2::/64"
# docker run -t -i --name c0 ubuntu:latest /bin/bash
	   

Следующий рисунок демонстрирует настроенный с диапазоном адресов IPv6 мост Docker:

 

Рисунок 2.1. Мост Docker с IPv6


Если внутри контейнера при помощи ifconfig вы проверите диапазон адресов IP, вы отметите, что интерфейсу eth0 была назначена соответствующая подсеть, что показывается в следующем коде:


#ifconfig
eth0      Link encap:Ethernet HWaddr 02:42:ac:11:00:01
          inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:1/64 Scope:Link
          inet6 addr: 1553:ba3:2::242:ac11:1/64 Scope:Global
          UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
          RX packets:7 errors:0 dropped:0 overruns:0 frame:0
          TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:738 (738.0 B) TX bytes:836 (836.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1 Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING MTU:65536 Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
	   

Весь обмен с подсетью 1553:ba3:2::/64 будет маршрутизироваться через интерфейс docker0.

Предыдущий контейнер назначался с применением fe80::42:acff:fe11:1/64 в качестве адреса локальной связи и 1553:ba3:2::242:ac11:1/64 в качестве глабального адреса маршрутизации.

[Замечание]Замечание

Адреса локальной связи (link-local) и контура обратной связи (loopback) имеют сферу действия локальной связи, что означает, что они должны применяться в сетевых средах непосредственного подключения (link). Все прочие адреса имеют глобальную область действия, что означает, что они применяются в глобальной маршрутизации и используются для повсеместной адресации с глобальной сферой деятельности.

 Настройка сервера DNS

Docker предоставляет имя хоста и настройки DNS каждому контейнеру без нашего вмешательства в построение настраиваемого под пользователя образа. Он совмещает (overlay) папку /etc внутри данного контейнера виртуальными файлами, в которые он может записывать новую информацию.

Это можно наблюдать выполнив команду mount внутри этого контейнера. Контейнер получит то же самый файл resolv.conf, который имелся на машине хоста когда он первоначально создавался. Если файл хоста resolv.conf изменяется, это будет в файле контейнера /resolv.conf только когда этот контейнер будет перезапущен.

В Docker вы можете установить параметры DNS двумя способами:

  • Воспользовавшись run --dns=<ip-address>

  • Добавляя DOCKER_OPTS="--dns ip-address" в файл вашего демона Docker

Также вы можете определить поиск домена при помощи --dns-search=<DOMAIN>.

Следующее изображение показывает настроенный в контейнере nameserver с помощью установок DOCKER_OPTS в файле вашего демона Docker:

 

Рисунок 2.2.nameserver с настройками DOCKER_OPTS


Основными файлами DNS являются:

  • /etc/hostname

  • /etc/resolv.conf

  • /etc/hosts

Вот команда для добавления сервера DNS:


# docker run --dns=8.8.8.8 --net="bridge" -t -i ubuntu:latest /bin/bash
	   

Имена хостов добавляются следующей командой:


#docker run --dns=8.8.8.8 --hostname=docker-vm1 -t -i ubuntu:latest /bin/bash
	   

  Взаимодействие между контейнером и внешними сетями

Обмен пакетами между контейнерами может осуществляться только если параметр ip-forward установлен в значение 1. Обычно вы просто оставляете сервер Docker в состоянии настроек по умолчанию, --ip-forward=true, а Docker установит ip-forward в значение 1 для вас при старте этого сервера.

Для проверки текущих установок или включения пересылки IP вручную воспользуйтесь следующими командами:


# cat /proc/sys/net/ipv4/ip_forward
0#
echo 1 > /proc/sys/net/ipv4/ip_forward
# cat /proc/sys/net/ipv4/ip_forward
1
 	   

Разрешив ip-forward, пользователи могут сделать возможным взаимодействие между контейнерами и их внешним миром; это также будет необходимо для взаимодействия между контейнерами в случае с установкой со множеством мостов. Следующий рисунок показывает как --ip-forward=true {Прим. пер.: В оригинале опечатка: --ip-forward=false.} перенаправляет все пакеты к/от контейнера из/в внешней сетевой среды:

 

Рисунок 2.3. обмен пакетами между контейнером и внешней сетью при --ip-forward=true


Docker не удаляет и не изменяет никакие правила в установленной цепочке фильтрации Docker. Это делает возможным пользователю создавать правила ограничения доступа к контейнеру.

Docker использует мост docker0 для потоков пакетов между всеми имеющимися контейнерами на единичном хосте. Он добавляет правило для пересылки по цепочке используя IPTables для организации перемещения пакетов между двумя контейнерами. Установка --icc=false отбрасывает все имеющиеся пакеты.

Когда демон Docker настроен и на --icc=false, и на --iptables=true, а docker run выполняется с параметром --link, сервер Docker вставит пару правил приёма из IPTables для новых контейнеров для соединения с портами, выставляемыми другими его контейнерами, которые будут портами, которые упоминаются в строках выставления в своих Dockerfile. Следующий рисунок отображает как ip_forward = false отбрасывает все пакеты к/от контейнеру из/в внешней сетевой среды:

 

Рисунок 2.4. отброс пакетов между контейнером и внешней сетью при --ip-forward=false


По умолчанию правило Docker forward разрешает все внешние IP. Для открытия доступа только к определённым IP или сетевой среде, добавьте в верхней части цепочки фильтрации Docker отвергающее правило.

Например, применяя следующую команду вы можете ограничить внешний доступ таким образом, что к данному контейнеру может осуществлять доступ только обладатель IP источника 10.10.10.10:


#iptables –I DOCKER –i ext_if ! –s 10.10.10.10 –j DROP
 	   
 

Ограничение доступа из одного контейнера к другому на SSH

Для ограничения SSH доступа от одного контейнера к другому следуйте таким шагам:

  1. Создайте два контейнера, c1 и c2.

    Для c1 воспользуйтесь следующей командой:

    
    # docker run -i -t --name c1 ubuntu:latest /bin/bash
     	   

    Она породит следующий вывод:

    
    root@7bc2b6cb1025:/# ifconfig
    eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:05
              inet addr:172.17.0.5  Bcast:0.0.0.0 Mask:255.255.0.0
              inet6 addr: 2001:db8:1::242:ac11:5/64 Scope:Global
              inet6 addr: fe80::42:acff:fe11:5/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
              RX packets:7 errors:0 dropped:0 overruns:0 frame:0
              TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0
              RX bytes:738 (738.0 B) TX bytes:696 (696.0 B)
    lo        Link encap:Local Loopback
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536 Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
     	   

    Для c2 воспользуйтесь следующей командой:

    
    # docker run -i -t --name c2 ubuntu:latest /bin/bash
     	   

    Она породит следующий вывод:

    
    root@e58a9bf7120b:/# ifconfig
    eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:06
              inet addr:172.17.0.6  Bcast:0.0.0.0 Mask:255.255.0.0
              inet6 addr: 2001:db8:1::242:ac11:6/64 Scope:Global
              inet6 addr: fe80::42:acff:fe11:6/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
              RX packets:6 errors:0 dropped:0 overruns:0 frame:0
              TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0
              RX bytes:648 (648.0 B)  TX bytes:696 (696.0 B)
    lo        Link encap:Local Loopback
              inet addr:127.0.0.1  Mask:255.0.0.0
              inet6 addr: ::1/128 Scope:Host
              UP LOOPBACK RUNNING  MTU:65536 Metric:1
              RX packets:0 errors:0 dropped:0 overruns:0 frame:0
              TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:0
              RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
     	   

    Мы можем проверить наличие связи между контейнерами с использованием только что обнаруженных нами адресов. Давайте посмотри её сейчас применив инструмент ping:

    
    root@7bc2b6cb1025:/# ping 172.17.0.6
    PING 172.17.0.6 (172.17.0.6) 56(84) bytes of data.
    64 bytes from 172.17.0.6: icmp_seq=1 ttl=64 time=0.139 ms
    64 bytes from 172.17.0.6: icmp_seq=2 ttl=64 time=0.110 ms
    ^C
    --- 172.17.0.6 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 999ms
    rtt min/avg/max/mdev = 0.110/0.124/0.139/0.018 ms
    root@7bc2b6cb1025:/#
    
    root@e58a9bf7120b:/# ping 172.17.0.5
    PING 172.17.0.5 (172.17.0.5) 56(84) bytes of data.
    64 bytes from 172.17.0.5: icmp_seq=1 ttl=64 time=0.270 ms
    64 bytes from 172.17.0.5: icmp_seq=2 ttl=64 time=0.107 ms
    ^C
    --- 172.17.0.5 ping statistics ---
    2 packets transmitted, 2 received, 0% packet loss, time 1002ms
    rtt min/avg/max/mdev = 0.107/0.188/0.270/0.082 ms
    root@e58a9bf7120b:/#
     	   
  2. Установите в обоих контейнерах сервер openssh-server

    
    #apt-get install openssh-server
     	   
  3. Сделайте доступными iptables в вашей машине хоста:

    1. Изначально вам будет доступен SSH из одного контейнера к другому.

    2. Остановите службу Docker и добавьте DOCKER_OPTS="--icc=false --iptables=true" в Dockerfile по умолчанию вашей машины хоста. Этот параметр сделает доступным межсетевой экран iptables и отбросит все порты между контейнерами.

      По умолчанию, iptables не являются доступными на вашем хосте. Воспользуйтесь следующей командой для их доступности:

      
      root@ubuntu:~# iptables -L -n
      Chain INPUT (policy ACCEPT)
      target     prot opt source            destination
      Chain FORWARD (policy ACCEPT)
      target     prot opt source            destination
      DOCKER     all — 0.0.0.0/0         0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0         ctstate
      RELATED,ESTABLISHED
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0
      DOCKER     all — 0.0.0.0/0         0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0         ctstate
      RELATED,ESTABLISHED
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0         0.0.0.0/0
      
      #service docker stop
      #vi /etc/default/docker
       	   
    3. Docker Upstart и SysVinit файл установок. Настройте под себя местоположение своего исполняемого Docker (в особенности, при тестировании в процессе разработки):

      
      #DOCKER="/usr/local/bin/docker"
       	   
    4. Перезапустите службу Docker:

      
      # service docker start
       	   
    5. Проверьте iptables:

      
      root@ubuntu:~# iptables -L -n
      Chain INPUT (policy ACCEPT)
      target     prot opt source                         destination
      Chain FORWARD (policy ACCEPT)
      target     prot opt source                         destination
      DOCKER     all — 0.0.0.0/0                      0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0                      0.0.0.0/0    ctstate RELATED,
      ESTABLISHED
      ACCEPT     all — 0.0.0.0/0                      0.0.0.0/0
      DOCKER     all — 0.0.0.0/0                      0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0                      0.0.0.0/0    ctstate RELATED,
      ESTABLISHED
      ACCEPT     all — 0.0.0.0/0                      0.0.0.0/0
      ACCEPT     all — 0.0.0.0/0                      0.0.0.0/0
      DROP       all — 0.0.0.0/0                      0.0.0.0/0
       	   

      В iptables вашей машины хоста было добавлено правило DROP, которое отвергает соединение между контейнерами. Теперь вам будет недоступен SSH между контейнерами.

    6. 
      [root@us-east-1 ~]# s3cmd ls s3://owncloud 
       	   
  4. Мы можем взаимодействовать или соединиться с контейнерами с применением параметра --link при помощи следующих шагов:

    1. Создайте первый контейнер, который будет выступать в роли вашего сервера, sshserver:

      
      root@ubuntu:~# docker run -i -t -p 2222:22 --name sshserver ubuntu bash
      root@9770be5acbab:/#
       	   
    2. Выполните команду iptables и вы увидите добавленную цепочку правил Docker:

      
      #root@ubuntu:~# iptables -L -n
      Chain INPUT (policy ACCEPT)
      target     prot opt source                      destination
      Chain FORWARD (policy ACCEPT)
      target     prot opt source                      destination
      Chain OUTPUT (policy ACCEPT)
      target     prot opt source                      destination
      Chain DOCKER (0 references)
      target     prot opt source                      destination
      ACCEPT     tcp — 0.0.0.0/0                     172.17.0.3      tcp dpt:22
       	   
    3. Создайте второй контейнер, который выступает в роли клиента, sshclient:

      
      root@ubuntu:~# docker run -i -t --name sshclient --link sshserver:sshserver ubuntu bash
      root@979d46c5c6a5:/#
       	   
    4. Мы можем видеть, что появились дополнительные правила в цепочке правил Docker:

      
      root@ubuntu:~# iptables -L -n
      Chain INPUT (policy ACCEPT)
      target     prot opt source                      destination
      Chain FORWARD (policy ACCEPT)
      target     prot opt source                      destination
      Chain OUTPUT (policy ACCEPT)
      target     prot opt source                      destination
      Chain DOCKER (0 references)
      target     prot opt source                      destination
      ACCEPT     tcp — 0.0.0.0/0                   172.17.0.3           tcp dpt:22
      ACCEPT     tcp — 172.17.0.4                  172.17.0.3           tcp dpt:22
      ACCEPT     tcp — 172.17.0.3                  172.17.0.4           tcp spt:22
      root@ubuntu:~#
       	   

      Следующий рисунок объясняет взаимодействие между контейнерами с применением флага --link:

       

      Рисунок 2.5. взаимодействие между контейнерами с применением флага --link


  5. Вы можете проинспектировать свой присоединённый контейнер при помощи команды docker inspect:

    
    root@ubuntu:~# docker inspect -f "{{ .HostConfig.Links }}" sshclient
    [/sshserver:/sshclient/sshserver]
     	   

    теперь вы можете успешно осуществлять доступ ssh к sshserver по его IP адресу.

    
    #ssh root@172.17.0.3 –p 22
     	   

Применяя параметр --link, Docker создаёт безопасный канал между контейнерами который не требует делать видимыми вовне никакие порты ваших контейнеров.

 Настройка моста Docker

Сервер Docker создаёт мост с именем docker0 по умолчанию внутри ядра Linux, а он может передавать пакеты назад и далее между остальными физическими или виртуальными интерфейсами так, как если бы они вели себя как отдельные сети Ethernet. Выполните следующую команду для обнаружения списка интерфейсов в ВМ и те IP адреса, к которым они подключены:


root@ubuntu:~# ifconfig
docker0   Link encap:Ethernet  HWaddr 56:84:7a:fe:97:99
          inet addr:172.17.42.1  Bcast:0.0.0.0 Mask:255.255.0.0
          inet6 addr: fe80::5484:7aff:fefe:9799/64 Scope:Link
          inet6 addr: fe80::1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
          RX packets:11909 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14826 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:516868 (516.8 KB)  TX bytes:46460483 (46.4 MB)
eth0      Link encap:Ethernet  HWaddr 00:0c:29:0d:f4:2c
          inet addr:192.168.186.129  Bcast:192.168.186.255
Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe0d:f42c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500 Metric:1
          RX packets:108865 errors:0 dropped:0 overruns:0 frame:0
          TX packets:31708 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:59902195 (59.9 MB)  TX bytes:3916180 (3.9 MB)
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:336 (336.0 B)  TX bytes:336 (336.0 B)
 	   

Когда у вас в наличии один или более запущенных и работающих контейнеров, вы можете подтвердить, что Docker надлежащим образом соединил их с мостом docker0 выполнив на своей машине хоста команду brctl и промотрев его колонку вывода interfaces.

Перед настройкой моста docker0 установите утилиты моста:


# apt-get install bridge-utils
 	   

Вот хост с двумя различными присоединёнными контейнерами:


root@ubuntu:~# brctl show
bridge name     bridge id                STP enabled       interfaces
docker0         8000.56847afe9799        no                veth21b2e16
                                                           veth7092a45
 	   

Docker применяет настройки docker0 при каждом создании контейнера. Он назначает новый IP адрес из доступного диапазона в мосте при каждом создании нового контейнера, как мы можем увидеть здесь:


root@ubuntu:~# docker run -t -i --name container1 ubuntu:latest /bin/bash
root@e54e9312dc04:/# ifconfig
eth0      Link encap:Ethernet  HWaddr 02:42:ac:11:00:07
          inet addr:172.17.0.7  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: 2001:db8:1::242:ac11:7/64 Scope:Global
          inet6 addr: fe80::42:acff:fe11:7/64 Scope:Link
          UP BROADCAST RUNNING  MULTICAST  MTU:1500 Metric:1
          RX packets:7 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:738 (738.0 B)  TX bytes:696 (696.0 B)
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
root@e54e9312dc04:/# ip route
default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.7
 	   

По умолчанию Docker обеспечивает виртуальную сетевую среду с именем docker0, которая имеет IP адрес 172.17.42.1. Контейнеры Docker имеют IP адреса в диапазоне 172.17.0.0/16.

Для изменения в Docker настроек умолчанию, отредактируйте его файл /etc/default/docker.

Изменения моста по умолчанию с docker0 на br0 может быть сделано следующим образом:


# sudo service docker stop
# sudo ip link set dev docker0 down
# sudo brctl delbr docker0
# sudo iptables -t nat -F POSTROUTING
# echo 'DOCKER_OPTS="-b=br0"' >> /etc/default/docker
# sudo brctl addbr br0
# sudo ip addr add 192.168.10.1/24 dev br0
# sudo ip link set dev br0 up
# sudo service docker start
 	   

Следующая команда отображает новое имя моста и диапазон IP адресов службы Docker:


root@ubuntu:~# ifconfig
br0       Link encap:Ethernet  HWaddr ae:b2:dc:ed:e6:af
          inet addr:192.168.10.1  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::acb2:dcff:feed:e6af/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:738 (738.0 B)
eth0      Link encap:Ethernet  HWaddr 00:0c:29:0d:f4:2c
          inet addr:192.168.186.129 Bcast:192.168.186.255
Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe0d:f42c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:110823 errors:0 dropped:0 overruns:0 frame:0
          TX packets:33148 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:60081009 (60.0 MB)  TX bytes:4176982 (4.1 MB)
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536 Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:336 (336.0 B)  TX bytes:336 (336.0 B)
 	   

 Перекрывающие и лежащие в основе сетевые среды

Оверлейными (перекрывающими, overlay) являются виртуальные сетевые среды, которые стрятся поверх лежащих в основе сетевых инфраструктур (подстилающие, underlay). Их цель состоит в реализации сетевых служб, которые не доступны в физической сетевой среде.

Сетевые оверлеи драматически увеличивают число виртуальных подсетей которые могут быть созданы поверх физической сетевой среды, что в конечном итоге поддерживает множественную аренду и виртуализацию.

Каждому контейнеру в Docker назначается некий IP адрес, который применяется для взаимодействия с остальными контейнерами. Если контейнер должен взаимодействовать со своей внешней сетевой средой, вы настраиваете сетевую среду в системе хоста и выделяете или ставите в соответствие порт из контейнера в машину хоста. При таком подходе работающие внутри контейнера приложения не будут способны афишировать свои внешние IP и порты, поскольку данная информация им не доступна.

Решение в чём-то похоже назначению уникальных IP каждому контейнеру Docker по всем хостам и наличию некоторого сетевого продукта, который выполняет маршрутизацию обмена между хостами.

Для работы с сетевыми средами Docker существуют различные проекты, а именно:

  • Flannel

  • Weave

  • Open vSwitch

Flannel предоставляет решение, обеспечивая каждому контейнеру некий IP который может применяться для взаимодействия контейнера- с- контейнером. Применяя инкапсуляцию пакета, он создаёт виртуальную оверлейную сетевую среду поверх сетевой среды хоста. По умолчанию, Flannel обеспечивает хосту подсеть /24, из которой демон выделяет IP контейнерам. Следующий рисунок показывает взаимодействие между контейнерами с применением Flannel:

 

Рисунок 2.6. взаимодействие между контейнерами с применением Flannel


На всех хостах flannel работает как агент, flanneld, и отвечает за выделение ареды подсети из предварительно настроенного пространства адресов. Для хранения настроек сетевой среды, выделения подсетей и вспомогательных данных (например, IP хоста) Flannel использует etcd.

Flannel применяет универсальное устройство TUN/TAP и создаёт оверлейную сетевую среду применяя UDP для инкапсуляции пакетов IP. Выделение подсети выполняется при помощи etcd, который устанавливает перекрывающее соответствие подсети-к-хосту.

Weave создаёт виртуальную сетевую среду, которая соединяет контейнеры Docker, развёртываемые в хостах/ ВМ и делает возможным их автоматическое обнаружение. Следующий рисунок отображает сетевую среду Weave:

 

Рисунок 2.7. Контейнеры в сетевой среде Weave


Weave способен преодолевать межсетевые экраны и работать в частично соединённых сетевых средах. Обмен может быть опционально закодирован, что делает возможным хостам/ ВМ соединяться в сетевых средах с неподтверждённой безопасностью.

Weave расширяет существующие сетевые возможности Docker (для единичного хоста), такие как мост docker0, следовательно они могут продолжать применяться контейнерами.

Open vSwitch является виртуальным коммутатором с OpenFlow- совместимым открытым исходным кодом, который обычно применяется с гипервизорами для интерконнекта виртуальных машин в пределах хоста, а также между различными хостами в сетевых средах. Перекрывающие сетевые среды требуют создания виртуальных путей данных с применением поддерживаемой инкапсуляции туннелирования, например, VXLAN и GRE.

Оверлейный путь данных предоставляется между терминалами туннеля расположенными в хосте Docker, что даёт возможность всем хостам в пределах данного сегмента поставщика напрямую соединяться друг с другом.

Как только контейнер становится работающим, в протоколе маршрутизации обновляется его префикс, объявляя его местоположение в качестве терминала туннеля. По мере получения обновлений прочими хостами Docker, правила перенаправления устанавливаются в OVS для терминала (endpoint) туннеля, который размежает данный хост. При свёртывании хоста происходит аналогичный процесс и терминал хостов Docker удаляет записи перенаправления для сворачиваемого контейнера. Следующий рисунок отображает взаимодействие между контейнерами работающими на множестве хостов через туннели VXLAN на основе OVS:

 

Рисунок 2.8. Взаимодействие контейнеров в сетевой среде с множеством хостов по туннелям VXLAN на основе OVS


 Заключение

В этой главе мы обсудили внутреннюю сетевую архитектуру Docker. Мы изучили настройки IPv4, IPv6 и DNS в Docker. Затем в этой главе мы рассмотрели мост Docker и взаимодействие между контейнерами в пределах одного хоста и множества хостов.

Также мы обсудили оверлейное туннелирование и различные методы которые реализуются в сетевых средах Docker, таких как OVS, Flannel и Weave.

В следующей главе мы изучим практическое построение сетей Docker, собираемых воедино при помощи различных инфраструктур.