#Что означает ошибка и при каких условиях возникает
Пошаговая диагностика DNS контейнеров Docker: сети, имена сервисов Compose, настройки resolv.conf и внешние DNS-серверы. В пользовательской bridge-сети Docker предоставляет встроенное разрешение имён контейнеров; типичная причина отказа — контейнеры находятся в разных сетях либо приложение обращается к неправильному имени.
#Как различить причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| Сервисы находятся в разных сетяхИмя сервиса разрешается для контейнеров в общей пользовательской сети, а не вообще для любых контейнеров в Docker. | docker network inspect показывает нужный контейнер только в одной сети. | Подключить оба сервиса к общей доверенной сети в конфигурации Compose. |
| Используется встроенная сеть bridge вместо пользовательскойКлассическая bridge-сеть не предоставляет такого же автоматического DNS по именам контейнеров. | В конфигурации написано network_mode: bridge, а обращение идёт по имени сервиса. | Использовать обычную сеть Compose или свою user-defined bridge. |
| Перепутали DNS и недоступность самого сервисаDNS может выдавать IP правильно, но служба не слушает нужный порт или не готова. | Python socket.getaddrinfo возвращает адрес, а подключение к TCP-порту не удаётся. | Проверять слушающий порт, приложение и правила сети отдельно. |
| Проблема только с внешними доменамиКонтейнер резолвит имена внутренних сервисов, но не имена в интернете. | Имя db определяется, внешний домен нет; внутренний DNS 127.0.0.11 виден в resolv.conf. | Разобраться с исходным DNS хоста, корпоративной сетью и прокси. |
#Пошаговая диагностика и исправление
- Откройте правильный Compose-проектНа Linux откройте терминал через меню приложений, на Windows — PowerShell, на macOS — «Терминал». Перейдите в каталог с compose.yaml и выполните
docker compose psиdocker compose config --services. Оба действия безопасны и показывают службы. Запишите имена клиента и сервера: в примере это client и db. Если Docker не запущен, откройте Docker Desktop либо обратитесь к администратору Engine. - Проверьте имя сервиса, а не localhostВ конфигурации приложения найдите адрес сервера БД. Внутри контейнера
localhostи127.0.0.1означают сам этот контейнер; для обращения к другому сервису Compose обычно нужно его имя, напримерdb. Откройте compose.yaml в текстовом редакторе и посмотрите ключи сразу подservices:. Если используется другое имя, исправлять нужно конфигурацию приложения, а не системный DNS. - Убедитесь, что оба контейнера подключены к одной сетиВыполните
docker network ls, затемdocker compose config; в результате найдите секцию networks и сетевые привязки служб. Для конкретной созданной сети используйтеdocker network inspect ИМЯ_СЕТИ, подставив существующее имя из списка. В разделе Containers должны быть обе нужные службы. Если нет, настройте общую сеть через compose.yaml после копии файла и проверки конфигурации; не присоединяйте случайные контейнеры к чужой сети. - Проверьте DNS внутри контейнера, не полагаясь на pingНе все минимальные образы содержат ping, nslookup и getent. В образе с Python выполните
docker compose exec client python -c "import socket; print(socket.getaddrinfo('db', 6379)[0][4][0])", заменив client и db именами своего тестового проекта и портом реального сервиса. В ответ ожидается адрес сети Docker;gaierrorозначает, что имя не разрешено. Для чужого образа сначала выясните доступные программы, не устанавливайте их на работающий контейнер ради одной проверки. - Посмотрите настроенный DNS без правок системных файловВ учебном Linux-контейнере выполните
docker compose exec client cat /etc/resolv.conf; в пользовательских сетях часто указанnameserver 127.0.0.11— это встроенный резолвер Docker и его не нужно заменять на публичный DNS. Если файл содержит другое значение, учитывайте настройки проекта и запуска, не редактируйте его вручную внутри контейнера: при пересоздании изменения исчезнут. - Отделите DNS от связи с портомКогда имя db успешно разрешилось, проверьте доступность самого сервиса отдельно; например, для Redis из контейнера, где есть redis-cli:
redis-cli -h db pingдолжен вернуть PONG. Если IP выдаётся, но PONG нет, изучайте порт 6379, логи db и готовность Redis. Не меняйте DNS в попытке починить остановленную базу. - Исправьте сеть в YAML после резервной копииСделайте копию compose.yaml, в редакторе свяжите обе службы с общей именованной сетью bridge как в примере ниже; не задавайте
network_mode: bridgeодновременно с networks. Выполнитеdocker compose config -q: успешная команда не выводит ошибок. На отдельном тестовом проекте выполнитеdocker compose up -d; на работающей системе согласуйте пересоздание, потому что оно влияет на подключения и доступность. - Проверьте устойчивость после пересозданияСнова получите IP по имени сервиса через socket.getaddrinfo и проверьте реальное подключение приложения. В учебном примере выполните
docker compose exec client python -c "import socket; print(socket.getaddrinfo('db', 6379)[0][4][0])"; при успехе вы увидите IP контейнера, который может измениться после пересоздания — клиент должен пользоваться именем, а не сохранённым IP. Если внешний DNS не работает при исправном внутреннем, передайте администратору параметры корпоративного DNS и хоста. - Команды для отдельных ситуацийВыберите только подходящий вариант. Это не одна последовательность: часть команд диагностирует проблему, а часть меняет настройки или данные.
#Минимальный пример для отдельного тестового проекта
docker compose up -d разрешение имени db из client выполняется встроенным DNS Docker. Не объявляет открытые порты наружу.services:
client:
image: python:3.12-alpine
command: ["sleep", "3600"]
networks: [private_net]
db:
image: redis:7-alpine
networks: [private_net]
networks:
private_net:
driver: bridge#Как проверить результат и что делать, если проблема осталась
Результат достигнут, когда getaddrinfo из нужного контейнера возвращает IP правильного сервиса, а соединение к его реальному порту успешно. Если DNS работает, но приложение нет — соберите данные о порте и журнале приложения; при ошибке внешних доменов проверьте доступность штатного DNS вашей сети.