美文网首页
k8s线上集群的机器,重启iptables后,造成CI系统(dr

k8s线上集群的机器,重启iptables后,造成CI系统(dr

作者: 海角之南 | 来源:发表于2018-08-01 11:00 被阅读169次

    引子:

    线上的k8s集群内部,每一台机器,都有2块网卡,一块儿em1(10网段),一个 em2(192网段)。然后,线上的机器,通过iptables限制为:访问192段的服务任意端口都是畅通的,而访问10段的服务端口,只有333端口可以连通。333端口,是线上机器的ssh端口。

    线上集群的k8s,使用的calico网络。

    线上有一个问题,就是容器访问当前宿主机192段IP的999端口不通,访问其他机器192段IP的9999端口畅通。

    我们知道,当从容器访问宿主机的应用时,会重新进入iptables的INPUT链,而线上的iptables INPUT链如下:

    Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination         
    1    1477K 2519M cali-INPUT  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* cali:Cz_u1IQiXIMmKD4c */
    2     272K   20M KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
    3     273K   20M KUBE-FIREWALL  all  --  *      *       0.0.0.0/0            0.0.0.0/0           
    4     263K   20M ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
    5        0     0 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0           
    6      393 17292 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0           
    7    11880 1019K ACCEPT     all  --  em2    *       0.0.0.0/0            0.0.0.0/0           
    8        7   308 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:333
    9     228 62052 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
    

    意思是:

    ①:如果报文是途径em2网卡,访问任意其他网卡。则全部放行。(这就是为什么192段的访问全部放行)

    ②:如果报文是tcp,不管报文从哪个网卡出来,去往哪个网卡,只要目的端口是333,就放行。(这就是为什么10段的访问,只能访问333)

    我们容器发出的报文,网卡是 cal 网卡(calico的网卡名称),所以,容器只能访问333。

    错误操作:

    要把9999端口放开,意味着,我要添加开放9999端口到INPUT链路中,为了让iptables再重启后依然生效,我将规则,添加到

    /etc/sysconfig/iptables
    

    在添加完成后其实并未生效,然后,有2种方式,用于让iptables生效:

    ①:手动添加规则,比如 iptables -t filter -I INPUT 9 -s 172.20.0.0/14 -p tcp -m tcp --dport 9999 -j ACCEPT

    ②:重启iptables(会自动加载 /etc/sysconfig/iptables内容 )

    我选择了后者,之所以选择后者,其实是因为,即便重启了iptables,加载了刚刚的规则,原来的k8s和calico的iptables会丢失,但是,k8s会重建自己的整套iptables规则的。

    事实上,k8s确实也在我重启iptables后,重建了iptables,但问题来了。

    引发的2个网络问题:

    1、我们线上的CI系统,是基于drone,做的二次开发,改动了很多的东西,添加了很多特性,结果上面一系列操作之后,我发现,我们的CI系统中,个别镜像的构建(Dockerfile中的RUN操作,有网络相关操作时,比如yum)会失败。

    2、线上的机器,执行 docker run,起来的容器,无法访问外网了。然而,k8s起来的pod里的容器,却可以访问外网。

    镜像的构建,其实本质上,也是起容器来做事情,而且,你无法定制docker build操作时,使用的网络模式,只能是bridge模式。而 docker run 起来的容器,默认也是 bridge 模式。结合上面2个内容,基本上可以确定,此问题,和k8s无关,而是纯粹的docker的问题了。

    排查:

    ①:一开始以为是k8s的iptables重建不完整,所以,多次用线上的机器的机器 nodeA(无人访问的一台),不断尝试清空iptables,等待k8s重建iptables,多次尝试无效。

    ②:stop docker -> stop kubelet -> clean iptables -> start docker -> start kubelet。这个操作的意义是,以为重启docker,重启k8s,docker 和 k8s 都会重建自己的 iptables。多次尝试无效。

    ③:使用现在的k8s安装工具:kubespray,重新安装 nodeA,并添加到k8s集群内。寄希望于安装工具重装docker和k8s,结果依然无效。

    ④:回归问题本身,问题一定出在iptables上。也是因为一开始重启了iptables导致此一系列问题。

    解决过程:

    既然问题出在iptables上,而我们要访问外网,那么,就得重iptables 报文转出入手。好在线上的机器,并没有都为了适配9999端口重启iptables,有3台 k8s 的 master 节点,并没有重启 iptables。

    然后,对比有问题机器、没有问题机器的 FORWARD、POSTROUTING 的规则。发现,缺少DOCKER相关的规则,这些规则,本来是安装docker之后,由docker创建的。那么,解决此问题,就需要重建docker的iptables。

    ①:找一台干净的机器(只安装了docker,未启动容器,为安装k8s),然后从中提取docker相关的规则

    ②:将提取的规则,与出问题的机器的iptables默认规则融合。

    ③:执行 iptables-restore 恢复规则。

    后续验证:

    在问题机器上,docker run centos 容器,然后ping qq.com,链路畅通。有一个小问题,就是如果你先启动的容器执行 ping 外网操作。然后才再目的机器上执行 iptables-restore 的话,会发现,容器的 ping,有一个短暂的耗时,然后才会畅通,这是因为 iptables-restore 恢复规则后,有一个过程。

    最后:

    我整理一个相对标准的docker iptables规则备份,如果你也遇到了启动的docker容器,无法访问外网的问题,可以通过下面的内容,恢复规则

    将下面的规则,保存到一个文件,比如 docker-iptables-backup

    # Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
    *nat
    :PREROUTING ACCEPT [18:1080]
    :INPUT ACCEPT [18:1080]
    :OUTPUT ACCEPT [22:1550]
    :POSTROUTING ACCEPT [22:1550]
    :DOCKER - [0:0]
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
    -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
    -A POSTROUTING -s 172.17.0.1/32 -d 172.17.0.1/32 -p tcp -m tcp --dport 80 -j MASQUERADE
    -A DOCKER ! -i docker0 -p tcp -m tcp --dport 3001 -j DNAT --to-destination 172.17.0.1:80
    COMMIT
    # Completed on Thu Apr 30 20:48:42 2015
    # Generated by iptables-save v1.4.21 on Thu Apr 30 20:48:42 2015
    *filter
    :INPUT ACCEPT [495:53218]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [480:89217]
    :DOCKER - [0:0]
    -A FORWARD -o docker0 -j DOCKER
    -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
    -A FORWARD -i docker0 -o docker0 -j ACCEPT
    -A DOCKER -d 172.17.0.1/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
    COMMIT
    # Completed on Thu Apr 30 20:48:42 2015
    

    然后,执行恢复 iptables-restore docker-iptables-backup

    注意:

    ①:如果你的docker在k8s集群内部,理论上来说,上面的操作会有清空iptables的能力,但是你不需要担心,因为k8s会自行修复本身的iptables,也就是说,k8s会重建自己的iptables。但是假如你的k8s没能完整重建,就需要手动恢复k8s的iptables。如果是calico网络,只需要删除当前节点的calico pod即可,删除之后,k8s会重启这个pod,自然也就会重建iptables了。同理,flannel网络也是一样的。

    ②:上面的规则,有一个关键,是 172.17.0.0 和 172.17.0.1,这是docker默认安装后的网段和docker0网卡的IP。如果你是默认安装的docker,上面的规则不需要改动,但如果你定制了docker0网卡的IP,记得修改一下上面的规则,适配你的环境。

    相关文章

      网友评论

          本文标题:k8s线上集群的机器,重启iptables后,造成CI系统(dr

          本文链接:https://www.haomeiwen.com/subject/flplvftx.html