Docker 容器端口转发失效

今天公司 Docker 里的服务突然莫名其妙访问不了了,经过将近一个小时的排查,最后摸索出了问题所在。详细情况是这样的,本来 Docker 里有个 web 服务,80 端口映射到宿主 0.0.0.0:18800,最初一切都很顺利,从前天开始会突然无法从外部网络访问服务,刚开始重启容器后问题的确消失了,但后来问题出现越来越频繁,最后到今天重启也无法解决问题。

下面详细记录下我排查问题的经过。

1. 从外部排查

首先从外部查起,打开浏览器看报错代码,chrome 报错显示 no response 服务器无响应,一脸懵逼明明网络是正常的,我的电脑和服务器在两个互通的内网下,能够 ping 通服务器,ssh 也正常。然后 curl -vvv 也证实了同样的结果——服务器完全不响应请求,没有发回任何数据。看样子问题出在服务端,从内部排查比较靠谱。

2. 进入容器,从内部排查

是不是服务挂了?登入服务器,进入容器内部排查问题,docker exec -it container /bin/bash 进入容器环境查看,发现服务后端进程正常运行,容器内 curl -vvv localhost 输出结果也正常,服务日志没有异常记录,但是仔细看完全没有刚刚从我电脑上请求的记录,也就是说容器里后端是正常的,只是没有收到外部请求。这让我更加疑惑了,既然容器内服务本身没问题,问题是不是在宿主服务器上?

3. 退一步海阔天空?

那么现在查查看服务器本身有没有问题。

  • docker ps 查看容器的配置,那个容器的端口映射配置显示 0.0.0.0:18800->80/tcp,正常无误;
  • netstat -apn | grep -w 18800 显示 docker proxy 也在正常监听;
  • ifconfigip addr…… 各种查看日志也没有发现服务器网络配置有异常变动;
  • tcpdump port 18800 在宿主服务器监听数据包来往的大体情况,然后从我的电脑发起请求。还是很奇怪,能看到发起请求的数据包正常到达端口 18800,后端服务就是没有任何回应
  • iptables --list-rules,服务器环境比较复杂,iptables 规则很多也很复杂,iptables -L FORWARD 大体阅读了下 FORWARD 链,也都正常的,不存在意外 REJECTDROP 的情况;

这让我太疑惑了,现在既然连转发查下来都是正常的,问题到底处在哪一环???

4. 我有一个大胆的想法系列!

我有一个大胆的想法,问题还是出在宿主服务器转发一环上!我也不知道为什么!有一个比较奇怪的现象是,从宿主服务器 curl localhost:18800 也能得到正常的响应,但从网络中其他电脑发请求就是不行,说明 docker 端口转发设置其实也是正常生效的。

因为服务器的 iptables 规则超级多,我并没有全部读完,所以我决定大胆尝试(作死)一波

  • iptables -P FORWARD ACCEPTFORWARD 链的 policy 本来是 DROP,我先来把它改成 ACCEPT,尝试发现没用,继续;
  • iptables -I FORWARD -j ACCEPT。暴力 ACCEPT FORWARD 链,抱着很大希望,尝试结果还是失败;
  • iptables -I INPUT -j ACCEPTiptables -I OUTPUT -j ACCEPT,意料之中的失败;

所以问题到底出在哪里???(趁人不注意乖乖把 iptables 恢复原样)回回神仔细考虑分析了下,的确只剩下上面这种可能了,问题只能出在宿主转发上!🤔再次一脸懵逼之余漫无目的地随手敲打敲打键盘 sysctl net/ipv4/ip_forward…… 等一下!它输出了:net.ipv4.ip_forward = 0?!内核转发为什么是关闭的?!赶紧 sysctl net/ipv4/ip_forward=1 再尝试,我的想法果然是对的,还是宿主转发的问题,现在可以正常访问了!

我靠!瞎搞半天,最后问题居然不在 docker 上,🙄查看下 /etcsysctl 的配置文件,居然把内核转发给关了!服务器谁写的坑爹配置!我现在很好奇以前是怎么用的…… 是不是写死进哪个脚本里去了?不管了,只要现在能稳定用就好。