Сети и volumes в Docker

↑ Этап 2 · Контейнеры: Docker, docker-compose, Makefile

Обязательно~6 мин чтенияУровень: junior

Зачем это на собесе

Контейнерные сети и тома — обязательная часть вопросов: как контейнеры общаются и где хранятся данные.

Сетевые драйверы

ДрайверОписание
bridge (по умолчанию)виртуальный мост docker0/пользовательский: контейнеры в своей подсети, NAT наружу
hostконтейнер использует сетевой стек хоста (без изоляции и NAT; быстро; порты хоста)
noneбез сети
overlayсеть между хостами (Swarm)
macvlan / ipvlanконтейнер получает адрес во внешней L2-сети
docker network ls; docker network inspect bridge
docker network create --driver bridge --subnet 172.30.0.0/24 appnet
docker run -d --name api --network appnet myapi
docker network connect appnet existing_container

Пользовательский bridge и DNS

В пользовательской сети (не default bridge) работает встроенный DNS: контейнеры обращаются друг к другу по имени контейнера/сервиса (http://api:8080, postgres:5432), а не по IP. В compose все сервисы автоматически попадают в общую сеть проекта с именами = названия сервисов; алиасы: networks.<name>.aliases.

Изоляция: контейнеры в разных сетях не видят друг друга; сервис может входить в несколько сетей (например, frontend и backend, а БД только в backend).

services:
  nginx:   { networks: [public, internal] }
  api:     { networks: [internal] }
  db:      { networks: [internal] }
networks:
  public:
  internal: { internal: true }     # без доступа наружу

Публикация портов

docker run -p 8080:80 nginx                    # хост:контейнер на всех интерфейсах (0.0.0.0)
docker run -p 127.0.0.1:5432:5432 postgres     # только localhost (БД наружу не выставлять!)
docker run -P nginx                            # случайные порты для EXPOSE
docker port web
  • EXPOSE — документация, не публикация;
  • публикация реализована через iptables DNAT и docker-proxy; Docker обходит ufw (см. firewall);
  • связь контейнер→контейнер в одной сети не требует публикации портов.

Доступ контейнера к хосту: host.docker.internal (Docker Desktop; на Linux — --add-host=host.docker.internal:host-gateway).

Volumes и хранение данных

Файловая система контейнера эфемерна. Способы сохранить данные:

ТипПримерКогда
Named volume-v pgdata:/var/lib/postgresql/dataданные, управляемые Docker (/var/lib/docker/volumes): БД, файлы приложений
Bind mount-v $(pwd)/conf:/etc/app:roфайлы хоста: разработка, конфиги
tmpfs--tmpfs /tmpвременные данные в памяти (секреты, скорость)
docker volume create pgdata; docker volume ls; docker volume inspect pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:17
docker run --rm -v pgdata:/data -v $(pwd):/backup alpine tar czf /backup/pgdata.tgz -C /data .   # бэкап тома
docker volume prune
services:
  db:
    image: postgres:17
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init:/docker-entrypoint-initdb.d:ro
volumes:
  pgdata:

Named volume инициализируется содержимым образа при первом монтировании (если пуст), bind mount — нет (перекрывает каталог). Права: UID процесса в контейнере должен иметь доступ (chown, user: в compose, fsGroup в Kubernetes).

Драйверы томов: local, NFS (driver_opts), облачные, плагины. Производительность bind mount на macOS/Windows ниже (файловая виртуализация).

Данные и отказоустойчивость

  • тома не равны бэкапам: копируйте (pg_dump/снапшоты);
  • БД в контейнерах в проде: нужно осознанное хранение (PVC, локальные SSD, оператор) — часто управляемые БД;
  • не храните состояние в слое контейнера.

Диагностика

docker exec api getent hosts db          # DNS внутри сети
docker exec api nc -zv db 5432
docker network inspect appnet | jq '.[0].Containers'
docker inspect api | jq '.[0].NetworkSettings.Networks'
sudo nsenter -t $(docker inspect -f '{{.State.Pid}}' api) -n ss -tulpn
docker run --rm --network container:api nicolaka/netshoot    # сетевой toolbox в сети контейнера

Частые проблемы: localhost внутри контейнера — это сам контейнер (а не хост и не другой сервис); приложение слушает 127.0.0.1, а нужно 0.0.0.0; не в той сети; пересечение подсетей с VPN (default-address-pools в daemon.json); DNS (--dns), MTU за VPN.

Вопросы с ответами