Docker host 网络下代理全返 503:一次 DNS 注入缺失的排查

举报
yd_269248920 发表于 2026/11/10 00:54:25 2026/11/10
【摘要】 gost 用 --network host 部署后,本机自测正常、跨机访问全部 503。日志里的 lookup ... on [::1]:53 指向根因:host 网络模式跳过 Docker 的 DNS 注入。

背景

内网里有一批机器需要统一的出网 HTTP 代理。选型时没有走自研,而是用了成熟的 gost,一条命令即可起一个带认证的 HTTP 代理:

docker run -d --name gost-proxy --network host \
  gost -L http://user:pass@:8081

用 --network host 是为了避免端口映射带来的额外一层 NAT,代理直接监听宿主机的 8081。部署完成后,在宿主机上自测:

curl -x http://user:pass@127.0.0.1:8081 https://www.example.com -I

返回 200,看起来一切正常。问题出在从其它机器访问这台代理的时候。

现象

从另一台机器把代理指向这台机器的内网地址后,请求全部失败,而且失败得很整齐——不是超时,是立刻就返回:

curl -x http://user:pass@10.x.x.71:8081 http://example.com -v
* CONNECT tunnel failed, response 503

503 是代理自己返回的,说明 TCP 已经连上了、代理进程活着,是它转发不出去。同一时刻在代理所在的机器上用 127.0.0.1 测又是好的。

这就把排查范围收得很窄了:代理进程本身没问题,认证没问题,端口映射没问题,问题只出在「从外部进来」和「从本机走」之间的差别。而这两者唯一的区别是请求的来源地址,不涉及代理的转发逻辑。

定位过程

第一步看容器日志,gost 把每一次失败的解析都打出来了:

docker logs --tail 50 gost-proxy
... dial tcp: lookup www.example.com on [::1]:53: read udp [::1]:54912->[::1]:53: connection refused

关键信息是 on [::1]:53——容器在拿 ::1(IPv6 回环)当 DNS 服务器,而那个地址上根本没有 resolver 在监听,于是每次域名解析都瞬间失败,代理只能返回 503。

继续查容器的 /etc/resolv.conf:

docker exec gost-proxy cat /etc/resolv.conf
# 空文件,或者只剩一行 nameserver ::1

根因

这是 --network host 的一个常见副作用。使用 bridge 网络时,Docker 的嵌入式 DNS 会给容器注入可用的 nameserver(通常是 127.0.0.11);而在 host 网络模式下,容器直接复用宿主机的网络命名空间,Docker 不再做这层 DNS 注入,resolv.conf 要么被写空,要么只留下一个从宿主机 IPv6 配置里继承来的 ::1。

宿主机上 ::1:53 没有 resolver,所以容器内的解析必然失败。宿主机自己不受影响,因为宿主机的 glibc 会按 resolv.conf 里的多个 nameserver 顺序尝试,而容器里只剩这一个失效条目。

修复

不需要改 gost 的任何配置,只需要显式告诉 Docker 用哪个 DNS:

docker rm -f gost-proxy
docker run -d --name gost-proxy --network host \
  --dns 223.5.5.5 --dns 119.29.29.29 \
  gost -L http://user:pass@:8081

重建后确认:

docker exec gost-proxy cat /etc/resolv.conf
# nameserver 223.5.5.5
# nameserver 119.29.29.29

再次从外部机器测,503 消失,代理恢复正常。

一个容易踩的验证顺序坑

这次排查里最容易走弯路的地方不是修,而是验证。因为一开始在宿主机上用 127.0.0.1 自测是通过的,很容易得出「代理是好的,是网络不通」的错误结论,然后去查防火墙、查 overlay 网络、查路由。

正确的验证分两层,两层含义完全不同:

  • 在代理所在机器上测 127.0.0.1:只证明代理进程能工作、认证对、能出网。这一层过不了,才是代理本身的问题。
  • 从其它机器测内网地址:这才验证「跨主机可达性」。这一层过不了,可能是网络,也可能是代理的转发路径依赖了某些只在本机成立的条件(本例就是 DNS)。

如果只在第一层验证就宣布部署完成,故障会在所有下游使用者那里同时爆发。

小结

三点结论:

  1. --network host 会跳过 Docker 的 DNS 注入,容器里的 resolv.conf 可能为空或只剩 ::1,所有依赖域名解析的程序都会静默失败。
  2. 代理返回 503 而不是超时,通常说明「TCP 通了、上层失败」,先看日志里的 lookup ... on [x]:53,比查网络快得多。
  3. 部署验收必须分两层做:本机回环能通只代表进程健康,跨机可达才算真部署完。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。