Короткий ответ
В сети bridge по умолчанию (docker0) встроенный DNS Docker не резолвит имена контейнеров — обращаться можно только по IP; нужно создать пользовательскую bridge-сеть (docker network create) и подключить к ней оба контейнера, тогда Docker DNS начнёт резолвить имена.
Как это работает подробнее
сеть bridge по умолчанию существует для обратной совместимости и не включает встроенный DNS-сервер Docker (127.0.0.11), который резолвит имена контейнеров и сервисов. Пользовательские (user-defined) сети, созданные через docker network create, автоматически получают этот встроенный DNS, и каждый подключённый контейнер может обращаться к другим по их имени или заданному через --network-alias псевдониму.
Пример кода
Пример конфигурации
$ docker network create app-net
$ docker run -d --name db --network app-net postgres:16
$ docker run -it --rm --name api --network app-net alpine sh -c "nslookup db"
Name: db
Address 1: 172.19.0.2 dbЧто использовать на практике
- Практика. в большинстве реальных сценариев (включая docker-compose, который всегда создаёт пользовательскую сеть по умолчанию для проекта) контейнеры одного логического приложения нужно явно объединять в одну пользовательскую сеть. Диагностика начинается с проверки, в какой сети находится каждый контейнер (
docker inspect --format '{{.NetworkSettings.Networks}}'), и проверки DNS-резолва внутри контейнера.
Подводные камни
- Риск. пытаются использовать имя контейнера как hostname в default bridge сети и считают это багом Docker, не зная про ограничение встроенного DNS именно для сети по умолчанию; создают пользовательскую сеть, но забывают подключить к ней один из двух контейнеров (
docker network connect), из-за чего связь всё равно не работает.