目录

cilium-without-Kubernetes调研

概述

根据公司目前部署的 Kubernetes 集群的模式(见下图的k8s-master部分),kube-apiserver 的进程是通过二进制在独立的节点上部署,节点上不会部署 kubelet,也不会有 kube-proxy 等进程,因此是无法识别类似 Service 这样的负载均衡的流量手段。

/cilium-without-kubernetes%E8%B0%83%E7%A0%94/img.png

之前有考虑过能否在 k8s-master 的节点上部署 cilium-agent 来实现在 k8s-master 也能识别类似 Service 这样的负载均衡方式(见下面问号部分),下面是实验和过程的结果。

/cilium-without-kubernetes%E8%B0%83%E7%A0%94/img_1.png

cilium-docker

cilium-docker 是 Cilium 官方在 v1.9 的版本最后一次提到 Cilium without Kubernetes 了,详情可以参考 Is it possible to run Cilium without Kubernetes? #13072。鉴于目前 Cilium 已经发展到 v1.14 的版本了,代码变化很大,官方也已经不推荐这种方式来使用 Cilium 了。

Without Kubernetes

从 issue 中,可以看到跟我们有类似的问题,参考 Cilium Operator panics when starting without Kubernetes #24767,从官方的回复来说,如果不在 Kubernetes 的节点上运行 cilium-agent,可能很难去获取所有节点、网络策略等信息的同步,从官方文档,我们也可以大概了解到相关的限制 Apiserver outside of cluster

测试验证

因为之前分析过 cilium-agent 的启动流程,从 DaemonSet 的角度分析了 cilium-agent 的 Pod 需要经过几个 init-container 的流程才可以正常启动,详细可以参考之前的文章。所以按照之前的分析,我们完全可以在物理机或者一个 cilium-agent 的镜像启动的容器内尝试启动 cilium-agent,并且通过远程 debug 分析 cilium-agent 启动与 Kubernetes 的关联,进一步确认 cilium-agent 能否在非 Kubernetes 的环境下启动和运行。

通过下面的脚本,在某个节点上,通过 docker 启动一个 cilium-agent 的容器,并且执行一些必要的脚本。

 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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# config
cilium build-config
cilium build-config --k8s-kubeconfig-path /root/.kube/config  --source config-map:kube-system/cilium-config

mkdir -p /hostbin /var/run/cilium /sys/fs/bpf /run/cilium/cgroupv2 /opt/cni/bin /etc/cni/net.d /proc/sys/net /proc/sys/kernel
# mount-cgroup

# /hostbin是一个非常临时的目录
# /hostproc相当于/proc
mkdir -p /hostbin
mkdir -p /hostproc
mount --bind /proc /hostproc
mount --bind /opt/cni/bin /hostbin
export BIN_PATH=/opt/cni/bin
export CGROUP_ROOT=/run/cilium/cgroupv2

cp /usr/bin/cilium-mount /hostbin/cilium-mount;
nsenter --cgroup=/hostproc/1/ns/cgroup --mount=/hostproc/1/ns/mnt "${BIN_PATH}/cilium-mount" $CGROUP_ROOT;
rm /hostbin/cilium-mount

# apply-sysctl-overwrites
mkdir -p /hostbin
mkdir -p /hostproc
mount --bind /proc /hostproc
mount --bind /opt/cni/bin /hostbin
export BIN_PATH=/opt/cni/bin

cp /usr/bin/cilium-sysctlfix /hostbin/cilium-sysctlfix;
nsenter --mount=/hostproc/1/ns/mnt "${BIN_PATH}/cilium-sysctlfix";
rm /hostbin/cilium-sysctlfix

# mount-bpf-fs
mount | grep "/sys/fs/bpf type bpf" || mount -t bpf bpf /sys/fs/bpf

# clean-cilium-state
/init-container.sh

# install-cni-binaries
/install-plugin.sh

最后,通过 dlv,在容器内启动 cilium-agent,并且在本地进行远程 debug。

1
/tmp/dlv --listen=:12345 --headless=true --api-version=2 --accept-multiclient exec /tmp/cilium-agent -- --k8s-kubeconfig-path=/root/.kube/config --config-dir=/tmp/cilium/config-map

默认情况下,cilium-agent 走到这里就会陷入循环,循环超时之后,然后报错退出,主要原因是 cilium-agent 需要获取当前节点的信息,而这个信息是通过 Kubernetes 的 API 获取的,因为节点没有部署 kubelet,或者说节点不属于正常的 Kubernetes 集群内的节点,因此这个循环是没法获得节点的信息的。

/cilium-without-kubernetes%E8%B0%83%E7%A0%94/img_2.png

从上面看,如果想在非 Kubernetes 节点部署 cilium-agent,不改配置或者代码是无法达成的,即使我们将 IPv4NodeAddr 设置成节点的 IP,而不是默认的 auto,因为本身这个 IP 没有注册到 Kubernetes 集群,实际上也会报错。

/cilium-without-kubernetes%E8%B0%83%E7%A0%94/img_3.png /cilium-without-kubernetes%E8%B0%83%E7%A0%94/img_4.png /cilium-without-kubernetes%E8%B0%83%E7%A0%94/img_5.png

总结

cilium-agent 需要拿到 Node 的信息来构建 Host Endpoint 等资源,而 Node 的信息会从 Kubernetes 里获取,而且从源码以及 issue 上看,在不修改代码的情况下,没有配置可以绕开这个逻辑,同时需要考虑到,如果修改这个逻辑,需要更多的时间来完善测试和验证才可能把 cilium-agent 部署到 k8s-master 这个节点上,否则出现任何问题,都可能会是灾难级别的网络问题,需要谨慎考虑。

另外还需要考虑到当前集群的 k8s-master 节点的内核版本普遍较低,未来需要考虑升级节点的内核版本,以及考虑将部署的架构进行调整,按照新的版本,将 Kubernetes 的组件通过 static pod 这样的方式进行部署和维护,这样就不需要在 cilium without Kubernetes 上折腾太多时间。

参考资料

  1. Is it possible to run Cilium without Kubernetes? #13072
  2. Cilium Operator panics when starting without Kubernetes #24767
  3. Apiserver outside of cluster
警告
本文最后更新于 2023年11月12日,文中内容可能已过时,请谨慎参考。