博客园出海记-K8S集群优化:一次命中注定的失败

在上一篇出海记博文提到,本想试试 Cilium 的一个高科技,却试验失败。

这个高科技就是,Cilium 可以实现一个"魔法",给 Kubernetes LoadBalancer Service 分配一个虚拟 IP,当内网中的机器访问这个 IP 时,Cilium 会选举1台节点服务器,填上它的 MAC 地址,瞒天过海地与请求方进行通信。如果用上这个科技,就可以用 Kubernetes Service 取代阿里云负载均衡作为 control-plane 的负载均衡,省钱又环保。

上次试验失败后,心里有些不甘心,又继续折腾。本想着成功后能发篇博文分享胜利经验,没想到现实很骨感------失败其实是注定的,因为忽略了一个关键点------云上的网络是一个虚拟世界,基于 ARP 协议的巧妙玩法,在现实(虚拟现实)面前行不通。

于是,这篇原本打算分享胜利经验的出海记博文被迫降级分享失败经验。

以下是试验 Cilium L2 Announcements 失败过程的分享。

首先,在阿里云专有网络 VPC 中预留 172.21.48.240/28 网段给 Cilium LoadBalancer 使用

接着,更新 cilium 的部署,开启 cilium 与负载均衡相关的特性

shell 复制代码
cilium upgrade --version 1.18.1 \
  --namespace kube-system \
  --set bpf.masquerade=true \
  --set kubeProxyReplacement=true \
  --set l2announcements.enabled=true \
  --set l2NeighDiscovery.enabled=true \
  --set externalIPs.enabled=true

相比之前的 cilium 部署,多了3个配置选项

shell 复制代码
--set l2announcements.enabled=true
--set l2NeighDiscovery.enabled=true
--set externalIPs.enabled=true

部署完成后,检查一下配置是否生效

shell 复制代码
~ # cilium config view | grep enable-l2
enable-l2-announcements                           true
enable-l2-neigh-discovery                         true
~ # kubectl -n kube-system exec ds/cilium -- cilium-dbg status --verbose | grep externalIPs                                                                                                        2 ↵
- externalIPs:    Enabled

都生效了。

接下来,部署用于转发请求到 api-server 的 LoadBalancer Service,清单文件 lb-service.yaml 内容如下

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  annotations:
    io.cilium/lb-ipam-ips: 172.21.48.240
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-api
  namespace: kube-system
spec:
  selector:
    component: kube-apiserver
    tier: control-plane
  ports:
  - name: https
    port: 6443
    protocol: TCP
    targetPort: 6443
  type: LoadBalancer

下单部署这个 service

shell 复制代码
# kubectl apply -f lb-service.yaml    
service/kube-api created

查看部署情况

shell 复制代码
~ # kubectl get svc --field-selector spec.type=LoadBalancer -n kube-system
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
kube-api   LoadBalancer   10.107.192.67   <pending>     6443:31920/TCP   31s

这个 kube-api service 监听于 6443 端口,将转发请求给 control-plane 的 api-server,看上去是一个称职的 control-plane 负载均衡,但它现在只是一个摆设,中看不中用,因为只有 CLUSTER-IP,没有 EXTERNAL-IP,只能在 k8s 集群内部访问,而要作为 control-plane 负载均衡,需要能通过节点服务器所在的网络访问。

再接下来,部署 CiliumLoadBalancerIPPool,清单中 cidr 对应的是阿里云 VPC 预留的网段,清单文件 lb-ip-pool.yaml 内容如下

yaml 复制代码
apiVersion: "cilium.io/v2alpha1"
kind: CiliumLoadBalancerIPPool
metadata:
  name: api-server
  annotations:
spec:
  blocks:
  - cidr: "172.21.48.240/28"

下单部署

shell 复制代码
~ # kubectl apply -f lb-ip-pool.yaml
ciliumloadbalancerippool.cilium.io/api-server created

查看部署结果

shell 复制代码
~ # kubectl get CiliumLoadBalancerIPPool
NAME         DISABLED   CONFLICTING   IPS AVAILABLE   AGE
api-server   false      False         16              77s
~ # kubectl get svc --field-selector spec.type=LoadBalancer -n kube-system
NAME       TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)          AGE
kube-api   LoadBalancer   10.107.192.67   172.21.48.240   6443:31920/TCP   17m

这时你会发现 kube-api service 的 EXTERNAL-IP 被分配了一个节点所在网络(阿里云VPC)的 IP 地址,这个 IP 是通过部署清单中的 io.cilium/lb-ipam-ips: 172.21.48.240 指定的,如果没有指定,会从 CiliumLoadBalancerIPPool cidr 指定的网段中分配一个。

我们试试在其中一台节点服务器上访问这个 IP 与 6443 端口

shell 复制代码
~ # curl -k https://172.21.48.240:6443/livez
ok

竟然可以访问了,我们只是部署了 CiliumLoadBalancerIPPool,其他什么也没做,是 cilium 根据我下的菜单(清单文件),知道我的口味,把一切都包办了。

现在,k8s 集群中的任一节点都可以通过 172.21.48.240 访问负载均衡,不管是 control-plane 还是 worker 节点,

但仅仅这样是不够的,比如向集群加入新节点或者节点服务器重启时, 怎么访问这台负载均衡?

我们还需要再下一个菜单,开启 cilium 的魔法能力 ------ L2 Announcements,让同一个内网中没有加入集群的服务器也能访问负载均衡,清单文件 lb-l2-announcements.yaml 内容如下

yaml 复制代码
apiVersion: "cilium.io/v2alpha1"
kind: CiliumL2AnnouncementPolicy
metadata:
  name: control-plane
spec:
  serviceSelector:
    matchLabels:
      component: kube-apiserver
      tier: control-plane
  nodeSelector:
    matchExpressions:
    - key: node-role.kubernetes.io/control-plane
      operator: Exists
  loadBalancerIPs: true
  externalIPs: true

注:serviceSelector 需要对应之前部署的 LoadBalancer Service

下单部署

shell 复制代码
~ # kubectl apply -f lb-l2-announcements.yaml 
ciliuml2announcementpolicy.cilium.io/control-plane created

查看部署情况

shell 复制代码
# kubectl get CiliumL2AnnouncementPolicy                                                          
NAME            AGE
control-plane   29s

查看 lease 是否生效

shell 复制代码
~ # kubectl -n kube-system get lease | grep "cilium-l2announce"
cilium-l2announce-kube-system-kube-api   kube-cp-03 

查看 l2-announce 是否正常

shell 复制代码
~ # kubectl -n kube-system get pod -l 'app.kubernetes.io/name=cilium-agent' -o wide | grep kube-cp-03                                                                              1 ↵
cilium-sgjv9   1/1     Running   8 (21m ago)   14d   172.21.49.58   kube-cp-03   <none>           <none>
shell 复制代码
~# kubectl -n kube-system exec pod/cilium-sgjv9 -- cilium-dbg shell -- db/show l2-announce
IP              NetworkInterface
172.21.48.240   eth0

确认 L2 Announcements 已部署成功。

找一台内网中没有加入 k8s 集群的服务器测试一下,看是否可以访问负载均衡的 6443 端口

shell 复制代码
~ # telnet 172.21.48.240 6443
Trying 172.21.48.240...

连不上,L2 Announcements 没起作用。

用 arping 命令测试一下 APR 解析是否正常

shell 复制代码
~ # arping 172.21.48.240
ARPING 172.21.48.240
58 bytes from ee:ff:ff:ff:ff:ff (172.21.48.240): index=0 time=59.783 usec
58 bytes from ee:ff:ff:ff:ff:ff (172.21.48.240): index=1 time=69.028 usec
58 bytes from ee:ff:ff:ff:ff:ff (172.21.48.240): index=2 time=88.491 usec

ARP 解析虽然成功了,但却是一个很奇怪的 MAC 地址 ee:ff:ff:ff:ff:ff。一开始以为是 cilium-agent 在搞鬼,但后来试着 arping 一个根本不存在的内网 IP,竟然也是这个地址!原来,阿里云 VPC 中的任何内网 IP 都会被解析到它。这时才意识到,问题应该与身在云上有关。

后来在网上找到一篇博文 阿里云ecs服务器arp映射表与实际mac地址不一致的疑问 终于真相大白:

发工单后回答说:

ecs底层是虚拟化的网络,不是传统的物理网络。表项的学习是通过arp代理实现,为了避免大量ARP学习影响组件性能,所以看到的都是同一个MAC ee:ff:ff:ff:ff:ff ,是正常的现象。

原来,阿里云 VPC 的虚拟网络并未完全遵循标准的 ARP 协议,Cilium 巧妙的 L2 Announcements 方案如同"无根之木",在云平台这个虚拟世界的"物理定律"下,其失效自然是注定的。

参考:

相关推荐
spider_xcxc1 小时前
K8s 部署学习笔记
docker·容器·kubernetes·云计算·k8s
ShirleyWang0122 小时前
Day02 K3s NGF(Nginx Gateway Fabric)单 Worker 环境网关更新与故障处置 SOP
linux·服务器·python·k8s·k3s
ShirleyWang0123 小时前
DAY01 K3s 私有化部署排障复盘与 SOP
linux·服务器·k8s·k3s·企业部署
XUHUOJUN4 天前
AKS 不是安装在 Windows Server 上,而是运行在 Windows Server 之上的 Azure 平台能力
windows·架构·k8s·azure local·azure stack
Geek-Chow4 天前
Connecting kubectl to a Private EKS Cluster Over an Internal Domain
kubernetes·k8s·aws
spider_xcxc6 天前
Docker Compose 容器通信详解:同一个 Compose 文件才能互通吗?
docker·容器·k8s·容器化·容器网络
欢醉11 天前
k8s调用服务异常cannot allocate memory
kubernetes·k8s
万里侯14 天前
GitOps 漂移检测:集群里改了配置,Git 还以为一切正常
微服务·容器·k8s
spider_xcxc15 天前
云上网络基石(阿里云):深入解读阿里云VPC及其应用生态
网络·阿里云·云计算·k8s·运维开发·虚拟化
weixin_4399306416 天前
Kubernetes(K8s)入门实践
云原生·容器·kubernetes·k8s