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 |
+-----------------+---------------+-------+----------+-------------+
查看 报文过程
- Node111 向 node113 通告本节点 cidr 的路由 10.244.153.192/26 到 192.168.100.111
- Node111 向 node112 通告本节点 cidr 的路由 10.244.153.192/26 到 192.168.100.111
- Node113 向 node111 通告本节点 cidr 的路由 10.244.84.192/26 到 192.168.100.113
- node112 向 node111 通告本节点 cidr 的路由 10.244.146.192/26 到 192.168.100.112
- node111 向 node113 通告到 10.244.146.192/26 到 192.168.100.112
- 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
- 在 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
- 在 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