Skip to content

Основы Docker: Сети (Networking)

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

Типы сетей Docker

Docker предоставляет несколько встроенных сетевых драйверов:

  • bridge (default): Это сетевой драйвер по умолчанию. Когда Docker устанавливается, он создает сетевой мост с именем docker0. По умолчанию все контейнеры подключаются к этой сети. Контейнеры в одной bridge-сети могут взаимодействовать друг с другом по IP-адресам. Для доступа к портам контейнера извне (с хост-машины или из внешней сети) необходимо выполнить публикацию портов.

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

  • none: Контейнеры, подключенные к сети none, полностью изолированы от внешней сети и других контейнеров. У них есть только интерфейс loopback (lo).

  • macvlan: Позволяет назначать MAC-адреса контейнерам, что делает их видимыми в физической сети как отдельные устройства.

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

  • ipvlan: Похож на macvlan, но работает на уровне IP и MAC-адресов Ethernet link.

  • Пользовательские сети (User-defined networks): Вы можете создавать собственные сети типа bridge, overlay и macvlan. Пользовательские сети bridge обеспечивают лучшую изоляцию и взаимодействие между контейнерами по имени (DNS-разрешение имен контейнеров внутри сети).

Управление сетями Docker

Вы можете управлять сетями Docker с помощью команды docker network.

Просмотр доступных сетей

bash
docker network ls

Эта команда выведет список всех доступных сетей, их ID, имен, драйверов и областей действия.

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

Вы можете создать собственную сеть с определенным драйвером (по умолчанию bridge):

bash
docker network create my-custom-network
docker network create -d bridge another-bridge-network
docker network create -d overlay my-overlay-network # Требуется Docker Swarm

Подключение контейнера к сети

При создании контейнера вы можете указать, к какой сети его подключить с помощью флага --network:

bash
docker run --name my-container --network my-custom-network my-image

Вы также можете подключить уже запущенный контейнер к сети (или отключить его от сети):

bash
docker network connect my-custom-network my-container
docker network disconnect my-custom-network my-container

Просмотр информации о сети

Чтобы получить подробную информацию о конкретной сети, используйте команду docker network inspect:

bash
docker network inspect my-custom-network

Эта команда выведет JSON-объект с информацией о сети, включая ее конфигурацию, подключенные контейнеры и IP-адреса.

Удаление сети

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

bash
docker network rm my-custom-network

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

Контейнеры, находящиеся в одной сети (кроме none и host), могут взаимодействовать друг с другом.

В сети bridge по умолчанию (docker0)

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

В пользовательских сетях bridge

В пользовательских сетях bridge, Docker предоставляет автоматическое DNS-разрешение имен контейнеров. Это означает, что контейнеры могут взаимодействовать друг с другом, используя имена своих контейнеров в качестве хост-имен.

Например, если у вас есть два контейнера с именами web и db в одной пользовательской сети my-network, контейнер web может обращаться к сервису, работающему на контейнере db, используя хост-имя db (и соответствующий порт).

Публикация портов (-p или ports в Docker Compose)

Чтобы сделать сервис, работающий внутри контейнера, доступным с хост-машины или из внешней сети, необходимо опубликовать порты контейнера на порты хост-машины. Это делается с помощью флага -p при запуске контейнера (docker run -p host_port:container_port) или с помощью секции ports в файле docker-compose.yml.

bash
docker run -p 8080:80 nginx # Порт 80 контейнера будет доступен на порту 8080 хоста

В docker-compose.yml:

yaml
version: "3.9"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80" # Порт 80 контейнера будет доступен на порту 80 хоста

Примеры сетевого взаимодействия

Веб-приложение и база данных в одной пользовательской сети

Предположим, у вас есть веб-приложение (работающее в контейнере web) и база данных MySQL (работающая в контейнере db), и вы создали пользовательскую сеть my-app-network.

  1. Создайте сеть: docker network create my-app-network
  2. Запустите контейнер базы данных, подключив его к сети:
    bash
    docker run --name db --network my-app-network -e MYSQL_ROOT_PASSWORD=secret -d mysql:latest
  3. Запустите контейнер веб-приложения, подключив его к той же сети:
    bash
    docker run --name web --network my-app-network -p 80:80 -d my-web-app-image

Теперь контейнер web может обращаться к базе данных MySQL, используя хост-имя db и порт MySQL (обычно 3306), без необходимости знать IP-адрес контейнера db. Веб-приложение также доступно на порту 80 хост-машины.

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

Если контейнеры находятся в разных сетях или вы хотите получить доступ к сервису контейнера с хост-машины, вы можете использовать опубликованные порты. В этом случае вы будете использовать IP-адрес хост-машины (или localhost, если обращаетесь с той же машины) и опубликованный порт.

Например, если вы запустили контейнер MySQL с публикацией порта -p 3306:3306, вы можете подключиться к нему с хост-машины, используя localhost:3306.

Docker Compose и сети

Docker Compose упрощает управление сетями для многоконтейнерных приложений. По умолчанию Compose создает одну сеть для вашего приложения. Все службы, определенные в одном файле docker-compose.yml, автоматически подключаются к этой сети и могут взаимодействовать друг с другом по именам служб (которые используются как хост-имена).

Вы также можете определять собственные сети в секции networks файла docker-compose.yml и подключать к ним определенные службы.

yaml
version: "3.9"
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    networks:
      - frontend
      - backend
    depends_on:
      - app

  app:
    build: ./app
    networks:
      - backend
    environment:
      DB_HOST: db

  db:
    image: mysql:8.0
    networks:
      - backend
    environment:
      MYSQL_ROOT_PASSWORD: secret

networks:
  frontend:
  backend:

В этом примере созданы две сети: frontend и backend. Служба web подключена к обеим сетям, служба app и db — только к backend. Это позволяет изолировать сетевой трафик между различными частями приложения. Веб-сервер может взаимодействовать с приложением, а приложение — с базой данных, но прямой доступ к базе данных извне (через сеть frontend) отсутствует.

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