«1. Обзор

Одной из основных функций Docker является создание и изоляция сетей.

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

2. Сеть в Docker

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

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

Каждый из них будет содержать простую HTTP-службу «Hello World»:

version: "3.5"

services:
  test1:
    image: node
    command: node -e "const http = require('http'); http.createServer((req, res) => { res.write('Hello from test1\n'); res.end() }).listen(8080)"
    ports:
      - "8080:8080"
    networks:
      - network1
  test2:
    image: node
    command: node -e "const http = require('http'); http.createServer((req, res) => { res.write('Hello from test2\n'); res.end() }).listen(8080)"
    ports:
      - "8081:8080"
    networks:
      - network1
      - network2
  test3:
    image: node
    command: node -e "const http = require('http'); http.createServer((req, res) => { res.write('Hello from test3\n'); res.end() }).listen(8080)"
    ports:
      - "8082:8080"
    networks:
      - network2

networks:
  network1:
    name: network1
  network2:
    name: network2

Вот схема этих контейнеров для более наглядного представления:

Давайте запустим их все с помощью команды docker-compose:

$ docker-compose up -d
Starting bael_test2_1 ... done
Starting bael_test3_1 ... done
Starting bael_test1_1 ... done

3. Проверка сети

Во-первых, давайте перечислим все доступные сети Docker:

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
86e6a8138c0d        bridge              bridge              local
73402de5766c        host                host                local
e943f7124776        network1            bridge              local
3b9a28673a16        network2            bridge              local
9361d16a834a        none                null                local

Мы можем увидеть мостовую сеть, которая используется по умолчанию, когда мы используем команду запуска docker. Кроме того, мы можем видеть сети, которые мы создали с помощью команды docker-compose.

Давайте проверим их с помощью команды docker inspect:

$ docker inspect network1 network2
[
    {
        "Name": "network1",
        "Id": "e943f7124776d45a1481ee26795b2dba3f2ab51f000d875a179a99ce832eee9f",
        "Created": "2020-08-22T10:38:22.198709146Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        // output cutout for brevity
    }
],
    {
        "Name": "network2",
        // output cutout for brevity
    }
}

Это даст длинный подробный вывод. Нам редко нужна вся эта информация. К счастью, мы можем отформатировать его с помощью шаблонов Go и извлечь только те элементы, которые нам нужны. Давайте получим только подсеть network1:

$ docker inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' network1
172.22.0.0/16

4. Инспекция контейнера

Точно так же мы можем инспектировать конкретный контейнер. Во-первых, давайте перечислим все контейнеры с их идентификаторами:

$ docker ps --format 'table {{.ID}}\t{{.Names}}'
CONTAINER ID        NAMES
78c10f03ad89        bael_test2_1
f229dde68f3b        bael_test3_1
b09a8f47e2a8        bael_test1_1

Теперь мы будем использовать идентификатор контейнера в качестве аргумента для команды проверки, чтобы найти его IP-адрес. Как и в случае с сетями, мы можем форматировать вывод, чтобы получить только ту информацию, которая нам нужна. Мы проверим второй контейнер и его адрес в обеих созданных нами сетях:

$ docker inspect 78c10f03ad89 --format '{{.NetworkSettings.Networks.network1.IPAddress}}'
172.22.0.2
$ docker inspect 78c10f03ad89 --format '{{.NetworkSettings.Networks.network2.IPAddress}}'
172.23.0.3

В качестве альтернативы мы можем вывести хосты непосредственно из контейнера с помощью команды docker exec:

$ docker exec 78c10f03ad89 cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.22.0.2	78c10f03ad89
172.23.0.3	78c10f03ad89

5. Связь между контейнерами ~ ~~ Используя знания о наших сетях Docker, мы можем установить связь между контейнерами в одной сети.

Во-первых, давайте перейдем внутрь контейнера «test1»:

Затем используйте curl для отправки запроса в контейнер «test2»:

$ docker exec -it b09a8f47e2a8 /bin/bash

Так как мы внутри контейнера Docker сети мы также можем использовать псевдоним вместо IP-адреса. Встроенная служба DNS Docker разрешит нам адрес:

[email protected]:/# curl 172.22.0.2:8080
Hello from test2

Помните, что мы не можем подключиться к контейнеру «test3», потому что он находится в другой сети. Время ожидания подключения по IP-адресу истекло:

[email protected]:/# curl test2:8080
Hello from test2

Подключение по псевдониму также не удастся, потому что служба DNS не распознает его:

[email protected]:/# curl 172.23.0.2:8080

Чтобы это работало, нам нужно добавить «test3». € контейнер к «network1» (из-за пределов контейнера):

[email protected]:/# curl test3:8080
curl: (6) Could not resolve host: test3

Теперь запрос к «test3» будет работать правильно:

$ docker network connect --alias test3 network1 f229dde68f3b

6. Заключение

[email protected]:/# curl test3:8080
Hello from test3

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

«