Основы сетевого взаимодействия в Docker

DockerDockerBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/NetworkOperationsGroup(["Network Operations"]) linux(("Linux")) -.-> linux/RemoteAccessandNetworkingGroup(["Remote Access and Networking"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/ContainerOperationsGroup -.-> docker/inspect("Inspect Container") docker/ContainerOperationsGroup -.-> docker/port("List Container Ports") docker/NetworkOperationsGroup -.-> docker/network("Manage Networks") linux/RemoteAccessandNetworkingGroup -.-> linux/ip("IP Managing") subgraph Lab Skills docker/run -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} docker/exec -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} docker/inspect -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} docker/port -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} docker/network -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} linux/ip -.-> lab-389048{{"Основы сетевого взаимодействия в Docker"}} end

Понимание типов сетей Docker

Docker предоставляет несколько встроенных сетевых драйверов. Начнем с рассмотрения сетей по умолчанию в вашей системе.

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

docker network ls

Эта команда выводит список всех сетей, созданных Docker в вашей системе. Вы должны увидеть вывод, похожий на следующий:

NETWORK ID     NAME      DRIVER    SCOPE
79dce413aafd   bridge    bridge    local
91199fc6ad2e   host      host      local
1078d2c781b6   none      null      local

Разберем типы сетей по умолчанию:

  1. bridge: Это драйвер сети по умолчанию. Когда вы запускаете контейнер без указания сети, он автоматически подключается к сети bridge. Контейнеры в одной и той же сети bridge могут общаться между собой по своим IP-адресам.

  2. host: Этот драйвер удаляет сетевое изоляцию между контейнером и хостом Docker. Контейнер использует пространство имен сети хоста, то есть напрямую использует IP-адрес и порт хоста. Это может быть полезно для оптимизации производительности в определенных сценариях.

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

Столбец SCOPE показывает, ограничена ли сеть одним хостом (local) или может охватывать несколько хостов в кластере Docker (swarm).

Проверка сети bridge по умолчанию

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

Выполните следующую команду, чтобы проверить сеть bridge:

docker network inspect bridge

Эта команда предоставляет подробную информацию о сети bridge, включая ее подсеть, шлюз и подключенные контейнеры. Вы увидите вывод, похожий на следующий (для краткости сокращен):

[
  {
    "Name": "bridge",
    "Id": "79dce413aafdd7934fa3c1d0cc97decb823891ce406442b7d51be6126ef06a5e",
    "Created": "2024-08-22T09:58:39.747333789+08:00",
    "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,
    "Ingress": false,
    "ConfigFrom": {
      "Network": ""
    },
    "ConfigOnly": false,
    "Containers": {},
    "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": {}
  }
]

Разберем основную информацию из этого вывода:

  • Subnet: Подсеть, используемая контейнерами в этой сети, - 172.17.0.0/16. Это означает, что контейнерам будут присвоены IP-адреса в этом диапазоне.
  • Gateway: Шлюз для этой сети - 172.17.0.1. Это IP-адрес, который контейнеры используют для связи с сетями вне своей подсети.
  • Containers: Это поле пустое, потому что мы еще не запустили ни одного контейнера.
  • Options: Это различные параметры конфигурации сети bridge. Например, enable_icc, установленный в "true", означает, что между контейнерами в этой сети разрешено общение.

Понимание этой информации является важным при устранении сетевых проблем или при настройке контейнеров для взаимодействия с определенными диапазонами IP-адресов.

Создание пользовательской сети bridge

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

Создадим пользовательскую сеть bridge с именем my-network:

docker network create --driver bridge my-network

Эта команда создает новую сеть bridge. Опция --driver bridge здесь на самом деле необязательна, так как bridge - это драйвер по умолчанию, но она добавлена для ясности.

Теперь проверим, что наша новая сеть была создана:

docker network ls

Вы должны увидеть my-network в списке сетей:

NETWORK ID     NAME         DRIVER    SCOPE
1191cb61c989   bridge       bridge    local
91199fc6ad2e   host         host      local
47ac4e684a72   my-network   bridge    local
1078d2c781b6   none         null      local

Наша новая сеть my-network появилась в списке, что подтверждает ее успешное создание. Теперь эта сеть доступна для подключения контейнеров.

Подключение контейнеров к сетям

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

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

docker run -d --name container1 --network my-network nginx
docker run -d --name container2 --network my-network nginx

Разберем эти команды:

  • -d: Этот флаг запускает контейнер в отсоединенном режиме, то есть он работает в фоновом режиме.
  • --name: Этот параметр присваивает имя нашему контейнеру, что упрощает его дальнейшее обращение.
  • --network: Этот параметр указывает, к какой сети должен подключиться контейнер.
  • nginx: Это имя образа, который мы используем для создания наших контейнеров.

Эти команды создают два отсоединенных (-d) контейнера с именами container1 и container2, оба подключенных к нашей сети my-network.

Проверим, что контейнеры запущены и подключены к нашей сети:

docker ps

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

CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS     NAMES
1234567890ab   nginx     "/docker-entrypoint.…"   10 seconds ago   Up 9 seconds    80/tcp    container2
abcdef123456   nginx     "/docker-entrypoint.…"   20 seconds ago   Up 19 seconds   80/tcp    container1

Этот вывод показывает, что оба контейнера используют образ Nginx и экспонируют порт 80 внутри контейнера.

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

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

Протестируем это, отправив запрос от container1 к container2:

docker exec container1 curl -s container2

Разберем эту команду:

  • docker exec: Эта команда сообщает Docker выполнить команду внутри запущенного контейнера.
  • container1: Это имя контейнера, в котором мы хотим выполнить команду.
  • curl -s container2: Это команда, которую мы выполняем внутри контейнера. Она отправляет GET-запрос к container2, а флаг -s заставляет curl работать в тихом режиме.

Эта команда выполняет команду curl внутри container1, отправляя запрос к container2. В выводе вы должны увидеть HTML-код страницы приветствия по умолчанию Nginx:

<!doctype html>
<html>
  <head>
    <title>Welcome to nginx!</title>
    <style>
      html {
        color-scheme: light dark;
      }
      body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
      }
    </style>
  </head>
  <body>
    <h1>Welcome to nginx!</h1>
    <p>
      If you see this page, the nginx web server is successfully installed and
      working. Further configuration is required.
    </p>

    <p>
      For online documentation and support please refer to
      <a href="http://nginx.org/">nginx.org</a>.<br />
      Commercial support is available at
      <a href="http://nginx.com/">nginx.com</a>.
    </p>

    <p><em>Thank you for using nginx.</em></p>
  </body>
</html>

Успешный ответ показывает, что container1 может общаться с container2 с использованием его имени контейнера. Встроенный DNS-сервер Docker преобразует имя контейнера в его IP-адрес в рамках сети.

Открытие портов контейнера

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

Создадим новый контейнер с открытым портом:

docker run -d --name exposed-container -p 8080:80 --network my-network nginx

Разберем эту команду:

  • -d: Запустить контейнер в отсоединенном режиме.
  • --name exposed-container: Назвать контейнер "exposed-container".
  • -p 8080:80: Отобразить порт 80 внутри контейнера на порт 8080 на хосте.
  • --network my-network: Подключить контейнер к нашей пользовательской сети.
  • nginx: Использовать образ Nginx.

Эта команда создает новый контейнер с именем exposed-container, отображает порт 80 контейнера на порт 8080 хоста и подключает его к нашей сети my-network.

Теперь вы можете получить доступ к серверу Nginx этого контейнера с вашего хост-компьютера, открыв веб-браузер и перейдя по адресу http://localhost:8080, или используя curl:

curl localhost:8080

Вы должны увидеть ту же HTML-страницу приветствия Nginx, как и раньше. Однако на этот раз мы получаем доступ к контейнеру напрямую с хоста, а не из другого контейнера.

Использование сетевого стека хоста

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

Создадим контейнер, используя сеть хоста:

docker run -d --name host-networked --network host nginx

Эта команда создает новый контейнер с именем host-networked, используя сеть хоста. Обратите внимание, что вы не можете использовать -p при использовании сети хоста, так как контейнер уже использует сетевые интерфейсы хоста.

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

docker inspect --format '{{.HostConfig.NetworkMode}}' host-networked

Эта команда проверяет контейнер и форматирует вывод так, чтобы показать только NetworkMode. Она должна вывести host, подтверждая, что контейнер использует сеть хоста.

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

Итоги

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

Мы научились:

  • Выводить список и проверять настройки сетей Docker
  • Создавать пользовательские мостовые сети (custom bridge networks)
  • Подключать контейнеры к сетям
  • Тестировать взаимодействие между контейнерами
  • Открывать порты контейнеров для доступа с хоста
  • Использовать сетевой стек хоста для контейнеров

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

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