Cilium的LoadBalancer的测试

目录

传统上云厂商都有自己的 Service LoadBalancer,可以直接将 Kubernetes 的工作负载暴露在公网或者内网中,而一般企业内部自建的 Kubernetes 集群是无法使用 LoadBalancer 的,并且企业内部在使用 Kubernetes 之前,一般都有成熟的内部 LoadBalancer 体系,基于 Nginx 或者 HAProxy 等等,所以大部分企业都会考虑将当前正在使用的 LoadBalancer 方案直接移植到企业自建的 Kubernetes 集群中。

理论上实现这一套并不难。

而在开源的选择上,还有更多,比如 Metallb,就是为这样的场景而生的,但本文不准备细聊 Metallb 了,而是聊聊在这个领域上的新秀 Cilium。Cilium 是行业的 CNI 标准之一了,也正在覆盖越来越多的容器网络和物理网络之间的场景,本文准备说说,如何在 Kubernetes 集群中,通过 Cilium 来为工作负载创建 LoadBalancer 类型的 Service。

参考部署的前提条件,你需要一套 Kubernetes 集群,最简单的可以通过 kind 等工具起一套,复杂一点的通过 kubeadm 部署也是可以的,有一个功能完整的集群之后,就不要部署 Cilium 了,可以参考下面的 helm 命令。

1
2
3
4
5
6
# 部署命令
helm install cilium . --namespace=kube-system --set k8sServiceHost=192.168.1.201 --set k8sServicePort=6443 --version v1.16.1 --set ipv4NativeRoutingCIDR="10.0.0.0/8"  --set cluster.id=1  --set cluster.name=cluster1 --set kubeProxyReplacement=true --set l2announcements.enabled=true
# 查看安装情况 
kubectl -n kube-system exec ds/cilium -- cilium-dbg config --all | grep EnableL2Announcements
kubectl -n kube-system exec ds/cilium -- cilium-dbg config --all | grep KubeProxyReplacement
kubectl -n kube-system exec ds/cilium -- cilium-dbg config --all | grep EnableExternalIPs

其中 CiliumLoadBalancerIPPool 和 CiliumL2AnnouncementPolicy 都是基于本人的局域网环境的,首先这两个 IP 在我的局域网内都不会被 DHCP 的方式被自动分配,然后 eno1 是我节点网卡的名称。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: "pool"
spec:
  blocks:
    - start: "192.168.1.15"
      stop: "192.168.1.16"
---      
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
  name: l2policy
spec:
  loadBalancerIPs: true
  interfaces:
    - eno1

之后通过下面的命令,创建一个 Pod,以及暴露 Pod 的 80 端口。

1
2
3
4
5
# 查看ippools
kubectl get ippools
# 创建Pod和Service
kubectl run centos --image runzhliu/network-multitool:20240301 --command -- python3 -m http.server 80
kubectl expose pod centos --type=LoadBalancer --name=centos-service --port=80 --target-port=80

然后查看 Service 是否正常创建,并且分配好 LoadBalancer 的 IP,需要注意这里的 NodePort 的含义,是因为无论是 Metallb 还是 Cilium 的 LB,都是基于 NodePort 实现的,所以这里的 NodePort 是有标注的。

1
2
3
[root@node1 cilium]# k get svc
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                  AGE
centos-service           LoadBalancer   10.98.58.16      192.168.1.16   80:30157/TCP             72m

观察一下 Cilium LB 开启之后,关于 LB 的 IP 是怎么实现 ARP 响应的。

1
2
3
4
5
6
7
# 可以用wireshark
yum install -y wireshark
tshark -i eno1 arp and host 192.168.1.202

# 清空记录
ip neigh flush all
ip neigh 

下面是节点、Pod、Service 的现况。

1
2
3
4
5
6
7
8
9
[root@node1 cilium]# k get no
NAME    STATUS   ROLES           AGE    VERSION
node1   Ready    control-plane   118d   v1.30.4
[root@node1 cilium]# k get pods
NAME                                      READY   STATUS             RESTARTS         AGE
centos                                    1/1     Running            0                170m
[root@node1 cilium]# k get svc
NAME                     TYPE           CLUSTER-IP       EXTERNAL-IP    PORT(S)                  AGE
centos-service           LoadBalancer   10.98.58.16      192.168.1.16   80:30157/TCP             160m

现在我们先清理 node2 上的 ARP 记录,然后在 node1 上通过 wireshark 查看 ARP 的请求和返回,然后在 node2 上请求这个 EXTERNAL-IP。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# node2操作
[root@node2 ~]# ip neigh flush all
[root@node2 ~]# ip neigh
192.168.1.200 dev enp7s0 lladdr 00:e0:4c:25:04:68 REACHABLE

# node1操作
[root@node1 cilium]# tshark -i eno1 arp and host 192.168.1.202

# node2操作
[root@node2 ~]# curl 192.168.1.16

# node1查看到ARP记录
[root@node1 cilium]# tshark -i eno1 arp and host 192.168.1.202
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eno1'
    1 0.000000000 00:e2:69:6b:77:28 → Broadcast    ARP 60 Who has 192.168.1.16? Tell 192.168.1.202
    2 0.000026903 00:e2:69:69:5c:ed → 00:e2:69:6b:77:28 ARP 60 192.168.1.16 is at 00:e2:69:69:5c:ed
    3 0.000330687 00:e2:69:69:5c:ed → Broadcast    ARP 42 Who has 192.168.1.202? Tell 192.168.1.201
    4 0.000447908 00:e2:69:6b:77:28 → 00:e2:69:69:5c:ed ARP 60 192.168.1.202 is at 00:e2:69:6b:77:28
    
# node2查看ARP记录
[root@node2 ~]# arp -n
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.1.201            ether   00:e2:69:69:5c:ed   C                     eno1
192.168.1.16             ether   00:e2:69:69:5c:ed   C                     eno1

从上面的 ARP 记录看,192.168.1.16 已经被 node1 响应,并且 192.168.1.16 的 MAC 地址被关联到了 node1 eno1 网卡的 Mac 地址,这样一来,局域网内就知道 192.168.1.16 应该要发去哪里了。

  1. l2-announcements