zoukankan      html  css  js  c++  java
  • 几个容器网络相关问题的分析和解决总结

    【摘要】 网络/容器网络因为其本身的复杂性,以及很多侧重软件开发的童鞋并不熟悉网络,导致和网络/容器网络相关问题的定位、分析和解决都比较困难,很多时 候有无从下手之感。我对最近、再加上以前参与处理了的几个网络/容器网络相关的问题,总结如下,希望能给遇到类似的问题的童鞋一点启发。

    目录

    1. 目标主机上没有到源主机的路由,导致ping包没有返回 - route 
    2. Pod可以跨节点访问docker0 IP,但是不能跨节点访问Pod IP - ip_forward 
    3. Flannel隧道内部payload的源地址改变为flannel0设备地址 - iptables 
    4. 从Docker容器内可以ping通宿主机IP,但ping不通其它主机 - iptables 
    5. K8s集群掉电,导致所有的服务不能访问 - flannel & docker0 
    6. K8s Master主机上ping不通Node节点上的docker0和容器,但在Node上可以ping通 - iptables

    网络/容器网络因为其本身的复杂性,以及很多侧重软件开发的童鞋并不熟悉网络,导致和网络/容器网络相关问题的定位、分析和解决都比较困难,很多时 候有无从下手之感。我对最近、再加上以前参与处理了的几个网络/容器网络相关的问题,总结如下,希望能给遇到类似的问题的童鞋一点启发。

    总结一下,引起网络不通的主要原因有:

    路由(route)问题。这类问题多如牛毛。常见的是目标主机到源主机的路由不通。

    防火墙(iptables)问题。这类问题多如牛毛,但iptables比route更复杂。主要有:(1)防火墙filter表的规则阻止icmp包;(2)防火墙NAT表的SNAT/MASQUERADE。

    系统内核参数问题。较少,更隐蔽,现象怪异得会让你怀疑自己的智商和人生。例如ip_forward,rp_filter等。

    Linux设备参数设置。较少,更隐蔽,现象怪异得会让你怀疑自己的智商和人生。例如MTU等。 至于IP地址配置错误等问题就太明显了,不在本文讨论之列。

    1. 目标主机上没有到源主机的路由,导致ping包没有返回 - route

    问题现象:

    某类生产环境,因为网络不通导致安装PaaS平台失败。从源主机ping目标主机,数据包没有返回。

    分析排查:

    思路得清楚,你需要画一张类似如下的图:

    在目标主机使用route -n查看没有到源主机网络的路由。

    源主机和目标主机都需要加路由。否则目标机器能收到ping包,但是返回报文会因为路由不通丢失。

    route add -net 192.144.52.0/24 gw 192.144.152.253 dev eth1 
    route add -net 192.144.152.0/24 gw 192.144.52.253 dev eth0

    2. Pod可以跨节点访问docker0 IP,但是不能跨节点访问Pod IP - ip_forward

    问题现象:

    某生产环境,K8s+Docker+flannel。从pod内跨节点ping另外节点的pod ip,不通;但是ping另外节点的docker0,是可以ping通的。意思是Pod可以跨节点访问docker0(证明flannel隧道是可以的),但是不能跨节点访问pod。

    图示如下:

    分析排查:

    排查如下:

    测试如下:

    问题解决:

    因为问题现象比较怪异,一度开始怀疑自己的智商和人生。

    最后欧拉的同事发现是故障节点的内核参数ip_forward=0。

    这个ip_forward是必须打开的参数,否则内核收到来自docker0的非本地地址的数据包会丢弃,而不会转发(forward)出去。

    进一步分析,应该是EulerOS的security-tool启动时修改了内核参数(包括设置net.ipv4.ip_forward=0)导致的问题。

    Docker engine启动的时候默认也会设置net.ipv4.ip_forward=1,但是security-tool和docker engine都是系统的service,启动时间和快慢不同,可能导致这个值被两个工具设置的先后顺序不一样,导致我们看到不一样的行为。(注:这个分析待商榷)

    建议的解决办法:

    设置/etc/sysconf中的net.ipv4.ip_forward=1,执行sysctl –p。但这个需要欧拉Docker确认security-tool修改的其它内核参数和安全加固等,会不会影响docker引擎。 
    如果还不行,就修改security-tool的配置(不推荐): 修改/etc/euleros_security/security.conf的 
    301@m@/etc/sysctl.conf@net.ipv4.ip_forward=@0 ---> 
    301@m@/etc/sysctl.conf@net.ipv4.ip_forward=@1 
    当然我们的Salt脚本也会显式地设置这个值。

    3. Flannel隧道内部payload的源地址改变为flannel0设备地址 - iptables

    问题现象:

    但是在抓包的过程中,发现Flannel隧道内部payload的源地址改变为发起请求的Pod所在节点的flannel0设备地址,而不是发起请求的Pod的IP地址。

    关于这个问题的详细分析,请见Flannel隧道内部payload的源地址改变为flannel0设备地址的问题分析

    分析排查:

    首先,应该不是Kube-Proxy做的修改。因为Kube-Proxy只对访问Service(ClusterIP)的流量,做了很多iptables规则;而抓包实验中是直接使用Pod的IP地址操作的。

    其次,进程flanneld应该不会修改这个源IP地址。因为flanneld在跨节点传送数据的过程中的一个主要作用是做隧道的解/封装,它没有理由去修改payload的内容(inner source ip)。

    我们有理由相信,flanneld拿到这个数据包时,这个inner source ip已经被修改成发起请求的Pod所在节点的flannel0设备地址了。

    通过查看iptables规则,发现有如下一条:

    -A POSTROUTING -s 10.1.15.0/24 ! -o docker0 -j MASQUERADE 
    这是docker设置的。它的意思是:在POSTROUTING链上,如果源地址属于10.1.15.0/24,且出站网络接口不是docker0,则做地址伪装。

    MASQUERADE,即IP伪装,是SNAT的一种特殊形式。这应该只用于动态分配IP地址的场景。在MASQURADE中,你不需要明确指定源地址,iptables会使用该数据包出站时的网口的IP地址。关于MASQUERADE,请参考Kubernetes和容器网络详解系列之Kubernetes iptables。

    由于以上这条规则,从docker0入站的流量,最终通过flannel0出站时,会把数据包源地址修改为出站接口flannel0的地址。这个时候flanneld再做封装时,payload中的源地址(inner source ip)已经被修改成flannel0的地址了。

    问题解决:

    删除这条规则。

    4. 从Docker容器内可以ping通宿主机IP,但ping不通其它主机IP - iptables

    问题现象:

    从Docker容器内可以ping通宿主机IP,但ping不通其它主机IP。

    分析排查:

    从现象可以看到数据包可以从Pod中经过docker0出去。检查防火墙规则的时候发现是因为没有做SNAT。这样会导致目标主机可以收到ping包,但是返回包会丢失。(没有抓码流验证)

    问题解决:

    给防火墙添加了如下iptables规则: iptables -t nat -A POSTROUTING -s 172.16.94.0/24 -j SNAT --to <宿主机IP>

    5. K8s集群掉电,导致所有的服务不能访问 - flannel & docker0

    问题现象:

    K8s集群掉电后,服务不能访问。 查看主机上的flannel.1和docker0网络,发现网段不一致。

    如下:

    分析排查:

    原因:掉电导致集群节点的docker0网络配置和flannel0的网络配置不一致。flannel的网络配置是保存在etcd集群中的,以此为准。

    问题解决:

    解决办法:

    1、ifconfig flannel0和ifconfig docker0看到二者的网络配置不一致 
    2、停止docker0,并删除之:ifconfig docker0 down; brctl delbr docker0 
    3、修改/etc/default/docker中的--bip,和flannel0的保持一致 
    4、重启docker daemon,service docker restart 
    5、docker服务运行正常后,ifconfig docker0检查:(1)docker0是否重新创建;(2)网段配置是否和flannel0保持一致。如果提示没有docker0设备,稍等一会,或者再次重启docker服务 
    6、重启docker服务,会造成上面的pod运行状态错误为Error。用watch kubectl get pods监视一会,会自动恢复正常。 
    7、按照常规测试业务的连通性。 
    建议:较新版本的CCE已经对此问题有处理手段,建议升级。

    6. K8s Master主机上ping不通Node节点上的docker0和容器,但在Node上可以ping通 - iptables

    问题现象:

    一个K8s集群,包含一个Master三个Node,Master没有Node的角色,但同时安装和启动了Flannel。 使用Flannel做Overlay,backend是VXLAN。从Master上ping其它Node的docker0/Pod IP不通,从Node节点上互ping docker0/Pod IP没有问题。 导致开放原生K8s API失败(从api server代理proxy流量到Pod失败)。

    分析排查:

    在目标Node节点的flannel.1上抓包,可以看到有返回包,但是收不到。 检查IP、路由、网络设备等均无发现问题。

    在Master节点上,用ipables-save查看防火墙规则,发现如下两条和icmp相关的,一条在INPUT链上,一条在FORWARD链上:

    -A INPUT -j REJECT --reject-with icmp-host-prohibited 
    ... ... 
    -A FORWARD -j REJECT --reject-with icmp-host-prohibited 
    可以看出Master节点会拒绝掉icmp包,理由是主机不允许。

    问题解决:

    找到以上两条防火墙规则的所在行号,然后删除之:

    查看INPUT链: 
    iptables -L INPUT --line-numbers 
    如下: 
    7 REJECT all -- anywhere anywhere reject-with icmp-host-prohibited 
    删除: 
    iptables -D INPUT 7 
    查看FORWARD链: 
    iptables -L FORWARD --line-numbers 
    如下: 
    13 REJECT all -- anywhere anywhere reject-with icmp-host-prohibited 
    删除: 
    iptables -D FORWARD 13

    来源:华为云社区  作者: 乔雷

  • 相关阅读:
    AI生万物,新世界的大门已敞开
    荣耀10带来AI版WPS,玩转潮酷新功能
    P20 旅行助手,从未有过的至尊私人导游服务!
    如何成为快手尬舞王?HUAWEI HiAI了解一下!
    golang中的接口实现(二)
    golang中的接口实现(一)
    new~mac os 给终端命令写alias(及其他常用命令)及软连接
    Java面试题精选
    干货 unity小贴士
    js数组插入指定位置元素,删除指定位置元素,查找指定位置元素算法
  • 原文地址:https://www.cnblogs.com/2020-zhy-jzoj/p/13165747.html
Copyright © 2011-2022 走看看