Сеть с оверлейными сетями

Эта серия руководств посвящена организации сети для служб swarm. Сведения о работе в сети с автономными контейнерами см. в статье Сеть с автономными контейнерами. Если вам нужно узнать больше о сети Docker в целом, см. статью обзор.

Эта тема включает четыре различных руководства. Вы можете выполнить каждый из них в Linux, Windows или Mac, но для последних двух вам понадобится второй хост Docker, работающий в другом месте.

Предпосылки

Для этого требуется, чтобы у вас был хотя бы один узел swarm, что означает, что вы запустили Docker и запустили docker swarm init на хосте. Вы также можете выполнить примеры на мультиузле swarm.

Используйте оверлейную сеть по умолчанию

В этом примере вы запускаете службу alpine и изучаете характеристики сети с точки зрения отдельных контейнеров службы.

В этом учебнике не рассматриваются специфичные для операционной системы подробности о том, как реализуются оверлейные сети, а основное внимание уделяется тому, как работает оверлей с точки зрения службы.

Предпосылки

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

Данные хосты будут называться manager, worker-1 и worker-2. Хост manager будет работать и как менеджер, и как рабочий, что означает, что он может выполнять сервисные задачи и управлять сервером swarm. worker-1 и worker-2 будут работать только как рабочие,

Если у вас нет под рукой трёх хостов, простое решение — настроить три хоста Ubuntu на облачном провайдере, таком как Amazon EC2, все в одной сети со всеми соединениями, разрешенными для всех хостов в этой сети (используя такой механизм, как группы безопасности EC2), а затем следовать коду инструкции по установке Docker Engine — Сообщество в Ubuntu.

Прохождение

Создаёт swarm

В конце этой процедуры все три хоста Docker будут присоединены к swarm и будут соединены друг с другом с помощью оверлейной сети с именем ingress.

  1. На manager. инициализировать swarm. Если хост имеет только один сетевой интерфейс, флаг --advertise-addr необязателен.

    $ docker swarm init --advertise-addr=<IP-ADDRESS-OF-MANAGER>
    

    Записывает напечатанный текст, т. к. он содержит токен, который вы будете использовать для присоединения worker-1 и worker-2 к swarm. Рекомендуется хранить токен в менеджере паролей.

  2. В worker-1 присоединитесь к swarm. Если хост имеет только один сетевой интерфейс, флаг --advertise-addr необязателен.

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-1> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  3. На worker-2 присоединитесь к swarm. Если хост имеет только один сетевой интерфейс, флаг --advertise-addr необязателен.

    $ docker swarm join --token <TOKEN> \
      --advertise-addr <IP-ADDRESS-OF-WORKER-2> \
      <IP-ADDRESS-OF-MANAGER>:2377
    
  4. На manager перечислите все узлы. Эту команду можно выполняет только из менеджера.

    $ docker node ls
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    

    Вы также можете использовать флаг --filter для фильтрации по роли:

    $ docker node ls --filter role=manager
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    d68ace5iraw6whp7llvgjpu48 *   ip-172-31-34-146    Ready               Active              Leader
    
    $ docker node ls --filter role=worker
    
    ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS
    nvp5rwavvb8lhdggo8fcf7plg     ip-172-31-35-151    Ready               Active
    ouvx2l7qfcxisoyms8mtkgahw     ip-172-31-36-89     Ready               Active
    
  5. Перечислите сети Docker на manager, worker-1 и worker-2 и обратите внимание, что каждая из них теперь имеет оверлейную сеть с именем ingress и мостовую сеть с именем docker_gwbridge. Здесь показан только список для manager:

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    495c570066be        bridge              bridge              local
    961c6cae9945        docker_gwbridge     bridge              local
    ff35ceda3643        host                host                local
    trtnl4tqnc3n        ingress             overlay             swarm
    c8357deec9cb        none                null                local
    

docker_gwbridge подключает сеть ingress к сетевому интерфейсу узла Docker, чтобы трафик мог передаваться к менеджерам и рабочим swarm и от них. Если вы создаёте службы swarm и не указываете сеть, они подключаются к сети ingress. Рекомендуется использовать отдельные оверлейные сети для каждого приложения или группы приложений, которые будут работать вместе. В следующей процедуре вы создадите две оверлейные сети и подключите службу к каждой из них.

Создаёт службы

  1. На manager создаёт новую оверлейную сеть с именем nginx-net:

    $ docker network create -d overlay nginx-net
    

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

  2. На manager создаёт службу Nginx с 5 репликами, подключенную к nginx-net. Сервис опубликует порт 80 для внешнего мира. Все контейнеры сервисных задач могут взаимодействовать друг с другом, не открывая никаких портов.

    Примечание

    Сервисы можно создавать только на менеджере.

    $ docker service create \   --name my-nginx \   --publish target=80,published=80 \   --replicas=5 \   --network nginx-net \   nginx
    

    Режим публикации по умолчанию ingress, который используется, когда вы не указываете mode для флага --publish, означает, что если вы перейдете к порту 80 на manager, worker-1 или worker-2, вы будете подключены к порту 80 на одном из 5 служебные задачи, даже если на узле, к которому вы просматриваете, в настоящее время не выполняются никакие задачи. Если вы хотите опубликовать порт в режиме host, вы можете добавить mode=host к выводу --publish. Однако в этом случае также следует использовать --mode global вместо --replicas=5, т. к. только одна сервисная задача может привязать данный порт к данному узлу.

  3. Выполните docker service ls, чтобы отслеживать ход запуска службы, что может занять несколько секунд.

  4. Проверяет сеть nginx-net на manager, worker-1 и worker-2. Помните, что вам не нужно было создавать его вручную на worker-1 и worker-2, потому что Docker создал его для вас. Вывод будет длинным, но обратите внимание на разделы Containers и Peers. Containers перечисляет все сервисные задачи (или автономные контейнеры), подключенные к оверлейной сети с этого хоста.

  5. Из manager проверяет службу, используя docker service inspect my-nginx, и обратите внимание на информацию о портах и конечных точках, используемых службой.

  6. Создаёт новую сеть nginx-net-2, затем обновляет службу, чтобы использовать эту сеть вместо nginx-net:

    $ docker network create -d overlay nginx-net-2
    
    $ docker service update \
      --network-add nginx-net-2 \
      --network-rm nginx-net \
      my-nginx
    
  7. Выполните docker service ls, чтобы убедиться, что служба была обновлена и все задачи были повторно развернуты. Выполните docker network inspect nginx-net, чтобы убедиться, что к нему не подключены контейнеры. Выполняет ту же команду для nginx-net-2 и обратите внимание, что все контейнеры служебных задач подключены к нему.

    Примечание

    Несмотря на то, что оверлейные сети автоматически создаются на рабочих узлах swarm по мере необходимости, они не удаляются автоматически.

  8. Очищает сервис и сети. Из manager выполняет следующие команды. Менеджер направит рабочих на автоматическое удаление сетей.

    $ docker service rm my-nginx
    $ docker network rm nginx-net nginx-net-2
    

Используйте определяемую пользователем оверлейную сеть

Предпосылки

В этом руководстве предполагается, что swarm уже настроен, и вы используете менеджер.

Прохождение

  1. Создаёт пользовательскую оверлейную сеть.

    $ docker network create -d overlay my-overlay
    
  2. Выполните службу, используя оверлейную сеть и опубликовав порт 80 на порт 8080 на хосте Docker.

    $ docker service create \
      --name my-nginx \
      --network my-overlay \
      --replicas 1 \
      --publish published=8080,target=80 \
      nginx:latest
    
  3. Выполните docker network inspect my-overlay и убедиться, что к нему подключена сервисная задача my-nginx, просмотрев раздел Containers.

  4. Удаляет службу и сеть.

    $ docker service rm my-nginx
    
    $ docker network rm my-overlay
    

Используйте оверлейную сеть для автономных контейнеров

В этом примере демонстрируется обнаружение контейнеров DNS, в частности, как обмениваться данными между автономными контейнерами в разных демонах Docker с использованием оверлейной сети. Шаги есть:

  • В host1 инициализировать узел как swarm (менеджер).

  • В host2 присоедините узел к swarm (рабочий).

  • В host1 создаёт присоединяемую оверлейную сеть (test-net).

  • В host1 запускается интерактивный контейнер alpine (alpine1) в test-net.

  • В host2 запускается интерактивный и отсоединенный контейнер alpine (alpine2) в test-net.

  • На host1 из сеанса alpine1 отправить эхо-запрос alpine2.

Предпосылки

Для этого теста вам понадобятся два разных хоста Docker, которые могут взаимодействовать друг с другом. На каждом хосте должны быть открыты следующие порты между двумя хостами Docker:

  • TCP-порт 2377

  • TCP- и UDP-порт 7946

  • UDP-порт 4789

Один из простых способов настроить это — иметь две виртуальные машины (либо локальные, либо в облачном провайдере, таком как AWS), на каждой из которых установлен и запущен Docker. Если вы используете AWS или аналогичную платформу облачных вычислений, проще всего настроить группу безопасности, которая открывает все входящие порты между двумя хостами и порт SSH с IP-адреса вашего клиента.

В этом примере два узла в swarm называются host1 и host2. В этом примере также используются хосты Linux, но те же самые команды работают и в Windows.

Прохождение

  1. Настраивает swarm.

    1. В host1 инициализировать swarm (и, если будет предложено, используйте --advertise-addr, чтобы указывает IP-адрес для интерфейса, который взаимодействует с другими хостами в swarm, например, частный IP-адрес в AWS):

    $ docker swarm init
    Swarm initialized: current node (vz1mm9am11qcmo979tlrlox42) is now a manager.
    
    To add a worker to this swarm, run the following command:
    
        docker swarm join --token SWMTKN-1-5g90q48weqrtqryq4kj6ow0e8xm9wmv9o6vgqc5j320ymybd5c-8ex8j0bc40s6hgvy5ui5gl4gy 172.31.47.252:2377
    
    To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
    
    1. В host2 присоединитесь к swarm, как указано выше:

    $ docker swarm join --token <your_token> <your_ip_address>:2377
    This node joined a swarm as a worker.
    

    Если узлу не удаётся присоединиться к swarm, время ожидания команды docker swarm join истекает. Чтобы устранить проблему, выполните docker swarm leave --force на host2, проверяет настройки сети и брандмауэра и повторяет попытку.

  2. В host1 создаёт присоединяемую оверлейную сеть с именем test-net:

    $ docker network create --driver=overlay --attachable test-net
    uqsof8phj3ak0rq9k86zta6ht
    

    Примечание

    Обратите внимание на возвращённый NETWORK ID — вы увидите его снова, когда подключитесь к нему с host2.

  3. На host1 запускается интерактивный (-it) контейнер (alpine1), который подключается к test-net:

    $ docker run -it --name alpine1 --network test-net alpine
    / #
    
  4. На host2 перечислите доступные сети — обратите внимание, что test-net ещё не существует:

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ec299350b504        bridge              bridge              local
    66e77d0d0e9a        docker_gwbridge     bridge              local
    9f6ae26ccb82        host                host                local
    omvdxqrda80z        ingress             overlay             swarm
    b65c952a4b2b        none                null                local
    
  5. В host2 запускается отдельный (-d) и интерактивный (-it) контейнер (alpine2), который подключается к test-net:

    $ docker run -dit --name alpine2 --network test-net alpine
    fb635f5ece59563e7b8b99556f816d24e6949a5f6a5b1fbd92ca244db17a4342
    
    Automatic DNS container discovery only works with unique
    container names.
    
  6. На host2 убедиться, что test-net был создан (и имеет тот же NETWORK ID, что и test-net на host1):

    $ docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    ...
    uqsof8phj3ak        test-net            overlay             swarm
    
  7. На host1 отправить эхо-запрос alpine2 в интерактивном терминале alpine1:

    / # ping -c 2 alpine2
    PING alpine2 (10.0.0.5): 56 data bytes
    64 bytes from 10.0.0.5: seq=0 ttl=64 time=0.600 ms
    64 bytes from 10.0.0.5: seq=1 ttl=64 time=0.555 ms
    
    --- alpine2 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 0.555/0.577/0.600 ms
    

    Два контейнера взаимодействуют с оверлейной сетью, соединяющей два хоста. Если вы запускаете другой контейнер alpine на host2, который не отсоединён, вы можете пропинговать alpine1 из host2 (здесь мы добавляем опцию remove для автоматической очистки контейнера):

    $ docker run -it --rm --name alpine3 --network test-net alpine
    / # ping -c 2 alpine1
    / # exit
    
  8. На host1 закрывает сеанс alpine1 (который также останавливает контейнер):

    / # exit
    
  9. Очищает свои контейнеры и сети:

    Вы должны останавливать и удалять контейнеры на каждом хосте независимо, потому что демоны Docker работают независимо, и это автономные контейнеры. Вам нужно только удаляет сеть на host1, потому что, когда вы останавливаете alpine2 на host2, test-net исчезает.

    1. На host2 останавливает alpine2, убедиться, что test-net был удален, затем удаляет alpine2:

    $ docker container stop alpine2
    $ docker network ls
    $ docker container rm alpine2
    
    1. На host1 удаляет alpine1 и test-net:

    $ docker container rm alpine1
    $ docker network rm test-net
    

Связь между контейнером и службой swarm

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

  1. Открывает окно терминала. Перечислите текущие сети, прежде чем делать что-либо ещё. Вот что вы должны увидеть, если вы никогда не добавляли сеть или не инициализировали swarm в этом демоне Docker. Вы можете видеть разные сети, но вы должны видеть хотя бы данные (идентификаторы сетей будут другими):

    $ docker network ls
    
    NETWORK ID          NAME                DRIVER              SCOPE
    17e324f45964        bridge              bridge              local
    6ed54d316334        host                host                local
    7092879f2cc8        none                null                local
    

    Сеть по умолчанию bridge указана вместе с host и none. Последние два не являются полноценными сетями, но используются для запуска контейнера, подключенного непосредственно к сетевому стеку хоста демона Docker, или для запуска контейнера без сетевых устройств. Это руководство соединит два контейнера в мостовой сети.

  2. Запускает два контейнера alpine с ash, который является оболочкой Alpine по умолчанию, а не bash. Флаги -dit означают запуск контейнера отсоединенным (в фоновом режиме), интерактивным (с возможностью ввода в него) и с TTY (чтобы вы могли видеть ввод и вывод). Поскольку вы запускаете его отдельно, вы не сразу подключитесь к контейнеру. Вместо этого будет напечатан идентификатор контейнера. Поскольку вы не указали флаги --network, контейнеры подключаются к сети bridge по умолчанию.

    $ docker run -dit --name alpine1 alpine ash
    
    $ docker run -dit --name alpine2 alpine ash
    

    Убедиться, что оба контейнера действительно запущены:

    $ docker container ls
    
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    602dbf1edc81        alpine              "ash"               4 seconds ago       Up 3 seconds                            alpine2
    da33b7aa74b0        alpine              "ash"               17 seconds ago      Up 16 seconds                           alpine1
    
  3. Проверяет сеть bridge, чтобы узнать, какие контейнеры к ней подключены.

    $ docker network inspect bridge
    
    [
        {
            "Name": "bridge",
            "Id": "17e324f459648a9baaea32b248d3884da102dde19396c25b30ec800068ce6b10",
            "Created": "2017-06-22T20:27:43.826654485Z",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": null,
                "Config": [
                    {
                        "Subnet": "172.17.0.0/16",
                        "Gateway": "172.17.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Containers": {
                "602dbf1edc81813304b6cf0a647e65333dc6fe6ee6ed572dc0f686a3307c6a2c": {
                    "Name": "alpine2",
                    "EndpointID": "03b6aafb7ca4d7e531e292901b43719c0e34cc7eef565b38a6bf84acf50f38cd",
                    "MacAddress": "02:42:ac:11:00:03",
                    "IPv4Address": "172.17.0.3/16",
                    "IPv6Address": ""
                },
                "da33b7aa74b0bf3bda3ebd502d404320ca112a268aafe05b4851d1e3312ed168": {
                    "Name": "alpine1",
                    "EndpointID": "46c044a645d6afc42ddd7857d19e9dcfb89ad790afb5c239a35ac0af5e8a5bc5",
                    "MacAddress": "02:42:ac:11:00:02",
                    "IPv4Address": "172.17.0.2/16",
                    "IPv6Address": ""
                }
            },
            "Options": {
                "com.docker.network.bridge.default_bridge": "true",
                "com.docker.network.bridge.enable_icc": "true",
                "com.docker.network.bridge.enable_ip_masquerade": "true",
                "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
                "com.docker.network.bridge.name": "docker0",
                "com.docker.network.driver.mtu": "1500"
            },
            "Labels": {}
        }
    ]
    

    В верхней части указана информация о сети bridge, включая IP-адрес шлюза между хостом Docker и сетью bridge (172.17.0.1). Под ключом Containers перечислены все подключенные контейнеры вместе с информацией о его IP-адресе (172.17.0.2 для alpine1 и 172.17.0.3 для alpine2).

  4. Контейнеры работают в фоновом режиме. Используйте команду docker attach для подключения к alpine1.

    $ docker attach alpine1
    
    / #
    

    Приглашение изменится на #, чтобы указывает, что вы являетесь пользователем root в контейнере. Используйте команду ip addr show, чтобы показывает сетевые интерфейсы для alpine1, как они выглядят внутри контейнера:

    # ip addr show
    
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host
           valid_lft forever preferred_lft forever
    27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
        link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.2/16 scope global eth0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:acff:fe11:2/64 scope link
           valid_lft forever preferred_lft forever
    

    Первый интерфейс — это loopback-устройство. Игнорировать это пока. Обратите внимание, что второй интерфейс имеет IP-адрес 172.17.0.2, который совпадает с адресом, показанным для alpine1 на предыдущем шаге.

  5. Изнутри alpine1 убедиться, что вы можете подключиться к Интернету, отправив эхо-запрос google.com. Флаг -c 2 ограничивает выполнение команды двумя двумя попытками ping.

    # ping -c 2 google.com
    
    PING google.com (172.217.3.174): 56 data bytes
    64 bytes from 172.217.3.174: seq=0 ttl=41 time=9.841 ms
    64 bytes from 172.217.3.174: seq=1 ttl=41 time=9.897 ms
    
    --- google.com ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 9.841/9.869/9.897 ms
    
  6. Теперь пытается пропинговать второй контейнер. Сначала пропингуйте его по IP-адресу 172.17.0.3:

    # ping -c 2 172.17.0.3
    
    PING 172.17.0.3 (172.17.0.3): 56 data bytes
    64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.086 ms
    64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.094 ms
    
    --- 172.17.0.3 ping statistics ---
    2 packets transmitted, 2 packets received, 0% packet loss
    round-trip min/avg/max = 0.086/0.090/0.094 ms
    

    Это удается. Затем пытается пропинговать контейнер alpine2 по имени контейнера. Это не удастся.

    # ping -c 2 alpine2
    
    ping: bad address 'alpine2'
    
  7. Отсоедините alpine1, не останавливая его, используя последовательность отсоединения CTRL + p CTRL + q (удерживая CTRL, входит p, а затем q). Если хотите, присоединитесь к alpine2 и повторяет шаги 4, 5 и 6, заменив alpine1 на alpine2.

  8. Останавливает и удаляет оба контейнера.

    $ docker container stop alpine1 alpine2
    $ docker container rm alpine1 alpine2
    

Помните, что сеть bridge по умолчанию не рекомендуется для производства. Чтобы узнать о пользовательских мостовых сетях, перейдите к следующий учебник.

Другие сетевые учебники

Теперь, когда вы завершили работу с сетевыми руководствами для оверлейных сетей, вы можете просмотреть данные другие сетевые руководства: