作者介绍:简历上没有一个精通的运维工程师。
我们上一章介绍了Docker基本情况,目前在规模较大的容器集群基本都是Kubernetes,但是Kubernetes涉及的东西和概念确实是太多了,而且随着版本迭代功能在还增加,笔者有些功能也确实没用过,所以只能按照我自己的理解来讲解。
我们前面2个小节介绍了svc的几种类型,但是并没有介绍这个流量是如何从svc走到pod去的,下面我将以iptables的方式介绍流量是如何通过svc方式走到pod里面的。
首先需要了解的就是svc是一个虚假的地址,并不真实存在,所以它不可以piing通(实际上svc也只是ip+端口形式的暴露),实际上这个svc地址的访问也只是命中了iptabels规则,通过iptables进行了转发。
我们以下面的这个30008端口来进行讲解,在比较早期的版本这个30008端口还会监听在每个节点的kube-proxy进程上,当前我使用的版本已经不再监听NodePort端口。
首先我们收集了这个规则对应的iptabes规则。
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/my-service" -m tcp --dport 30008 -j KUBE-SVC-FXIYY6OHUSNBITIX
-A KUBE-SVC-FXIYY6OHUSNBITIX -p tcp -m comment --comment "default/my-service" -m tcp --dport 30008 -j KUBE-MARK-MASQ
第一条规则是真正转发规则,我们详细说明。第二条规则只是起标记作用,方便做NAT转发,这里就不介绍,其实我也没完全理解到。
-A KUBE-NODEPORTS
在 KUBE-NODEPORTS
链中添加一条规则,这个链也是在nat表里面增加的自定义链,方便统一管理同类型的规则。-p tcp
指定该规则适用于 TCP 协议。-m comment --comment "default/my-service"
为该规则添加注释,说明这条规则是为名为 “my-service” 的服务在 “default” 命名空间中设置的。-m tcp --dport 30008
匹配目标端口为 30008 的 TCP 数据包。-j KUBE-SVC-FXIYY6OHUSNBITIX
如果数据包匹配上述条件,则跳转到 KUBE-SVC-FXIYY6OHUSNBITIX
链继续处理。通俗来说就是当访问当前节点的30008,也就是我们定义的svc的NodePort的时候它会把请求转发到KUBE-SVC-FXIYY6OHUSNBITIX继续处理,当然这里是基于有NodePort的情况,如果是ClusterIP则会有下面这个规则。
-A KUBE-SERVICES -d 10.100.211.232/32 -p tcp -m comment --comment "default/my-service cluster IP" -m tcp --dport 80 -j KUBE-SVC-FXIYY6OHUSNBITIX
这个规则其实和前面那个规则逻辑是一样的,只是这个规则命中的是svc的ip+端口,然后也是往KUBE-SVC-FXIYY6OHUSNBITIX继续处理。
前面2条规则就是对流量进行拦截,只要命中这个svc的信息就接着往后走,下面我们接着看后面的规则。
-A KUBE-SVC-FXIYY6OHUSNBITIX ! -s 10.244.0.0/16 -d 10.100.211.232/32 -p tcp -m comment --comment "default/my-service cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-FXIYY6OHUSNBITIX -p tcp -m comment --comment "default/my-service" -m tcp --dport 30008 -j KUBE-MARK-MASQ
上面这2条规则也是主要起标记作用,下面3条就是真正的核心的转发逻辑,由于这个pod只有3个后端,所以这里就只有3条,这里的数量是由正常可用的pod数量决定的。
-A KUBE-SVC-FXIYY6OHUSNBITIX -m comment --comment "default/my-service" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-2326I2JTW2R4QT2Y
-A KUBE-SVC-FXIYY6OHUSNBITIX -m comment --comment "default/my-service" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-JZUXTWVVYKNJ3L75
-A KUBE-SVC-FXIYY6OHUSNBITIX -m comment --comment "default/my-service" -j KUBE-SEP-XKSMMTNDLCGHRV4S
-m statistic --mode random --probability 0.33333333349
:使用统计模块(statistic
)来随机选择数据包。这里指定了 random
模式,并且设置了一个概率值 0.33333333349
(大约等于 1/3)。这意味着大约有三分之一的匹配数据包会被发送到指定的目标。当前这个规则未命中,则继续匹配后面2个规则,所以第二个规则概念提升到了50%,如果前面2个未命中,则第三条规则命中的概率就是100%。通过这个方式svc就实现了类似轮询的方法把请求转发到后端的多个pod里面。-j KUBE-SEP-2326I2JTW2R4QT2Y
:如果数据包被随机选择(根据上述概率),则跳转到名为 KUBE-SEP-2326I2JTW2R4QT2Y
的链。这个链通常包含将数据包路由到特定后端 Pod 的规则。KUBE-SEP-*
链的名称是后端 Pod 端点(Endpoint)的哈希值。-A KUBE-SEP-2326I2JTW2R4QT2Y -p tcp -m comment --comment "default/my-service" -m tcp -j DNAT --to-destination 10.244.1.73:80
-A KUBE-SEP-JZUXTWVVYKNJ3L75 -p tcp -m comment --comment "default/my-service" -m tcp -j DNAT --to-destination 10.244.1.74:80
-A KUBE-SEP-XKSMMTNDLCGHRV4S -p tcp -m comment --comment "default/my-service" -m tcp -j DNAT --to-destination 10.244.1.75:80
这3条规则就是真正DNAT转发到后端pod的规则,由于我们的网络组件提前打通了到任何pod的通信,所以这里只要做了DNAT就可用转发成功。总结下来大概就是下图这样的。
如果出现访问svc不通,就可用通过该方式查询流量的走向,然后来排查问题所在。