2015年12月16日,朱鹏安装了新版kubernetes master版本(比1.1新,为1.2alpha**),然后发现,访问 clusterIP:clusterPort 会发生无法连接的故障。
从集群内Node上访问
分别在Node rz-ep19和container里执行curl访问,发现container里curl可以成功访问,但Node上一般不行(偶尔成功,几率很低)。查看iptables规则,发现新版kube-proxy已经不再将请求REDIRECT到本机kube-proxy端口,而是:
- 先把PREROUTING、OUTPUT无条件指向KUBE-SERVICES链;如匹配不上KUBE-SERVICES链,则再尝试匹配发给docker0
- 在KUBE-SERVICES链里匹配clusterIP:clusterPort条件,然后发到KUBE-SVC-***链
- 在KUBE-SVC-***链中,用-m statistic –mode random –probability这样的条件将流量按等比例分给多个KUBE-SEP-***链
- 然后再在KUBE-SEP-***链中,将数据包DNAT给endpoint
为了减少干扰,我们缩减了kube-system/elasticsearch-logging 10.16.59.73:9200服务的规模,到只有一个endpoint 172.16.86.48:9200运行在rz-ep10上;rz-ep19 10.16.49.16作为运行curl的客户端
- 在rz-ep19的flannel接口上抓包,抓到了 10.16.49.16->172.17.86.48的TCP SYN,但没有收到回应。
- 在rz-ep10(endpoint Pod所在的Node)的flannel接口上抓包,抓到了和上述相同的包,也没有收到回应。
- 在rz-ep10的docker0接口上抓包,没有抓到
由此判断,rz-ep10的内核在转发时主动丢弃掉了 10.16.49.16->172.17.86.48的SYN,以至于无法建立TCP连接。查看/proc/sys/net/ipv4/conf/{all,flannel.7890}/rp_filter,发现flannel.7890/rp_filter内容为1,即在此网卡上执行“根据回溯路由检查数据包是否为伪造”的检查。因为源IP 10.16.49.16在rz-ep10看来理应出现自eth0而非flannel.7890接口,所以被判定为假造包,丢弃。
将此参数改为0,再去docker0上抓包,可以收到172.17.86.48发回10.16.49.16 SYNACK包;但rz-ep19上curl仍显示无法建立连接。
在rz-ep10的角度考虑,这个172.17.86.48->10.16.49.16的包应该从eth0发出,也就是在rz-ep19的eth0上收到。而在rz-ep19的角度考虑,源IP 172.16.86.48不应来自eth0,也会被rp_filter参数影响,丢弃掉,所以无法建立连接。把rz-ep19的eth0/rp_filter参数改为0,终于可以正常访问了。
从集群外访问
从办公区我的笔记本电脑 172.30.26.169 访问 10.16.59.67:80 服务,该虚IP被手工绑在rz-ep01上,ping可以通,但访问不通。
在笔记本电脑上抓包,发现只有从本机发往clusterIP的SYN包,没有返回,所以无法建立TCP连接。
改以Pod IP为过滤条件,发现Pod IP直接发回 SYN_ACK给我的笔记本电脑,但因为笔记本电脑这边没有发起对Pod的SYN,所以直接回复RST给Pod了。
改用iptables模式之后,由于不对称路径的问题,这种访问基本上无法以以前“把clusterIP绑在Node上”的做法实现