1. 问题现象与初步诊断
当你进入Docker容器执行ping google.com时看到"Temporary failure in name resolution"错误,但ping 8.8.8.8却能正常通信,这就像你的手机能拨通电话号码却无法通过联系人名字拨打——问题出在域名解析环节。这种情况通常表明容器内的DNS配置出现了问题。
我遇到过最典型的场景是:开发环境突然无法拉取镜像,CI/CD流水线报错,或者微服务之间突然无法通过服务名通信。先别急着改配置,让我们用以下命令做个快速诊断:
# 检查容器内DNS配置 docker exec -it 容器名 cat /etc/resolv.conf # 测试基础网络连通性 docker exec -it 容器名 ping -c 4 114.114.114.114 # 检查域名解析 docker exec -it 容器名 nslookup google.com如果第一个命令返回空值或异常的DNS服务器地址,第二个能通但第三个失败,那就确认是DNS问题。这里有个容易忽略的细节:不同Docker网络模式下的/etc/resolv.conf生成机制完全不同,我们会在第三章详细展开。
2. 主机层网络检查
2.1 IP转发与防火墙配置
就像快递中转站必须允许包裹转发一样,Linux主机需要开启IP转发功能。我曾在CentOS环境遇到因为ip_forward未开启导致容器网络异常的案例:
# 检查ip_forward状态 cat /proc/sys/net/ipv4/ip_forward # 返回1表示已开启 # 若返回0,需要永久启用 echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf sysctl -p防火墙配置更是常见坑点。某次生产环境故障就是因为firewalld的masquerade未开启:
# Firewalld检查 firewall-cmd --query-masquerade # 返回yes表示正常 # 若返回no,需要执行 firewall-cmd --add-masquerade --permanent firewall-cmd --reload # UFW防火墙需放行DNS端口 ufw allow 53/udp ufw allow 53/tcp2.2 宿主DNS服务状态
主机自身的DNS解析异常会直接影响到容器。曾经有台Ubuntu服务器因为systemd-resolved服务崩溃导致所有容器解析失败:
# 检查systemd-resolved状态 systemctl status systemd-resolved # 检查DNS缓存服务 nscd -g | grep "hosts cache" dnsmasq --test建议同时检查/etc/resolv.conf内容是否合理。我见过有人误删这个文件导致整个系统DNS瘫痪的案例。正常应该包含有效的nameserver记录,比如:
nameserver 8.8.8.8 nameserver 114.114.114.1143. Docker网络模式深度解析
3.1 桥接模式下的DNS机制
默认的bridge网络模式下,Docker会通过内置的DNS服务器(127.0.0.11)处理容器请求。这就像公司内网的行政前台,负责把部门名字转成分机号。但有以下几种情况会导致前台"罢工":
自定义网络未启用DNS:
docker network inspect 网络名 | grep "EnableIPv6"容器启动时覆盖了DNS配置:
# 错误的启动方式示例 docker run --dns="" ...宿主机防火墙阻断了DNS流量
3.2 Host网络模式对比
使用--network=host时,容器直接复用主机网络栈,相当于省去了前台中转。但这种方式:
优点:
- 直接使用主机DNS配置
- 网络性能更好
缺点:
- 端口冲突风险
- 失去网络隔离性
我曾帮客户排查过一个经典案例:他们的监控容器在host网络下解析正常,但业务容器在bridge网络下解析失败,最终发现是Docker守护进程的DNS配置被误删。
4. Docker DNS配置大全
4.1 全局DNS配置
修改/etc/docker/daemon.json是最稳妥的方案(记得备份原文件):
{ "dns": ["114.114.114.114", "8.8.8.8"], "dns-opts": ["timeout=2", "attempts=2"], "dns-search": ["mydomain.com"] }配置后必须重启Docker服务:
systemctl restart docker重要提示:在Kubernetes集群中这样修改会影响所有节点,需要谨慎操作。我遇到过某次批量修改导致集群DNS瘫痪的事故。
4.2 单容器DNS设置
对于特定容器,可以在运行时指定:
docker run --dns=223.5.5.5 --dns-search=dev.svc.cluster.local ...或者使用docker-compose.yml:
services: app: dns: 223.5.5.5 dns_search: dev.svc.cluster.local4.3 特殊场景处理
当使用自定义网络时,建议显式指定DNS:
docker network create --driver=bridge --subnet=172.28.0.0/16 \ --gateway=172.28.5.1 --opt "com.docker.network.bridge.name"="docker1" \ --dns=8.8.8.8 my-bridge-network在Swarm模式下,需要修改/etc/docker/daemon.json后滚动重启节点。
5. 高级排错技巧
5.1 诊断工具集
# 查看容器完整配置 docker inspect --format='{{.NetworkSettings}}' 容器名 # 抓取DNS查询包 docker run --rm --net=container:目标容器名 nicolaka/netshoot \ tcpdump -i any -n udp port 53 # 使用dig工具测试 docker run --rm --dns=8.8.8.8 radial/busyboxplus dig google.com5.2 典型故障树
根据经验整理出以下排查路径:
- 检查容器内
/etc/resolv.conf内容 - 验证基础网络连通性
- 测试DNS服务器可达性
- 检查防火墙规则
- 审查Docker守护进程配置
- 检查自定义网络设置
5.3 日志分析要点
重点关注以下日志关键词:
- "Temporary failure in name resolution"
- "Name or service not known"
- "DNS timeout"
- "Servfail"
在Kubernetes环境中,还需要检查CoreDNS或kube-dns的日志:
kubectl logs -n kube-system -l k8s-app=kube-dns6. 生产环境最佳实践
6.1 配置规范建议
- 所有环境统一DNS配置
- 为不同环境设置不同的搜索域
- 开发环境:dev.example.com
- 生产环境:prod.example.com
- 设置合理的超时和重试参数
- 重要服务配置DNS缓存
6.2 监控方案
建议监控以下指标:
- DNS查询延迟
- DNS查询失败率
- DNS缓存命中率
Prometheus示例配置:
- job_name: 'container_dns' metrics_path: '/metrics' static_configs: - targets: ['dns-exporter:9100']6.3 灾备方案
- 主备DNS服务器配置
"dns": ["主DNS", "备DNS"] - 定期测试DNS故障转移
- 准备应急脚本快速切换DNS
7. 跨平台注意事项
7.1 macOS/WSL特殊处理
在Docker Desktop for Mac中,需要修改~/.docker/daemon.json:
{ "dns": ["host.docker.internal"] }WSL2环境下建议:
# 在/etc/wsl.conf中添加 [network] generateResolvConf = false7.2 云环境适配
各大云厂商的DNS服务:
- AWS:VPC DNS服务器
- 阿里云:100.100.2.136/100.100.2.138
- 腾讯云:183.60.83.19/183.60.82.98
在Kubernetes集群中,CoreDNS配置示例:
apiVersion: v1 kind: ConfigMap metadata: name: coredns data: Corefile: | .:53 { forward . 8.8.8.8 223.5.5.5 cache 30 }8. 终极解决方案
当所有常规方法都失效时,可以尝试以下"杀手锏":
完全重置Docker网络:
systemctl stop docker rm -rf /var/lib/docker/network systemctl start docker使用第三方网络插件:
docker plugin install weaveworks/net-plugin:latest切换为Containerd运行时
最后提醒:每次修改配置后,建议按顺序执行以下验证:
# 测试基础解析 docker run --rm busybox nslookup google.com # 测试服务发现 docker run --rm --network=my-network busybox nslookup service-name # 测试外部连通性 docker run --rm busybox ping -c 4 baidu.com