在 Cilium CNI 集群上运行 vCluster 虚拟集群
上周在 KubeCon China 2024 大会上,我和社区伙伴们作为志愿者在 Cilium 项目展台与用户交流。有位用户询问 Cilium 是否能与 vCluster 集成,当时未能给出明确答复,特地回来后进行了测试。
答案是:在最新的 vCluster v0.20 中容器网络没有问题,但如果要在虚拟集群上使用 Cilium 的网络策略,则会受到限制。
背景
什么是虚拟集群
虚拟集群是一种在现有 Kubernetes 集群(Host 集群)之上创建的轻量级 Kubernetes 集群。它提供了一个独立的 Kubernetes 环境,但实际上是通过共享 Host 集群的资源来实现的。这种方式允许多个虚拟集群运行在同一个物理集群中,为不同的团队或项目提供隔离的开发、测试和生产环境,而不需要为每个环境创建单独的物理集群。
为什么要使用虚拟集群
- 多租户隔离:在一个物理集群中为不同团队或项目提供独立的 Kubernetes 环境,确保资源和安全性隔离。
- 开发与测试便利:开发人员可以快速创建和销毁与生产环境类似的虚拟集群,用于独立开发、测试和调试。
- 资源优化:通过共享基础设施提高资源利用率,减少硬件需求和管理开销。
- 灵活管理:虚拟集群允许独立配置、运行不同版本的 Kubernetes,有助于版本控制和灵活调整集群策略。
- 成本降低:减少维护多个物理集群的需求,优化资源分配,降低整体成本。
vCluster 简介
vCluster 是一种轻量级的虚拟集群解决方案,允许你在 Kubernetes 集群中创建和管理虚拟的 Kubernetes 集群。它是由 Loft Labs 开发的,用于多租户环境、开发测试环境以及简化复杂的 Kubernetes 集群管理。
关于 vCluster 的更多信息,后面我会再写一篇深入介绍下。
Cilium CNI 简介
Cilium 是一个基于 eBPF(extended Berkeley Packet Filter)技术的容器网络接口(CNI)插件,旨在为 Kubernetes 和其他容器平台提供高效、安全的网络和负载均衡功能。Cilium 的核心目标是通过使用 eBPF 实现更高性能、更灵活的网络数据处理,并简化网络安全策略的管理。在之前的文章 Kubernetes 网络学习之 Cilium 与 eBPF 和 深入探索 Cilium 的工作机制 中曾介绍过
接下来我们看下如何在 Cilium CNI 集群上运行 vCluster 虚拟集群。
环境搭建
准备 Host 集群
准备 Kubernetes 集群,使用 v1.28.13+k3s1
版本的 K3s 作为 Host 集群,禁用 flannel。
export INSTALL_K3S_VERSION=v1.28.13+k3s1
curl -sfL https://get.k3s.io | sh -s - --disable traefik --disable metrics-server --flannel-backend=none --cluster-cidr=10.42.0.0/16 --disable-network-policy --write-kubeconfig-mode 644 --write-kubeconfig ~/.kube/config
集群安装后,查看 Pod 状态。Pending
状态是因为没有 CNI 插件。
kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-6799fbcd5-h8cfh 0/1 Pending 0 41s
kube-system local-path-provisioner-5ccc7458d5-scfq4 0/1 Pending 0 41s
安装 Cilium CNI
安装 Cilium。
curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/latest/download/cilium-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-amd64.tar.gz /usr/local/bin
rm cilium-linux-amd64.tar.gz{,.sha256sum}
目前最新的 stable 版本未 v1.16.1
cilium version
cilium-cli: compiled with go1.23.0 on linux/amd64
cilium image (default): v1.16.0
cilium image (stable): v1.16.1
cilium image (running): unknown. Unable to obtain cilium version. Reason: release: not found
安装 Cilium 到集群:
cilium install
等待 Cilium 安装完成。
cilium status --wait
/¯¯\
/¯¯\__/¯¯\ Cilium: 2 warnings
/¯¯\
/¯¯\__/¯¯\ Cilium: OK
\__/¯¯\__/ Operator: OK
/¯¯\__/¯¯\ Envoy DaemonSet: OK
\__/¯¯\__/ Hubble Relay: disabled
\__/ ClusterMesh: disabled
DaemonSet cilium Desired: 1, Ready: 1/1, Available: 1/1
Deployment cilium-operator Desired: 1, Ready: 1/1, Available: 1/1
DaemonSet cilium-envoy Desired: 1, Ready: 1/1, Available: 1/1
Containers: cilium Running: 1
cilium-envoy Running: 1
cilium-operator Running: 1
Cluster Pods: 2/2 managed by Cilium
Helm chart version:
Image versions cilium-operator quay.io/cilium/operator-generic:v1.16.0@sha256:d6621c11c4e4943bf2998af7febe05be5ed6fdcf812b27ad4388f47022190316: 1
cilium quay.io/cilium/cilium:v1.16.0@sha256:46ffa4ef3cf6d8885dcc4af5963b0683f7d59daa90d49ed9fb68d3b1627fe058: 1
cilium-envoy quay.io/cilium/cilium-envoy:v1.29.7-39a2a56bbd5b3a591f69dbca51d3e30ef97e0e51@sha256:bd5ff8c66716080028f414ec1cb4f7dc66f40d2fb5a009fff187f4a9b90b566b: 1
待 Cilium 安装完成后,所有的 Pod 都正常运行。
kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system cilium-envoy-t2vbd 1/1 Running 0 75s
kube-system cilium-gfk5r 1/1 Running 0 75s
kube-system cilium-operator-885db8fcf-kp2dr 1/1 Running 0 75s
kube-system coredns-6799fbcd5-4xmcd 1/1 Running 0 94s
kube-system local-path-provisioner-5ccc7458d5-scfq4 1/1 Running 0 94s
安装 vCluster
这里使用 vCluster CLI 来管理虚拟集群,首先安装 vCluster CLI。
curl -L -o vCluster "https://github.com/loft-sh/vCluster/releases/latest/download/vCluster-linux-amd64" && sudo install -c -m 0755 vCluster /usr/local/bin && rm -f vCluster
最新的版本为 vCluster
vCluster version
vCluster version 0.20.0
查看 Host 集群的命名空间。
kubectl get ns
NAME STATUS AGE
default Active 2m8s
kube-node-lease Active 2m8s
kube-public Active 2m8s
kube-system Active 2m8s
虚拟集群
创建虚拟集群
使用 vCluster create NAME
创建名为 vc-a
的虚拟集群。
vCluster create vc-a
07:02:38 info Creating namespace vCluster-vc-a
07:02:38 info Create vCluster vc-a...
07:02:38 info execute command: helm upgrade vc-a /tmp/vCluster-0.20.0.tgz-759956343 --create-namespace --kubeconfig /tmp/1343191442 --namespace vCluster-vc-a --install --repository-config='' --values /tmp/3416084562
07:02:39 done Successfully created virtual cluster vc-a in namespace vCluster-vc-a
07:02:44 info Waiting for vCluster to come up...
07:02:55 warn vCluster is waiting, because vCluster pod vc-a-0 has status: Init:2/3
07:03:15 done vCluster is up and running
07:03:15 done Switched active kube context to vCluster_vc-a_vCluster-vc-a_default
- Use `vCluster disconnect` to return to your previous kube context
- Use `kubectl get namespaces` to access the vCluster
vCluster 会在 Host 集群上为虚拟集群创建一个独立的命名空间,比如这里的 vCluster-vc-a
就是虚拟集群 vc-a
在 Host 集群上的命名空间。
kubectl get ns
NAME STATUS AGE
default Active 7m51s
kube-node-lease Active 7m51s
kube-public Active 7m51s
kube-system Active 7m51s
vCluster-vc-a Active 2m8s
在该命名空间下,有 vCluster 的控制面和 coredns。默认情况下,vCluster 的组件都是 StatefulSet 单实例运行。这种单实例架构适合开发环境或者 CI/CD 环境,但生产环境建议使用 高可用方案 部署。
kubectl get po -n vCluster-vc-a
NAME READY STATUS RESTARTS AGE
coredns-5c7466bb88-zgqqk-x-kube-system-x-vc-a 1/1 Running 0 2m19s
vc-a-0 1/1 Running 0 2m49s
这里 vc-a-0
就是虚拟集群 vc-a
的控制面实例,在这个实例中包含了:
- Kubernetes API server:Kubernetes API 服务器,它是虚拟集群内所有 API 请求的管理接口。
- controller manager:控制器管理器,用于维护 pod 等 Kubernetes 资源的状态,确保它们匹配所需的配置。
- data store:数据存储,是 API 存储所有资源的数据存储。默认使用内置的 SQLite,通过 PVC 做持久化存储。
- syncer:同步器,用于同步虚拟集群和主机集群之间的资源,并完成主机基础设施上的工作负载管理。
- scheduler:调度程序,它是调度工作负载的可选组件。默认情况下,vCluster 重用主机集群调度程序以节省计算资源。如果需要添加节点标签或污点来控制调度、排出节点或利用自定义调度程序,可以启用虚拟调度程序。
使用同样的方式,我们再创建一个虚拟集群 vc-b
:
vCluster create vc-b
查看已有的虚拟集群。
vCluster list
NAME | NAMESPACE | STATUS | VERSION | CONNECTED | AGE
-------+---------------+---------+---------+-----------+---------
vc-a | vCluster-vc-a | Running | 0.20.0 | | 41m34s
vc-b | vCluster-vc-b | Running | 0.20.0 | | 16m36s
虚拟集群的 KubeConfig
虚拟集群的 KubeConfig 保存在对应的 Host 集群的命名空间中,比如虚拟集群 vc-a
的 kubeconfig 保存在 Host 集群的命名空间 vCluster-vc-a
下的 Secret vc-vc-a
中。
kubectl get secret -n vCluster-vc-a
NAME TYPE DATA AGE
sh.helm.release.v1.vc-a.v1 helm.sh/release.v1 1 46m
vc-a-certs Opaque 25 46m
vc-config-vc-a Opaque 1 46m
vc-vc-a Opaque 4 45m
通过下面的命令可以查看 kubeconfig 的内容。
kubectl get secret -n vCluster-vc-a vc-vc-a -o jsonpath='{.data.config}' | base64 -d
连接到虚拟集群
要连接到虚拟集群不需要直接使用 kubeconfig,vCluster CLI 提供了命令可以快捷地连接到虚拟集群。
07:51:42 done vCluster is up and running
07:51:42 done Switched active kube context to vCluster_vc-a_vCluster-vc-a_default
- Use `vCluster disconnect` to return to your previous kube context
- Use `kubectl get namespaces` to access the vCluster
连接成功后,就可以操作虚拟集群了。
kubectl get po -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-5c7466bb88-zgqqk 1/1 Running 0 48m
通过命令 vCluster disconnect
可以断开连接,切换到 Host 集群。
测试
部署实例应用
在虚拟集群 vc-a
上部署应用 deathstar
、tiefighter
和 xwing
。
cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: Service
metadata:
name: deathstar
labels:
app.kubernetes.io/name: deathstar
spec:
type: ClusterIP
ports:
- port: 80
selector:
org: empire
class: deathstar
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deathstar
labels:
app.kubernetes.io/name: deathstar
spec:
replicas: 2
selector:
matchLabels:
org: empire
class: deathstar
template:
metadata:
labels:
org: empire
class: deathstar
app.kubernetes.io/name: deathstar
spec:
containers:
- name: deathstar
image: docker.io/cilium/starwars
---
apiVersion: v1
kind: Pod
metadata:
name: tiefighter
labels:
org: empire
class: tiefighter
app.kubernetes.io/name: tiefighter
spec:
containers:
- name: spaceship
image: docker.io/tgraf/netperf
---
apiVersion: v1
kind: Pod
metadata:
name: xwing
labels:
app.kubernetes.io/name: xwing
org: alliance
class: xwing
spec:
containers:
- name: spaceship
image: docker.io/tgraf/netperf
EOF
待应用启动后测试服务调用。
kubectl exec tiefighter -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
kubectl exec xwing -- curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing
如果显示下面的结果,访问正常,说明容器网络没有问题。
Ship landed
Ship landed
总结
vCluster 在使用 Cilium CNI 的 Host 集群上容器网络是没有问题的,可以说 vCluster 使用的还是 Host 集群的容器网络,不受 CNI 实现的影响。
但如果要在虚拟集群上使用 Cilium 的网络策略,则会受到限制。
这是因为 Syncer 是 vCluster 架构中的一个关键组件,负责在虚拟集群和 Host 集群之间同步 Kubernetes 资源。它使得 vCluster 能够在宿主集群上运行,同时保持与虚拟集群的 Kubernetes API Server 一致。
简单说 Syncer 在 Host 集群和虚拟集群间完成资源的“转译”,实现资源的同步,但仅限于 Kubernetes 的原生资源(如 Pods、Services、ConfigMaps 等)。
在 vCluster v0.14 - 0.19 中,可以通过扩展 vcluster-generic-crd-sync-plugin 完成特定 CRD 的同步,但这个仓库已经一年多未更新。