前言
在使用 Docker Compose 部署微服务架构时,发现部分服务无法通过容器名称解析其他服务,导致服务启动失败并进入重启循环。
问题现象
初始错误
启动 Docker Compose 时,出现以下错误:
bash
docker compose --env-file .env --env-file .env.image.amd64 up -d
✘ Container elastic-wanwu Error dependency es failed to start
服务重启循环
多个服务出现重启循环,日志显示 DNS 解析失败:
json
{"level":"FATAL","ts":"2026-01-06T07:12:05.681Z","caller":"assistant-service/main.go:56","msg":"init redis err: dial tcp: lookup redis-wanwu: i/o timeout"}
{"level":"FATAL","ts":"2026-01-06T07:11:36.091Z","caller":"iam-service/main.go:58","msg":"init redis err: dial tcp: lookup redis-wanwu: i/o timeout"}
问题排查过程
1. 首先解决 Elasticsearch 启动问题
Elasticsearch 容器日志显示:
bootstrap check failure [1] of [1]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
解决方案:
bash
# 永久修复
echo 'vm.max_map_count=262144' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
2. 网络连接状态检查
检查 Docker 网络配置:
bash
docker network ls | grep wanwu
docker network inspect wanwu-net
发现网络配置正常,所有容器都正确连接到 wanwu-net 网络并获得了 IP 地址。
3. DNS 解析测试
使用测试容器验证 DNS 解析:
bash
docker run --rm --network wanwu-net alpine:latest nslookup redis-wanwu
结果显示:
;; connection timed out; no servers could be reached
这表明问题出在 DNS 解析层面。
4. Docker 守护进程配置检查
检查 Docker 服务状态:
bash
sudo systemctl status docker
发现 Docker 守护进程配置了有问题的 DNS 设置:
--dns 10.233.0.3 --dns 127.0.0.53 --dns-search default.svc.cluster.local --dns-search svc.cluster.local
这些 Kubernetes 相关的 DNS 配置导致容器内的 DNS 解析失败。
根本原因分析
问题的根本原因是 Docker 守护进程配置了不当的 DNS 设置,这些设置来自于系统中的多个配置文件:
/etc/systemd/system/docker.service.d/docker-dns.conf/etc/systemd/system/docker.service.d/docker-options.conf/etc/systemd/system/docker.service.d/override.conf
这些配置文件中的 DNS 设置(特别是 Kubernetes 集群的 DNS)在非 Kubernetes 环境中无法正常工作,导致容器内的 DNS 解析完全失败。
解决方案
方案一:临时解决 - 使用 IP 地址
bash
# 获取 Redis 容器的 IP 地址
docker inspect redis-wanwu | grep IPAddress
# 修改环境变量,使用 IP 地址替代主机名
cp .env.bak .env.temp
sed -i 's/redis-wanwu/172.18.0.4/g' .env.temp
# 重启服务
docker compose --env-file .env.temp --env-file .env.image.amd64 restart bff-service iam-service assistant-service
方案二:根本解决 - 清理 Docker DNS 配置
- 查看现有配置文件:
bash
ls -la /etc/systemd/system/docker.service.d/
cat /etc/systemd/system/docker.service.d/docker-dns.conf
- 备份并禁用有问题的 DNS 配置:
bash
# 备份现有配置
sudo cp /etc/systemd/system/docker.service.d/docker-dns.conf /etc/systemd/system/docker.service.d/docker-dns.conf.bak
# 临时禁用 DNS 配置
sudo mv /etc/systemd/system/docker.service.d/docker-dns.conf /etc/systemd/system/docker.service.d/docker-dns.conf.disabled
- 重启 Docker 服务:
bash
sudo systemctl daemon-reload
sudo systemctl restart docker
- 重新启动应用服务:
bash
docker compose --env-file .env --env-file .env.image.amd64 up -d
验证解决方案
解决后,可以通过以下方式验证:
- 检查容器状态:
bash
docker ps
- 测试 DNS 解析:
bash
docker run --rm --network wanwu-net alpine:latest nslookup redis-wanwu
- 查看服务日志:
bash
docker logs assistant-service --tail 10
docker logs iam-service --tail 10
经验总结
问题诊断思路
- 分层排查:从基础设施(Elasticsearch)到网络层(DNS)逐步排查
- 日志分析:通过容器日志快速定位问题类型
- 网络测试:使用简单的测试容器验证网络连通性
- 配置检查:检查 Docker 守护进程的配置参数
预防措施
- 环境隔离:避免在非 Kubernetes 环境中使用 Kubernetes 相关的 DNS 配置
- 配置管理:定期检查和清理不必要的 Docker 配置文件
- 监控告警:建立容器健康检查和 DNS 解析监控
适用场景
这个解决方案适用于以下场景:
- Docker Compose 服务间无法通过容器名称互相访问
- 容器内 DNS 解析超时或失败
- 在混合环境(Kubernetes + Docker Compose)中出现的 DNS 冲突
通过彻底清理 Docker 的 DNS 配置,我们成功解决了服务间的网络通信问题,所有微服务都能正常启动并相互通信。