死磕k8s之calico-nodeport

2 篇文章 0 订阅
2 篇文章 0 订阅

死磕k8s之calico-nodeport

序言:

本篇文章将要聚焦于k8s在使用calico作为网络插件的时候,当pod以nodeport的形式暴露出来,我们以集群节点的ip加端口的形式访问的时候,流量如何转发到具体的pod,流量经过了哪些路由和哪些iptables链。如集群还没准备好,请参考[死磕k8s之calico-环境准备]

我的环境

在这里插入图片描述

nginx pod信息

NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE              NOMINATED NODE   READINESS GATES
nginx-6799fc88d8-wfztd   1/1     Running   0          3h32m   192.168.231.70   shen-k8s-node-1   <none>           <none>

nodeport信息

NAME    TYPE       CLUSTER-IP    EXTERNAL-IP   PORT(S)          AGE    SELECTOR
nginx   NodePort   10.101.14.7   <none>        8080:32220/TCP   2d1h   app=nginx

注意

接下来的分析主要基于该表的路径
在这里插入图片描述

开始发请求到nodeport

我目前nginx的pod在work节点1上面,为了减少分析过程,我在和k8s同网段的其他机器10.0.0.53上面请求work节点1的ip加端口

curl 10.0.0.51:32220

到达work节点1

1.首先会到达raw的PREROUTING,包的流向如下

在这里插入图片描述

raw的PRESOUTING相对比较简单,在这里没有匹配到任何的规则

2.然后到达mangle的PREROUTING,包的流向如下

在这里插入图片描述

对新来的包来说也没有匹配到任何规则,但是第二条规则会对以后的包做一个放行,效率更高

3.然后到了重要表nat的PREROUTING,在PREROUTING一般对包做DNAT操作,包的流量如下:

在这里插入图片描述

此表的规则路径稍微复杂一些了,第三条规则匹配到了我们的请求的目标端口32220,注意下第4条规则,会给包打上0x4000/0x4000标签。最后到了第7条做了一个比较重要的dnat操作,此时请求的包的源地址还是10.0.0.53,但是包的目的地址会变成192.168.231.70,并且目标端口也会换成我们暴露的容器端口80。192.168.231.70正是pod nginx-6799fc88d8-wfztd 的地址。因为我们这里只有一个pod,所以只会匹配到这一条dnat规则,如果我们有多个pod的话,会按照该规则上的概率随机匹配到一条dnat规则。大家由此就会联想到service的负载均衡策略也可以这么做。

4.然后就开始第一次的路由选择了

在这里插入图片描述

上图是work节点1 的路由信息,据上面分析得到包的目的地址是192.168.231.70,此时正好匹配到红色框的路由。而虚拟网卡cali583c2cee4e2是和192.168.231.70这个pod的veth pair,下图可以求证
在这里插入图片描述
在这里插入图片描述
第一张图是在pod内看到虚拟网络信息,第二张图示pod所在节点的网络接口信息,pod内if41正好对应节点上网卡cali583c2cee4e2@if4,该网卡和上面匹配到的路由一样,所以该包可以顺利到达pod内。
但是此时的源地址还是最初发送请求的地址10.13.0.53,如果以这个包转发到pod内,那么pod的回包就找不到正确发送回来的目的地址了,故接下来肯定会对该包多SNAT,也就是修改源地址。注意此时包还没有发出去,还会继续走其他的表。

5.由于匹配到了路由信息,所以此时会走的链是mangle的FORWARD,但是该表没有对它作任何操作

6.接下来看看filter表的FORWARD

在这里插入图片描述

该链看着挺复杂,其实没有对包作重要的操作。大概说几个比较关键的地方,第2条规则是能匹配到的,因为此时的包经过路由决策之后是需要去cali+开头的网卡。第3条恰恰精确匹配到了包要转发的虚拟网卡。第4条虽然给包打上了0x10000/0x10000,但是走到第8条的时候注意红色框出,这里重新打包为0x4000/0x4000了这里尤其注意了,不然会翻车。

7.然后是到了mangle的POSTROUTING,然而该表没有任何规则

8.接下来到了nat表的POSTROUTING链,nat表重要的是做了一个重要的操作SNAT

在这里插入图片描述

该表重点就是第5条,依照前面分析有个0x400/0x400标记,不然就完了,下面就不会走到第6条去SNAT操作了。
通过抓包显示此时包的目的地址和源地址都被替换了。
在这里插入图片描述

9.此时包的路径分析基本已经结束了,因为包已经走到pod里面去了。

10.因为我们此时我们的pod正好在请求的ip的节点上,如果pod在work节点2上包的走向又会怎么样呢?

那我们改一下该pod的调度策略:

kubectl edit deployment nginx
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "2"
  creationTimestamp: "2020-11-09T05:56:04Z"
  generation: 2
  labels:
    app: nginx
  name: nginx
  namespace: default
  resourceVersion: "1086147"
  selfLink: /apis/apps/v1/namespaces/default/deployments/nginx
  uid: ec684051-3725-4f5e-9efd-d96fb3257cca
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: nginx
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: nginx
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      nodeSelector:
        kubernetes.io/hostname: shen-k8s-node-2 #(节点2)
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: "2020-11-09T05:56:18Z"
    lastUpdateTime: "2020-11-09T05:56:18Z"
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: "True"
    type: Available
  - lastTransitionTime: "2020-11-09T05:56:04Z"
    lastUpdateTime: "2020-11-10T14:13:15Z"
    message: ReplicaSet "nginx-854f5d4bbd" has successfully progressed.
    reason: NewReplicaSetAvailable
    status: "True"
    type: Progressing
  observedGeneration: 2
  readyReplicas: 1
  replicas: 1
  updatedReplicas: 1

过段时间查看pod状态,最终会调度到work节点2上去
在这里插入图片描述

此时的iptables信息和路由信息我就贴到死磕k8s之calico-环境准备去,如果感兴趣可以去那里查看。

11.现在就要从上面第3条的nat的PREROUTING开始继续分析

主要是第7条规则有变化,变成了新的pod的ip:192.168.233.136

-A KUBE-SEP-PAOOOQUDSCRRYKFR -p tcp -m comment --comment "default/nginx:8080-80" -m tcp -j DNAT --to-destination 192.168.233.136:80

12.然后会经历一波路由策略

在这里插入图片描述

和上面的不一样,这里是网段匹配了,会匹配到最后一条路由。该路由的会将包从网关10.0.0.52用网卡tunl0这个网卡转发出去。此时需要注意2点:

  • 网关正好是work节点2上的ip,而pod也被调度到该节点上
  • tunl0是一个特殊的虚拟网卡,由于我的环境是用的ipip模式,故有一个这个通道网卡,用来封装该报的目的地址和源地址,当改包到达了目的地址的主机的时候,在目的主机的tunl0网卡会把该包拆出来,得到最初的包。

13.mangle的FORWARD链没有任何规则,忽略

14.filter的FORWARD链没有重要的规则,但是有一条需要注意,其他的和上面的流程分析一致

-A cali-FORWARD -i cali+ -m comment --comment "cali:8ZoYfO5HKXWbB3pk" -j cali-from-wl-dispatch
-A cali-FORWARD -o cali+ -m comment --comment "cali:jdEuaPBe14V2hutn" -j cali-to-wl-dispatch

上面2条规则目前来说都匹配不到了,由于上面的路由改变了。

15.mangle的POSTROUTING没有任何规则,故忽略

16.接下来nat的POSTROUTING会做一个SNAT操作

其他的规则和上面的分析一致,但是注意这一条规则

-A cali-POSTROUTING -o tunl0 -m comment --comment "cali:JHlpT-eSqR1TvyYm" -m addrtype ! --src-type LOCAL --limit-iface-out -m addrtype --src-type LOCAL -j MASQUERADE

该规则会被匹配到直接做了以work节点1的tunl0的ip为源地址的SNAT操作。此时包为192.168.231.64 -> 192.168.233.136

17.此时包就从tunl0通道留到work节点2的ens192网卡上了。又要走一遍work节点2上的四表五链。下面是我的抓包信息,可以佐证:

在这里插入图片描述

18.raw表的PREROUTING和上面的分析一致,没有操作。mangle表的PREROUTING此时也没有什么操作。nat表的PRESOUTING上上面分析的有差别了,就会匹配到

-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx:8080-80" -m tcp --dport 32220 -j KUBE-MARK-MASQ
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/nginx:8080-80" -m tcp --dport 32220 -j KUBE-SVC-DR2DYVPMBY3GPZ5L

因为此时的端口是80了。

19.然后会做路由决策

此时的路由为:
在这里插入图片描述

该路由能精确匹配到最后一条,注意该网卡和pod里面的网卡一一对应,veth pair.
work节点2网卡:
在这里插入图片描述

pod的网卡信息:
在这里插入图片描述

所以该包会从calib992f6c0b80转发到pod里面去。

20.接下来会走到mangle的FORWARD表,但是没有规则可匹配。nat的FORWARD也没有什么好分析的,该包也直接进入mangle的POSTROUTING,但是没有规则。然后到了nat的POSTROUTING,此时需要注意一点的是:

-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN

和前面的分析的差别就在这里,会直接转发到pod里面去了,到此包的旅程就解析完成了。

简单总结

  • 以nodeport的形式的包会被SNAT和DNAT,而且再SNAT之前会被打上很重要的标签0x400/0x400。
  • nodeport的形式的包会走forward链,不会进到INPUT和OUTPUT链。
  • 当nodeport的service的后面有多个终端的时候,也就是多个pod,会按照概率随机走到哪个pod。当流量真正落到的pod的节点不是请求的IP节点的时候,还会通过tunl0这个calico独有的网卡到另外一个节点继续转发。所以当知道pod所在的节点的时候,直接请求该节点的ip,效率会更高,因为会少一些网络的链路操作,当然这种优化个人绝对没有必要。
  • 后续会有其他的情况分析:集群内访问pod的ip,集群内访问service。。。
  • 3
    点赞
  • 2
    收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页
评论 6

打赏作者

zhangshen023

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值