Сетевые контейнеры

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

Имя контейнера

Вы уже видели что каждый контейнер который вы создаете получает автоматически сгенерированное имя. Навярнека вы уже познакомились с контейнером nostalgic_morse в процессе изучения этого руководства. Также вы можете самостоятельно давать имена контейнерам. Именование предоставляет две полезные функции:

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

  • Имена дают Docker ориентир, который позволяет обращаться к контейнеру из других контейнеров. Есть несколько команд которые позволяют это делать. С одной из них мы познакомимся в этом примере.

Для задания имени контейнера используйте флаг --name, для примера создадим новый контейнер с именем web:

$ docker run -d -P --name web training/webapp python app.py

Выполните команду docker ps что бы проверить корректность присвоенного имени:

$ docker ps -l

CONTAINER ID  IMAGE                  COMMAND        CREATED       STATUS       PORTS                    NAMES
aed84ee21bde  training/webapp:latest python app.py  12 hours ago  Up 2 seconds 0.0.0.0:49154->5000/tcp  web

Также можно использовать команду docker inspect с именем контейнера.

$ docker inspect web

[
   {
       "Id": "3ce51710b34f5d6da95e0a340d32aa2e6cf64857fb8cdb2a6c38f7c56f448143",
       "Created": "2015-10-25T22:44:17.854367116Z",
       "Path": "python",
       "Args": [
           "app.py"
       ],
       "State": {
           "Status": "running",
           "Running": true,
           "Paused": false,
           "Restarting": false,
           "OOMKilled": false,
  ...

Имена контейнеров должны быть уникальными. Это значит что вы можете назвать только один контейнер именем web. Если вы хотите использовать то же самое имя для другого контейнера вы должны удалить предыдущий контейнер (командаdocker rm) перед тем как использовать имя повторно. Теперь давайте остановим и удалим контейнер web.

$ docker stop web

web

$ docker rm web

web

Запуск контейнера в сети

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

Каждая установка Docker Engine автоматически включает три сети по умолчанию. Вы можете посмотреть их список:

$ docker network ls

NETWORK ID          NAME                DRIVER
18a2866682b8        none                null                
c288470c46f6        host                host                
7b369448dccb        bridge              bridge  

Сеть с названием bridge является основной. Если вы не скажете ему иначе, Docker всегда запускает все контейнеры в этой сети. Проверьте сами:

$ docker run -itd --name=networktest ubuntu

74695c9cea6d9810718fddadc01a727a5dd3ce6a69d09752239736c030599741

Инспектирование сети самый простой способ узнать IP адрес контейнера.

$ docker network inspect bridge

[
    {
        "Name": "bridge",
        "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.1/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Containers": {
            "3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
                "EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
                "EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/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": "9001"
        }
    }
]

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

$ docker network disconnect bridge networktest

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

Создание собственной сети типа мост

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

$ docker network create -d bridge my-bridge-network

Флаг -d говорит Докер использовать сетевой драйвер моста (bridge). Вы можете и не включать этот флаг, поскольку bridge значение по умолчанию для данного флага. Давайте посмотрим список сетей на вашей машине:

$ docker network ls

NETWORK ID          NAME                DRIVER
7b369448dccb        bridge              bridge              
615d565d498c        my-bridge-network   bridge              
18a2866682b8        none                null                
c288470c46f6        host                host

Если вы осмотрите сеть, вы обнаружите, что внутри нет контейнеров.

$ docker network inspect my-bridge-network

[
    {
        "Name": "my-bridge-network",
        "Id": "5a8afc6364bccb199540e133e63adb76a557906dd9ff82b94183fc48c40857ac",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {}
    }
]

Добавление контейнеров в сеть

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

Запустим контейнер с базой данных PostgreSQL и используем флаг --network=my-bridge-network для подключения к новой сети:

$ docker run -d --network=my-bridge-network --name db training/postgres

Если вы проинспектируете сеть my-bridge-network то увидите что в ней есть прикрепленный контейнер. Вы так же можете проверить контейнер что бы увидеть куда он подключен:

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  db

{"my-bridge-network":{"NetworkID":"7d86d31b1478e7cca9ebed7e73aa0fdeec46c5ca29497431d3007d2d9e15ed99",
"EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.18.0.1","IPAddress":"172.18.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}

Теперь запустим уже знакомое нам веб-приложение. В этот раз мы не используем флаг -P а также не указываем сеть.

$ docker run -d --name web training/webapp python app.py

В какой сети работает наше веб-приложение web? Проверив контейнер вы увидите что он работает в сети bridge.

$ docker inspect --format='{{json .NetworkSettings.Networks}}'  web

{"bridge":{"NetworkID":"7ea29fc1412292a2d7bba362f9253545fecdfa8ce9a6e37dd10ba8bee7129812",
"EndpointID":"508b170d56b2ac9e4ef86694b0a76a22dd3df1983404f7321da5649645bf7043","Gateway":"172.17.0.1","IPAddress":"172.17.0.2","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:02"}}

Теперь, скопируйте IP адрес контейнера web

$ docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' web

172.17.0.2

Теперь подключимся к терминалу контейнера db:

$ docker exec -it db bash

root@a205f0dd33b2:/# ping 172.17.0.2
ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
^C
--- 172.17.0.2 ping statistics ---
44 packets transmitted, 0 received, 100% packet loss, time 43185ms

Нажмите CTRL-C что бы прервать ping, убедившись что пинг не проходит. Это происходит по тому что контейнеры работают в разных сетях. Давайте исправим это. Выполните команду exit что бы выйти из контейнера.

Docker позволяет подключать контейнеры к любому количеству сетей. Также возможно подключить и уже запущенный контейнер. Давайте подключим наш контейнер web к сети my-bridge-network.

$ docker network connect my-bridge-network web

Снова откройте терминал приложения db и попробуйте сделать пинг. Но в этот раз используйте имя контейнера web вместо IP адреса.

$ docker exec -it db bash

root@a205f0dd33b2:/# ping web
PING web (172.18.0.3) 56(84) bytes of data.
64 bytes from web (172.18.0.3): icmp_seq=1 ttl=64 time=0.095 ms
64 bytes from web (172.18.0.3): icmp_seq=2 ttl=64 time=0.060 ms
64 bytes from web (172.18.0.3): icmp_seq=3 ttl=64 time=0.066 ms
^C
--- web ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.060/0.073/0.095/0.018 ms

Команда ping покажет другой IP адрес, это происходит по тому что адрес в сети my-bridge-network отличается от адреса сети bridge.

Следующий шаг

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

Перевод абзаца

Оригинал:


Комментарии:

Комментариев нет, желаете стать первым?

Пожалуйста, авторизуйтесь что бы оставлять комментарии.