CNI 网络流量 4.5 Calico BGP

BGP 介绍

不同于 RIP 、OSPF 协议都是基于 AS 即自治系统内的协议,BGP 是域间路由协议,或者叫做外部网关协议;
BGP 协议只是满足选择一条到达目的网络比较好的路由,而非选择一条最佳路由,BGP 采用了路径向量路由选择协议,它与 RIP 和 OSPF 有很大的差别;路径向量路由,BGP 中数据包送达目标网络时,会生成中途经过所有 AS 的编号列表,即 AS 路径信息访问列表;如果针对一个目标地址有多条路径,BGP 选择较短的路由。
在这里插入图片描述

BGP 支持 CIDR,因此 BGP 的路由表也就应当包括当前目的网络前缀、下一跳路由器,以及到达目的网络所经过的 AS;

在 BGP 刚刚运行时,BGP 的临站是交换整个 BGP 路由表,以后只要在发生变化时更新有新变化的部分即可。这样对节省网络带宽和减少路由器开销有很大好处,这个特性和 OSPF 非常相似。
BGP - 4 主要有下面几类报文类型:

  • OPEN ( 打开 )报文,用来和相邻的 BGP 区域边界路由器建立关系,进行通信初始化。
  • UPDATE ( 更新 ) 报文,用来通告路由信息,以及列出需要更新的多条路由。
  • KEEPALIVE ( 保活 ) 报文,用来周期性的证实临站的连通性。
  • NOTIFICATION ( 通知 ) 报文,用来发送检测到的差错。

如果两个临站属于两个不同的自治系统,而且其中一个临站打算和其他临站进行路由交换的时候,这时候应当有一个路由商量的过程。商量的过程包括临站路由器是否还能够接受额外的路由信息。因此一开始进行商谈的时候应该要先发送 OPEN 报文,如果临站可以接受这种关系,就用 KEEPALIVE 报文响应。

关系建立之后,是需要相互维持的,两个 BGP 边界路由器需要定期交换 KEEPALIVE 报文,一般这个定期的时间就是 30 s。

BGP 边界路由器可以使用 UPDATE 报文来更新路由:包括撤掉以前通知过的路由和增加新的路由。撤销路由时一次可以撤销多条,但是新增路由一个 UPDATE 报文只能增加一条。

BGP 边界路由器不只有一个,而且当某个路由器或者链路出现故障时,由于 BGP 边界路由器可以不止从一个临站获得路由信息,因此很容易选出新的路由。

BGP 分类

BGP 分为 IBGP,EBGP
IBGP:如果 BGP 对等体处于同一自治系统内,被称为 IBGP 对等体,要求 TCP 可达。为了防止环路,BGP 协议规定 BGP 发言者从 IBGP 获得的路由不向它的 IBGP 对等体发布。
EBGP:BGP 对等体处于不同自治系统时,被称为 EBGP 对等体,一般物理直连。BGP Speaker 从 EBGP 对等体获得的路由会向它所有 BGP 对等体通告(包括 EBGP 和 IBGP);同时为了防止环路,他不会将学习到的路由再向原发布者发布。

BGP 报文

在这里插入图片描述
不同类型报文首部都为 19 字节

  • Marker 字段 16字节,用来鉴别收到的 BGP 报文,如果不使用鉴别,标记字段要置为全 1。
  • 长度 2 字节,长度字段指出包括通用首部在内的整个 BGP 报文的长度,以字节为单位,最小值是 19,最大值是 4096.
  • 类型字段的值为 1 到 4,分别对应上面报文的介绍顺序。

OPEN:除了前三个字段,接下来依次是 version (1 字节),My AS 本自治系统号( 2 字节),Hold Time 保持时间 ( 2 字节,以秒计算的保持为临站关系的时间 ),BGP Identifier BGP 标识符 ( 4 字节,路由器的 IP 地址 )在这里插入图片描述
KEEPALIVE:只有 那 19 字节
在这里插入图片描述
UPDATE:报文中的 Unfeasible routes length 表示不可行路由长度,后面是 Withdrawn Routes ,要撤销的路由列表,后面的 Total Path Attribute Length 表示路径属性总长度,后面的 Path attributes 就表示路径属性,最后的 NLRI 标识发出这个报文的网络。
在这里插入图片描述

10.244.153.192/26 下一跳是 192.168.100.111

NOTIFICATION:主要包括差错代码 ( 1 字节 ),差错子代码 ( 1 字节 ) ,后面还有差错数据。
在这里插入图片描述

Calico BGP

一个集群内部 node 使用的 ippool 相同,as 号相同,集群内部使用的 IBGP,当有不同 ippool 的节点加到集群里就需要配置多个 as 号。

[root@node111 bgp]# calicoctl get node -o wide
NAME      ASN       IPV4                 IPV6   
node111   (64512)   192.168.100.111/24          
node112   (64512)   192.168.100.112/24          
node113   (64512)   192.168.100.113/24

Calico 默认开启 nodeToNodeMesh,每两个主机之间都会建立连接

[root@node111 bgp]# calicoctl node status
Calico process is running.

IPv4 BGP status
+-----------------+-------------------+-------+----------+-------------+
|  PEER ADDRESS   |     PEER TYPE     | STATE |  SINCE   |    INFO     |
+-----------------+-------------------+-------+----------+-------------+
| 192.168.100.112 | node-to-node mesh | up    | 09:43:09 | Established |
| 192.168.100.113 | node-to-node mesh | up    | 09:39:04 | Established |
+-----------------+-------------------+-------+----------+-------------+

鉴于集群规模变大后,链接太多,提出 BGP Route Reflectors,选择集群中几台机器作为 BGP Route Reflectors,其他 node 只与 BGP Route Reflectors 进行链接。
改成 BGP RR 模式
关掉 nodeToNodeMesh

apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
  name: default
spec:
  logSeverityScreen: Info
  nodeToNodeMeshEnabled: false
  asNumber: 64512

创建 bgppeer 配置

apiVersion: projectcalico.org/v3
kind: BGPPeer
metadata:
  name: node111
spec:
  nodeSelector: "all()"
  peerSelector: "has(route-reflector)"

给选定节点 node111 加 routeReflectorClusterID 和 label

配置 node111 routeReflectorClusterID
$ calicoctl get node node111 -o yaml > rr-node.yaml
bgp 加 routeReflectorClusterID: 244.0.0.1
$ calicoctl apply -f rr-node.yaml

$ kubectl label node node111 route-reflector=true

在三个节点

# node111
IPv4 BGP status
+-----------------+---------------+-------+----------+-------------+
|  PEER ADDRESS   |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+-----------------+---------------+-------+----------+-------------+
| 192.168.100.112 | node specific | up    | 10:39:33 | Established |
| 192.168.100.113 | node specific | up    | 10:39:33 | Established |
+-----------------+---------------+-------+----------+-------------+

# node112
IPv4 BGP status
+-----------------+---------------+-------+----------+-------------+
|  PEER ADDRESS   |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+-----------------+---------------+-------+----------+-------------+
| 192.168.100.111 | node specific | up    | 10:39:33 | Established |
+-----------------+---------------+-------+----------+-------------+

# node113
IPv4 BGP status
+-----------------+---------------+-------+----------+-------------+
|  PEER ADDRESS   |   PEER TYPE   | STATE |  SINCE   |    INFO     |
+-----------------+---------------+-------+----------+-------------+
| 192.168.100.111 | node specific | up    | 10:39:33 | Established |
+-----------------+---------------+-------+----------+-------------+

查看 报文过程
在这里插入图片描述

  1. Node111 向 node113 通告本节点 cidr 的路由 10.244.153.192/26 到 192.168.100.111
  2. Node111 向 node112 通告本节点 cidr 的路由 10.244.153.192/26 到 192.168.100.111
  3. Node113 向 node111 通告本节点 cidr 的路由 10.244.84.192/26 到 192.168.100.113
  4. node112 向 node111 通告本节点 cidr 的路由 10.244.146.192/26 到 192.168.100.112
  5. node111 向 node113 通告到 10.244.146.192/26 到 192.168.100.112
  6. node111 向 node112 通告到 10.244.84.192/26 到 192.168.100.113
    5-6 步 node111 作为 RR 的实现,node112 和 node113 不直接 bgp

部署

如果环境是 ipip,修改成 bgp

需要修改

1. 修改 calico-node
# kubectl edit ds calico-node -n kube-system
- name: CALICO_IPV4POOL_IPIP
value: Always
- name: CALICO_AUTODETECTION_METHOD
value: interface=eth0

2. 修改 ippool,需要把 ipipMode 从 Always 修改成为 Never(执行下面命令修改 ipipMode)
# kubectl edit ippool
ipipMode: Never

在这里插入图片描述

在这里插入图片描述
可以看到,在宿主机上有到每个 pod IP 的路由指向 veth 设备
到对端节点网段的路由对端 业务网卡的 ip

流量分析

Pod 间

  • 同 node 不同 pod 之间
    pod1 <-> pod2
  1. 在 pod1 eth0 抓包:
22:49:09.291741 de:f9:e6:21:f3:22 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.214 > 10.244.153.216: ICMP echo request, id 5409, seq 12, length 64
22:49:09.291804 ee:ee:ee:ee:ee:ee > de:f9:e6:21:f3:22, ethertype IPv4 (0x0800), length 98: 10.244.153.216 > 10.244.153.214: ICMP echo reply, id 5409, seq 12, length 64

pod1 中下一跳都是 169.254.1.1,且目的 mac 是 ee:ee:ee:ee:ee:ee
2. 在 host 端 calice0906292e2 抓包不变
3. 匹配主机路由 10.244.153.216 dev calibd2348b4f67 scope link 和 ip neighbor 10.244.153.216 dev calibd2348b4f67 lladdr 36:42:dd:fc:5a:a1 REACHABLE, 在 calibd2348b4f67 抓包

22:50:42.475843 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 98: 10.244.153.214 > 10.244.153.216: ICMP echo request, id 5409, seq 103, length 64
22:50:42.475869 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.216 > 10.244.153.214: ICMP echo reply, id 5409, seq 103, length 64
  1. 在 pod2 内 eth0 抓包:
    22:50:42.475843 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 98: 10.244.153.214 > 10.244.153.216: ICMP echo request, id 5409, seq 103, length 64
    22:50:42.475869 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.216 > 10.244.153.214: ICMP echo reply, id 5409, seq 103, length 64
  • 不同 node 上 pod 之间
    pod1 访问 pod3
    在 veth host 端抓包
22:51:50.782553 de:f9:e6:21:f3:22 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.214 > 10.244.146.212: ICMP echo request, id 60131, seq 20, length 64
22:51:50.783496 ee:ee:ee:ee:ee:ee > de:f9:e6:21:f3:22, ethertype IPv4 (0x0800), length 98: 10.244.146.212 > 10.244.153.214: ICMP echo reply, id 60131, seq 20, length 64

看 主机路由 10.244.146.192/26 via 192.168.100.112 dev ens10 proto bird 下一跳是 192.168.100.112
在 ens10 上抓包,可以看到 mac 地址是业务网卡两个端点的 mac,报文没有任何变化。

22:53:04.149175 52:54:00:dc:c7:b4 > 52:54:00:d3:bf:21, ethertype IPv4 (0x0800), length 98: 10.244.153.214 > 10.244.146.212: ICMP echo request, id 60131, seq 93, length 64
22:53:04.149870 52:54:00:d3:bf:21 > 52:54:00:dc:c7:b4, ethertype IPv4 (0x0800), length 98: 10.244.146.212 > 10.244.153.214: ICMP echo reply, id 60131, seq 93, length 64

在 对面机器上的报文路径与之对称

Node 到 Pod

  • Node 到本 node 上的 pod
    在 node111 ping pod1
    在 veth host 端抓包,根据路由 10.244.153.216 dev calibd2348b4f67 scope link,生成报文时拿默认路由网卡的 ip 做源地址
22:56:11.243903 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 98: 172.18.22.111 > 10.244.153.216: ICMP echo request, id 4, seq 7, length 64
22:56:11.243930 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.216 > 172.18.22.111: ICMP echo reply, id 4, seq 7, length 64

在 veth 内 eth0 抓包

22:56:11.243903 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 98: 172.18.22.111 > 10.244.153.216: ICMP echo request, id 4, seq 7, length 64
22:56:11.243930 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 98: 10.244.153.216 > 172.18.22.111: ICMP echo reply, id 4, seq 7, length 64
  • Node 到其他 node 上的 pod
    node111 到 pod3
    在 node111 ens10 抓包,根据路由 10.244.146.192/26 via 192.168.100.112 dev ens10 proto bird
21:10:18.124555 52:54:00:dc:c7:b4 > 52:54:00:d3:bf:21, ethertype IPv4 (0x0800), length 118: 192.168.100.111 > 192.168.100.112: 10.244.153.192 > 10.244.146.205: ICMP echo request, id 11, seq 62, length 64
21:10:18.129910 52:54:00:d3:bf:21 > 52:54:00:dc:c7:b4, ethertype IPv4 (0x0800), length 118: 192.168.100.112 > 192.168.100.111: 10.244.146.205 > 10.244.153.192: ICMP echo reply, id 11, seq 62, length 64

Pod 到 service

# kubectl get svc
NAME            TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
nginx-service   ClusterIP   10.107.161.255   <none>        8080/TCP   2s
# kubectl get endpoints
NAME            ENDPOINTS                             AGE
nginx-service   10.244.146.212:80,10.244.153.216:80   5s
  • Pod 访问 service clusterIP
    在 pod1 veth 对抓包,目的地之为 svcIP
22:58:56.371127 de:f9:e6:21:f3:22 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.153.214.33430 > 10.107.161.255.webcache: Flags [S], seq 1879858029, win 64240, options [mss 1460,sackOK,TS val 1064877586 ecr 0,nop,wscale 7], length 0
22:58:56.371341 ee:ee:ee:ee:ee:ee > de:f9:e6:21:f3:22, ethertype IPv4 (0x0800), length 74: 10.107.161.255.webcache > 10.244.153.214.33430: Flags [S.], seq 46666836, ack 1879858030, win 65160, options [mss 1460,sackOK,TS val 512837314 ecr 1064877586,nop,wscale 7], length 0

在 pod2 veth 对抓包,源地址为 主机默认路由网卡 ip,目的地址为 pod2,目的端口为 80

22:59:25.194941 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 74: 10.244.153.214.39958 > 10.244.153.216.http: Flags [S], seq 3052450619, win 64240, options [mss 1460,sackOK,TS val 1064906410 ecr 0,nop,wscale 7], length 0
22:59:25.194996 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.153.216.http > 10.244.153.214.39958: Flags [S.], seq 3853432263, ack 3052450620, win 65160, options [mss 1460,sackOK,TS val 512866138 ecr 1064906410,nop,wscale 7], length 0

去 service dnat 成后端 IP 转到 pod2,pod2 回复 pod1,再 snat 成 svcIP。
后端为 跨节点的 pod3 和上面相同

Node 到 service

  • Node 访问 service clusterIP
    本节点 pod 时
    Dnat 成 pod2 ip,根据默认路由网卡 IP,构造报文
22:59:56.156054 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 74: 172.18.22.111.49871 > 10.244.153.216.http: Flags [S], seq 1440047978, win 65495, options [mss 65495,sackOK,TS val 2095085657 ecr 0,nop,wscale 7], length 0
22:59:56.156112 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.153.216.http > 172.18.22.111.49871: Flags [S.], seq 1382921424, ack 1440047979, win 65160, options [mss 1460,sackOK,TS val 3307386812 ecr 2095085657,nop,wscale 7], length 0

跨节点 pod 时
Dnat 成 pod3 ip,根据路由用 10.244.146.192/26 via 192.168.100.112 dev ens10 proto bird 的 网关去请求

23:00:18.641689 ee:ee:ee:ee:ee:ee > be:9d:c7:f8:b7:61, ethertype IPv4 (0x0800), length 74: 192.168.100.111.12138 > 10.244.146.212.http: Flags [S], seq 417839269, win 65495, options [mss 65495,sackOK,TS val 2095108142 ecr 0,nop,wscale 7], length 0
23:00:18.641775 be:9d:c7:f8:b7:61 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.146.212.http > 192.168.100.111.12138: Flags [S.], seq 3468595817, ack 417839270, win 65160, options [mss 1460,sackOK,TS val 3469987261 ecr 2095108142,nop,wscale 7], length 0

外部到 svc

default    nginx-service   NodePort    10.107.161.255   <none>   8080:30080/TCP 

在主机被访问 IP 网卡抓包

23:04:01.185278 52:54:00:d0:eb:12 > 52:54:00:ba:dc:62, ethertype IPv4 (0x0800), length 74: 172.18.22.108.45618 > 172.18.22.111.30080: Flags [S], seq 662387376, win 64240, options [mss 1460,sackOK,TS val 14241135 ecr 0,nop,wscale 7], length 0
23:04:01.185529 52:54:00:ba:dc:62 > 52:54:00:d0:eb:12, ethertype IPv4 (0x0800), length 74: 172.18.22.111.30080 > 172.18.22.108.45618: Flags [S.], seq 1190337779, ack 662387377, win 65160, options [mss 1460,sackOK,TS val 3307631841 ecr 14241135,nop,wscale 7], length 0
Chain KUBE-NODE-PORT (1 references)
target     prot opt source               destination         
KUBE-MARK-MASQ  tcp  --  0.0.0.0/0            0.0.0.0/0            /* Kubernetes nodeport TCP port for masquerade purpose */ match-set KUBE-NODE-PORT-TCP dst

Masquerade 转为

23:04:01.185434 ee:ee:ee:ee:ee:ee > 36:42:dd:fc:5a:a1, ethertype IPv4 (0x0800), length 74: 172.18.22.111.8408 > 10.244.153.216.http: Flags [S], seq 662387376, win 64240, options [mss 1460,sackOK,TS val 14241135 ecr 0,nop,wscale 7], length 0
23:04:01.185484 36:42:dd:fc:5a:a1 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.153.216.http > 172.18.22.111.8408: Flags [S.], seq 1190337779, ack 662387377, win 65160, options [mss 1460,sackOK,TS val 3307631841 ecr 14241135,nop,wscale 7], length 0

如果 后端不在本节点
Masquerade 转为 192.168.100.111 (根据默认路由决定)

23:04:59.183752 ee:ee:ee:ee:ee:ee > be:9d:c7:f8:b7:61, ethertype IPv4 (0x0800), length 74: 192.168.100.111.36047 > 10.244.146.212.http: Flags [S], seq 3939988989, win 64240, options [mss 1460,sackOK,TS val 14299130 ecr 0,nop,wscale 7], length 0
23:04:59.183829 be:9d:c7:f8:b7:61 > ee:ee:ee:ee:ee:ee, ethertype IPv4 (0x0800), length 74: 10.244.146.212.http > 192.168.100.111.36047: Flags [S.], seq 2347549368, ack 3939988990, win 65160, options [mss 1460,sackOK,TS val 3470267803 ecr 14299130,nop,wscale 7], length 0
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值