在刚刚过去的北美KubeCon 18中,有一位来自Redhat的老哥分享了k8s网络的诊断的方法,阿里云容器服务在客户问题中有挺多是网络的问题,这个分享可以帮助在使用k8s网络遇到问题时的诊断流程。
首先介绍了k8s网络为啥这么复杂,都有哪些考虑到的地方,这部分介绍的很多内容也是我们团队在做网络时遇到的一些坑。
上面讲了很多网络的复杂度,下面讲师以kubeadm为例介绍了网络的配置过程,针对配置的过程以及每一步做的事情和完成的原因可以了解网络初始化的过程,方便出现问题时排查:
然后每个节点再配置CNI的plugin和配置,比如最常见的我们通过flannel的模板部署flannel的插件,节点在监听到插件和配置存在时会上报状态,这个时候整个节点的网络才ready,这时候k8s会将需要容器网络的容器调度到ready的节点上,Pending状态就会变成Creating状态,然后由节点上的kubelet再调用CNI插件去配置容器的网络,容器就能变成Running状态,这个时候容器的网络也就Ready了:
在CNI插件和配置文件安装到节点上后,节点就会变成ready了,就会有容器调度到节点上,但不一定容器能正确运行:
我们能看到的现象是这样的:容器一直在Creating,通过kubelet日志或者容器事件可以看到cni的报错
通常可以通过健康检查日志或者容器本身的网络请求的日志看到容器网络是不连通的:
对于容器网络不通的情况,我们要如何排查呢,这里讲师介绍了一些简单的容器虚拟化网络和排查的知识,可以从中入手:
ip -d -d link show dev {网卡名} 这个命令可以看到网卡的类型以及详细的一些信息,比如
cni0是一个bridge设备,可以比作物理网络中的交换机
这个截图是在容器内部执行的,容器的eth0网卡,是一个veth类型的设备,veth是用来联通不同的namespace的,通常用来联通容器和宿主机的网桥,后面的if33代表它联通的另外一端的网卡的编号,到宿主机的namespace中执行ip -d link show我们就能看到这个网卡编号对应的网卡
如果有的容器没有ip 命令,那我们要怎么进到容器中排查呢?可以通过nsenter的命令进入到容器的网络命名空间操作,例如:
其中的pid就是容器进程的ID,PID可以通过ps -ef | grep <容器进程>,也可以通过kubectl get pod -o yaml | grep containerID , 然后docker inspect 来找到对应的pid。
很多时候遇到网络配置成功,但是容器网络不通的问题都是iptables在从中作梗,比如增加了什么防火墙规则,Chain的Policy被改掉啦之类的。
容器进程访问网络时,会首先经过容器内部的iptables,然后到宿主机上面,在宿主机上面会通过宿主机的iptables和routing最终决定包的取舍和去向。
答案是谁都会。。。
iptables添加为了几个功能: 负载均衡(在PREROUTING中去做DNAT+RAMDOM), 访问控制(在FORWARD/INPUT/OUTPUT)中去做限制, 源地址装换(POSTROUTING中转换成宿主机的IP地址)等等
上面的介绍可见网络的过程和复杂度,但是通常排查时没办法一条一条规则的顺着去排查,何况规则还是由那么多组件操控随时会变化,这时候可以使用抓包工具排查在哪一层包被丢掉了来一一排除的解决问题:
我们可以在不同层次的网卡上抓包来看到底包丢在什么地方,或者被改成了啥熊样。
在容器服务这边,通常情况下,我们采用tcpdump的方式通过容器IP等过滤条件抓包排查,如果需要详细的包的解析,可以tcpdump -w写到文件中,然后通过wireshark去解析,这里讲师展示了另外一个工具:kokotap
可以创建一个拷贝的接口,将容器的流量也导入到这个接口上方便wireshark直接在宿主机上也能抓到容器的包。
整个分享就是这些,这个分享中前面介绍了很多k8s网络的复杂度,这块介绍的比较全面,我们在做网络插件时在那些点上也都会遇到一些坑,在后面的介绍中主要是网络排查的入门以及工具,通过这些工具可以上手排查问题了,但排查到现象后具体的原因没有详细介绍,可能因为遇到的问题场景就太多了,大家可以在排查的过程中多多增加经验。
容器服务在k8s网络上有深入的实践,另外有开源的网络插件Terway,覆盖了k8s网络的方方面面,项目链接 https://github.com/AliyunContainerService/terway