如何解决Docker DNS解析问题?无法通过主机名连接PostgreSQL
问题:Docker容器间DNS解析失败及外部工具无法通过容器名连接数据库
1. Docker Compose环境下的问题
我的docker-compose.yml配置如下:
version: '3.8' services: postgres: image: postgres:14-alpine ports: - '5432:5432' volumes: - ~/apps/postgres:/var/lib/postgresql/data env_file: - .env main: container_name: tm_main build: context: . env_file: - .env volumes: - .:/app - /app/node_modules ports: - '3000:3000' command: npm run start:dev depends_on: - postgres restart: always volumes: pgdata:
.env文件内容:
PORT=3000 DATABASE_HOST=postgres DATABASE_USER=user DATABASE_PASSWORD=root DATABASE_NAME=docker_problem_db DATABASE_PORT=5432 JWT_REFRESH_SECRET="refreshVeryHardSecret" JWT_REFRESH_EXPIRE=86000
运行时出现错误getaddrinfo ENOTFOUND postgres,用Beekeeper Studio连接时,用postgres作为主机名会报错,换成localhost就能正常连接。我希望通过主机名实现连接,试过很多DNS相关方法都没解决。
2. 单独PostgreSQL容器的问题
执行以下命令启动单独容器:
docker run --name acid -d -e POSTGRES_PASSWORD=postgres postgres:13
用以下凭据通过Beekeeper连接失败:
hostname=acid user=postgres password=postgres
但执行docker exec -it acid psql -U postgres可以正常连接。
3. 相关网络信息
docker inspect返回的acid容器网络信息:
"Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "0166c61f6a5aea83490fc8c598af04e55df71f9009e336684542f922b4c042cd", "EndpointID": "8c11cc65305666dee3786ad23453b981230adc2bd654aee4b8312fe5f54c074b", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } }
当前Docker网络列表:
NETWORK ID NAME DRIVER SCOPE 0166c61f6a5a bridge bridge local 491c2f61e8d2 host host local 33ac66fb767c mynetwork bridge local 8233fba80fe2 nest-backend_default bridge local 6cc450ff3353 none null local
解决方案
针对Docker Compose的容器间连接问题
- 确保服务在同一自定义网络
Docker Compose默认会创建项目名前缀的网络,但显式指定网络更稳妥。修改docker-compose.yml,添加自定义网络并让两个服务加入:version: '3.8' networks: app-network: driver: bridge services: postgres: image: postgres:14-alpine ports: - '5432:5432' volumes: - ~/apps/postgres:/var/lib/postgresql/data env_file: - .env networks: - app-network main: container_name: tm_main build: context: . env_file: - .env volumes: - .:/app - /app/node_modules ports: - '3000:3000' command: npm run start:dev depends_on: - postgres restart: always networks: - app-network volumes: pgdata: - 验证postgres容器是否就绪
depends_on只保证启动顺序,不保证数据库初始化完成。用docker-compose logs postgres查看日志,确认出现database system is ready to accept connections后再启动main服务。或者在main服务中加入健康检查脚本(比如wait-for-it.sh)延迟启动。 - 测试容器间DNS解析
进入main容器执行nslookup postgres,如果能返回postgres的IP,说明DNS正常;如果不行,检查网络是否正确关联。
针对外部工具通过容器名连接的问题
Docker默认的bridge网络不支持宿主机直接解析容器名,外部工具(比如Beekeeper)运行在宿主机,无法直接用postgres或acid作为主机名连接,解决方法:
- 使用宿主机IP+端口访问
保持端口映射(比如5432:5432),外部工具用localhost:5432或宿主机IP连接,这是最稳定的方式。 - 手动修改宿主机hosts文件
找到容器的IP(比如172.17.0.2),在宿主机hosts文件中添加172.17.0.2 postgres,但容器重启后IP可能变化,需要重新修改。 - 使用host网络模式
启动容器时添加--network host参数,容器直接使用宿主机网络,外部工具可以用localhost连接,但会失去容器的网络隔离性,不推荐生产环境使用。
单独acid容器连接失败的问题
这个容器在默认bridge网络中,外部工具无法解析acid主机名。先添加端口映射重新启动:
docker stop acid && docker rm acid docker run --name acid -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres postgres:13
然后用localhost:5432连接即可,或者用容器IP连接。
内容的提问来源于stack exchange,提问作者Shaxa Nematov
相关产品推荐
相关产品推荐

