Сети Docker: базовая настройка связи между контейнерами

Практическая работа с сетями Docker: создание пользовательской сети, подключение контейнеров, DNS по имени сервиса и использование в Docker Compose.

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

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

Проверено на: Ubuntu Server 24.04 LTS и Docker Engine
Уровень сложности: начальный
Время выполнения: около 15 минут
Требуемый доступ: пользователь с доступом к Docker

Что будет рассмотрено

После выполнения инструкции можно будет:

  • просматривать существующие сети;
  • создавать пользовательские bridge-сети;
  • подключать к ним контейнеры;
  • обращаться к контейнерам по имени;
  • публиковать порты на хосте;
  • описывать сети в Docker Compose;
  • разделять сервисы по нескольким сетям;
  • удалять неиспользуемые сети.

Просмотр существующих сетей

docker network ls

Обычно Docker создаёт стандартные сети:

bridge
host
none

Подробная информация о сети:

docker network inspect bridge

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

Создайте сеть:

docker network create app-network

Проверьте:

docker network ls

Посмотрите параметры:

docker network inspect app-network

По умолчанию будет создана сеть с драйвером bridge.

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

Запустите Nginx:

docker run -d \
  --name web \
  --network app-network \
  nginx:alpine

Проверьте контейнер:

docker ps

Посмотрите его сетевые параметры:

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

Проверка связи по имени контейнера

Запустите временный контейнер в той же сети:

docker run --rm \
  --network app-network \
  busybox \
  ping -c 3 web

Контейнер web доступен по собственному имени благодаря встроенному DNS Docker.

Проверьте DNS-разрешение:

docker run --rm \
  --network app-network \
  busybox \
  nslookup web

Проверка HTTP:

docker run --rm \
  --network app-network \
  alpine \
  sh -c 'apk add --no-cache curl >/dev/null && curl -I http://web'

Ожидаемый ответ:

HTTP/1.1 200 OK

Почему не нужен фиксированный IP

IP-адрес контейнера может измениться после пересоздания.

Проверить текущий IP:

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

Для связи между контейнерами используйте DNS-имя:

http://web

а не фиксированный IP-адрес.

Просмотр участников сети

docker network inspect app-network

В разделе Containers отображаются подключённые контейнеры.

Краткий вывод:

docker network inspect app-network \
  --format '{{json .Containers}}'

Публикация порта на хосте

Связь внутри сети не требует публикации порта. Чтобы открыть Nginx на хосте, контейнер нужно пересоздать с параметром -p.

Удалите тестовый контейнер:

docker rm -f web

Запустите снова:

docker run -d \
  --name web \
  --network app-network \
  -p 8080:80 \
  nginx:alpine

Проверьте с хоста:

curl -I http://127.0.0.1:8080

Параметр:

8080:80

означает:

порт 8080 хоста → порт 80 контейнера

Внутренняя и внешняя доступность

Без секции публикации портов:

  • сервис доступен другим контейнерам в той же сети;
  • сервис не публикуется на интерфейсы хоста.

С опубликованным портом:

  • сервис доступен через порт хоста;
  • внешний доступ дополнительно зависит от firewall и сетевых правил.

Базы данных и внутренние API не следует публиковать наружу без необходимости.

Подключение работающего контейнера

Создайте контейнер без нужной сети:

docker run -d \
  --name client \
  alpine \
  sh -c 'while true; do sleep 3600; done'

Подключите его:

docker network connect app-network client

Проверьте:

docker inspect \
  --format '{{json .NetworkSettings.Networks}}' \
  client

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

docker network disconnect app-network client

Проверьте список участников:

docker network inspect app-network

Добавление сетевого alias

Подключите контейнер с дополнительным DNS-именем:

docker network connect \
  --alias frontend \
  app-network \
  client

Проверьте alias:

docker run --rm \
  --network app-network \
  busybox \
  nslookup frontend

Использование сети в Docker Compose

Создайте каталог проекта:

mkdir -p ~/docker-network-example
cd ~/docker-network-example

Создайте файл compose.yaml:

cat >compose.yaml <<'EOF'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    networks:
      - frontend

  client:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    networks:
      - frontend

networks:
  frontend:
    driver: bridge
EOF

Проверьте конфигурацию:

docker compose config

Запустите:

docker compose up -d

Проверьте:

docker compose ps

Проверка связи в Compose

Сервис доступен по имени, указанному в services.

Проверьте:

docker compose exec client \
  ping -c 3 web

Проверка HTTP:

docker compose exec client \
  wget -S -O /dev/null http://web

Адрес сервиса внутри сети:

http://web

Публиковать порт web для доступа из client не требуется.

Автоматическая сеть Compose

Если явно не указывать networks, Docker Compose создаст для проекта общую сеть по умолчанию.

Пример:

services:
  web:
    image: nginx:alpine

  client:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done

Оба сервиса будут подключены к одной сети проекта и смогут обращаться друг к другу по именам web и client.

Разделение сервисов по сетям

Пример с отдельными frontend- и backend-сетями:

services:
  proxy:
    image: nginx:alpine
    networks:
      - frontend
      - backend

  app:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    networks:
      - backend

  db:
    image: postgres:alpine
    environment:
      POSTGRES_PASSWORD: CHANGE_ME
    networks:
      - backend

networks:
  frontend:
  backend:

В такой схеме:

  • proxy подключён к двум сетям;
  • app и db доступны только в backend-сети;
  • база данных не подключена к frontend-сети.

Это ограничивает ненужную сетевую доступность.

Внешняя сеть Compose

Создайте сеть вручную:

docker network create shared-network

Добавьте в compose.yaml:

services:
  app:
    image: alpine
    command:
      - sh
      - -c
      - while true; do sleep 3600; done
    networks:
      - shared

networks:
  shared:
    external: true
    name: shared-network

Compose будет использовать существующую сеть и не удалит её при выполнении:

docker compose down

Фиксированное имя сети

По умолчанию Compose добавляет к имени сети префикс проекта.

Чтобы задать точное имя:

networks:
  frontend:
    name: app-frontend

После запуска сеть будет называться:

app-frontend

Проверка опубликованных портов

Для конкретного контейнера:

docker port web

Для всех контейнеров:

docker ps \
  --format 'table {{.Names}}\t{{.Ports}}'

Проверка прослушиваемого порта на хосте:

sudo ss -lntup | grep ':8080'

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

Сначала удалите подключённые контейнеры:

docker rm -f web client

Удалите сеть:

docker network rm app-network

Если сеть используется, Docker не позволит её удалить.

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

cd ~/docker-network-example
docker compose down

Compose удалит созданные контейнеры и сеть проекта.

Внешние сети останутся.

Поиск неиспользуемых сетей

docker network ls \
  --filter dangling=true

Очистка неиспользуемых сетей

docker network prune

Без подтверждения:

docker network prune -f

Команда удаляет сети, не используемые контейнерами.

Типичные проблемы

Контейнер не разрешается по имени

Проверьте, что оба контейнера подключены к одной пользовательской сети:

docker network inspect NETWORK_NAME

Проверьте сети контейнера:

docker inspect \
  --format '{{json .NetworkSettings.Networks}}' \
  CONTAINER_NAME

Связь по IP работает, а по имени — нет

Убедитесь, что используется пользовательская сеть, а не только стандартная bridge.

Создайте отдельную сеть и подключите к ней оба контейнера.

Порт не открывается на хосте

Проверьте публикацию:

docker port CONTAINER_NAME

Проверьте локальный ответ:

curl -I http://127.0.0.1:8080

Проверьте прослушиваемые порты:

sudo ss -lntup | grep ':8080'

Сервис доступен из контейнера, но не извне

Проверьте:

  • секцию ports;
  • локальный firewall;
  • правила Docker;
  • адрес привязки;
  • сетевые ограничения провайдера.

Compose создал сеть с неожиданным именем

Посмотрите список:

docker network ls

При необходимости задайте параметр:

name: app-network

Быстрый набор команд

Создать сеть:

docker network create NETWORK_NAME

Посмотреть сети:

docker network ls

Проверить сеть:

docker network inspect NETWORK_NAME

Подключить контейнер:

docker network connect NETWORK_NAME CONTAINER_NAME

Отключить контейнер:

docker network disconnect NETWORK_NAME CONTAINER_NAME

Удалить сеть:

docker network rm NETWORK_NAME

Итог

После выполнения инструкции:

  • создана пользовательская Docker-сеть;
  • контейнеры подключены к общей сети;
  • проверена связь по DNS-именам;
  • опубликован порт на хосте;
  • сеть описана в Docker Compose;
  • рассмотрено разделение сервисов по нескольким сетям;
  • показано безопасное удаление сетей.

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

← Предыдущая статья Тома Docker: постоянное хранение данных контейнеров Следующая статья → Переменные окружения в Docker Compose