Cilium 多集羣 Cluster Mesh 介紹
Cluster Mesh 是 Cilium 的多集羣實現,可以幫助 Cilium 實現跨數據中心、跨 VPC 的多 Kubernetes 集羣管理,Cluster Mesh 主要有以下功能:
-
- 通過隧道或直接路由的方式,在多個 Kubernetes 集羣間進行 Pod IP 路由,而無需任何網關或代理。
-
- 使用標準 Kubernetes 服務發現機制。
-
- 跨多個集羣的網絡策略。策略可以使用 Kubernetes 原生的 NetworkPolicy 資源或者擴展的 CiliumNetworkPolicy CRD。
-
- 透明加密本集羣以及跨集羣節點間所有通信的流量。
接下來讓我們一起看看 Cilium Cluster Mesh 有哪些具體的使用場景。
1 使用場景
1.1 高可用
對大多數人來說,高可用是最普遍的使用場景。可以在多個區域(regions)或可用區(availability zones)中運行多個 Kubernetes 集羣,並在每個集羣中運行相同服務的副本。一旦發生異常,請求可以故障轉移到其他集羣。
1.2 共享服務
某些公共基礎服務可以在集羣間進行共享(如密鑰管理,日誌記錄,監控或 DNS 服務等),以避免額外的資源開銷。
1.3 拆分有狀態和無狀態服務
運行有狀態或無狀態服務的操作複雜性是非常不同的。無狀態服務易於擴展,遷移和升級。完全使用無狀態服務運行集羣可使集羣保持靈活和敏捷。有狀態服務(例如 MySQL,Elasticsearch, Etcd 等)可能會引入潛在的複雜依賴,遷移有狀態服務通常涉及存儲的遷移。爲無狀態和有狀態服務分別運行獨立的集羣可以將依賴複雜性隔離到較少數量的集羣中。
2 架構
Cilium Cluster Mesh 的架構如下:
-
每個 Kubernetes 集羣都維護自己的 etcd 集羣,保存自身集羣的狀態。來自多個集羣的狀態永遠不會在本集羣的 etcd 中混淆。
-
每個集羣通過一組 etcd 代理暴露自己的 etcd,在其他集羣中運行的 Cilium agent 連接到 etcd 代理以監視更改。
-
Cilium 使用 clustermesh-apiserver Pod 來建立多集羣的互聯,在 clustermesh-apiserver Pod 中有兩個容器:其中 apiserver 容器負責將多集羣的相關信息寫入 etcd 容器;etcd 容器(etcd 代理)用來存儲 Cluster Mesh 相關的配置信息。
-
從一個集羣到另一個集羣的訪問始終是隻讀的。這確保了故障域保持不變,即一個集羣中的故障永遠不會傳播到其他集羣。
3 前提條件
3.1 安裝相關軟件
-
安裝 Kubectl:https://kubernetes.io/zh/docs/tasks/tools/
-
安裝 Kind:https://kind.sigs.k8s.io/docs/user/quick-start/#installation
-
安裝 Helm:https://helm.sh/docs/intro/install/
-
安裝 Cilium Cli:https://github.com/cilium/cilium-cli
Kind [1](Kubernetes in Docker) 是一個使用 Docker 容器運行本地 Kubernetes 集羣的工具。爲了方便實驗,本文使用 Kind 來搭建 Kubernetes 多集羣環境。
3.2 環境要求
-
- 必須爲所有 Kubernetes 的工作節點分配唯一的 IP 地址,並且節點之間 IP 路由可達。
-
- 每個集羣都要分配唯一的 Pod CIDR。
-
3.Cilium 必須使用 etcd 作爲 kv 存儲。
-
- 集羣之間的網絡必須互通,具體的通信的端口號參見防火牆規則 [2]。
本實驗相關的配置文件可以在: cluster_mesh [3] 獲取。
4 準備 Kubernetes 環境
準備兩個 Kind 配置文件用於搭建 Kubernetes 集羣。
c1 集羣配置文件。
# kind-config1.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
networking:
disableDefaultCNI: true # 禁用默認的 CNI
podSubnet: "10.10.0.0/16"
serviceSubnet: "10.11.0.0/16"
c2 集羣 配置文件。
# kind-config2.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
networking:
disableDefaultCNI: true # 禁用默認的 CNI
podSubnet: "10.20.0.0/16"
serviceSubnet: "10.21.0.0/16"
使用 kind create cluster
命令創建兩個 Kubernetes 集羣。
kind create cluster --config kind-config1.yaml --name c1
kind create cluster --config kind-config2.yaml --name c2
查看兩個 Kubernetes 集羣。
kubectl get node --context kind-c1 -o wide
kubectl get node --context kind-c2 -o wide
5 安裝 Cilium
添加 Helm Repo。
helm repo add cilium https://helm.cilium.io/
在 c1 集羣上安裝 Cilium,使用 --kube-context
參數指定不同的集羣上下文。必須爲每個集羣分配一個唯一的名稱和集羣 id,cluster.id
參數指定集羣 id,範圍 1-255,cluster.name
參數指定集羣名稱。
helm install --kube-context kind-c1 cilium cilium/cilium --version 1.11.4 \
--namespace kube-system \
--set ipam.mode=kubernetes \
--set cluster.id=1 \
--set cluster.name=cluster1
在 c2 集羣上安裝 Cilium。
helm install --kube-context kind-c2 cilium cilium/cilium --version 1.11.4 \
--namespace kube-system \
--set ipam.mode=kubernetes \
--set cluster.id=2 \
--set cluster.name=cluster2
查看 Cilium Pod 狀態。
kubectl --context kind-c1 get pod -A
kubectl --context kind-c2 get pod -A
查看 Cilium 狀態。
cilium status --context kind-c1
cilium status --context kind-c2
6 安裝 Metallb(可選)
在 7 啓用 Cluster Mesh 章節中會介紹發佈 clustermesh-apiserver 服務使用的 Service 類型,建議使用 LoadBalancer 類型的 Service,這樣可以保證提供一個穩定且唯一的 LoadBalancer IP。在公有云提供的 Kubernetes 集羣中,LoadBalancer 類型的 Service 通常會通過公有云的負載均衡設備(例如 AWS 的 ELB,阿里雲的 SLB 等)來發布。在私有環境中可以使用 MetalLB [4] 實現。
準備兩個集羣的 Metallb 配置文件。c1 集羣配置文件。注意分配的網絡要和節點 IP 在同一網段。
# metallb-config1.yaml
configInline:
peers:
address-pools:
- name: default
protocol: layer2
addresses:
- 172.22.0.50-172.22.0.100
c2 集羣配置文件。
configInline:
peers:
address-pools:
- name: default
protocol: layer2
addresses:
- 172.22.0.101-172.22.0.150
使用以下命令在 c1 和 c2 集羣中部署 Metallb。
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install --kube-context kind-c1 metallb bitnami/metallb \
--namespace kube-system \
-f metallb-config1.yaml
helm install --kube-context kind-c2 metallb bitnami/metallb \
--namespace kube-system \
-f metallb-config2.yaml
查看 Metallb Pod 狀態。
7 啓用 Cluster Mesh
使用 cilium clustermesh enable
命令在 c1 集羣上啓用 Cluster Mesh:
-
--create-ca
參數表示自動創建 CA 證書,該證書需要在集羣之間共享,以確保跨集羣的 mTLS 能夠正常工作。 -
--service-type
參數指定發佈 clustermesh-apiserver 服務的方式,有以下 3 種方式: -
LoadBalancer(推薦): 使用 LoadBalancer 類型的 Service 發佈服務,這樣可以使用穩定的 LoadBalancer IP,通常是最佳選擇。
-
NodePort: 使用 NodePort 類型的 Service 發佈服務,如果一個節點消失,Cluster Mesh 將不得不重新連接到另一個節點,可能會造成網絡的中斷。
-
ClusterIP: 使用 ClusterIP 類型的 Service 發佈服務,這要求 ClusterIP 在集羣間是可路由的。
cilium clustermesh enable --create-ca --context kind-c1 --service-type LoadBalancer
執行命令後會在集羣中部署 clustermesh-apiserver 服務,並生成相關必要的證書。
創建的 CA 保存在 kube-system
Namespace 下的 cilium-ca Secret 中。
$ kubectl --context kind-c1 get secret -n kube-system cilium-ca -o yaml
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNFekNDQWJxZ0F3SUJBZ0lVZmVPNHlYbVZSSU1ZZVppSjZyODJ6L05FejBVd0NnWUlLb1pJemowRUF3SXcKYURFTE1Ba0dBMVVFQmhNQ1ZWTXhGakFVQmdOVkJBZ1REVk5oYmlCR2NtRnVZMmx6WTI4eEN6QUpCZ05WQkFjVApBa05CTVE4d0RRWURWUVFLRXdaRGFXeHBkVzB4RHpBTkJnTlZCQXNUQmtOcGJHbDFiVEVTTUJBR0ExVUVBeE1KClEybHNhWFZ0SUVOQk1CNFhEVEl5TURVd09UQXpNemt3TUZvWERUSTNNRFV3T0RBek16a3dNRm93YURFTE1Ba0cKQTFVRUJoTUNWVk14RmpBVUJnTlZCQWdURFZOaGJpQkdjbUZ1WTJselkyOHhDekFKQmdOVkJBY1RBa05CTVE4dwpEUVlEVlFRS0V3WkRhV3hwZFcweER6QU5CZ05WQkFzVEJrTnBiR2wxYlRFU01CQUdBMVVFQXhNSlEybHNhWFZ0CklFTkJNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVTQVNHRERDdnhsUmpYNTEwMEpCQnoxdXIKb29sMktUNVh6MUNYS1paVk5Pc1M5ZmVrOEJUOTRqTXpZcHpsZW5hZXdwczVDZGhWckkvSU9mK2RtaTR3UjZOQwpNRUF3RGdZRFZSMFBBUUgvQkFRREFnRUdNQThHQTFVZEV3RUIvd1FGTUFNQkFmOHdIUVlEVlIwT0JCWUVGTlVwCjBBRVROZ0JHd2ZEK0paRDFWV2w2elNvVk1Bb0dDQ3FHU000OUJBTUNBMGNBTUVRQ0lHZUszUklreUJzQnFxL0MKdzRFTU9nMjk1T244WDFyYVM5QVZMZmlzS2JJVEFpQW5Da3NQTm9BYmZVZ1lyMkVGaFZZaDU0bjlZMVlyU0NlZAprOEZ3Nnl2MWNBPT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
ca.key: LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0tCk1IY0NBUUVFSU9uWG9WTmhIdEJ0TTFaMFFlTWE5UWlLV1QvdXVNMk9jUXNmU252bXEwL2RvQW9HQ0NxR1NNNDkKQXdFSG9VUURRZ0FFU0FTR0REQ3Z4bFJqWDUxMDBKQkJ6MXVyb29sMktUNVh6MUNYS1paVk5Pc1M5ZmVrOEJUOQo0ak16WXB6bGVuYWV3cHM1Q2RoVnJJL0lPZitkbWk0d1J3PT0KLS0tLS1FTkQgRUMgUFJJVkFURSBLRVktLS0tLQo=
kind: Secret
metadata:
creationTimestamp: "2022-05-09T03:44:03Z"
name: cilium-ca
namespace: kube-system
resourceVersion: "20625"
uid: 7e4b2f21-815d-4191-974b-316c629e325c
type: Opaque
將 c1 集羣的 Cilium CA 證書導入集羣 c2。
# 將 c1 集羣的 Cilium CA 證書導出
kubectl get secret --context kind-c1 -n kube-system cilium-ca -o yaml > cilium-ca.yaml
# 將 CA 證書導入 c2 集羣
kubectl apply -f cilium-ca.yaml --context kind-c2
在 c2 集羣上啓用 Cluster Mesh。
cilium clustermesh enable --context kind-c2 --service-type LoadBalancer
查看 c1 和 c2 集羣的 clustermesh-apiserver Pod 狀態。
查看 c1 和 c2 集羣的 clustermesh-apiserver Service,可以看到 Servie 的類型是 LoadBalancer,這是 Metallb 分配的 IP 地址。
kubectl --context kind-c1 get svc -A
kubectl --context kind-c2 get svc -A
查看 Cilium 狀態。
cilium status --context kind-c1
cilium status --context kind-c2
查看 c1 和 c2 集羣的 Cluster Mesh 狀態,當前兩個集羣都已經成功啓用 Cluster Mesh,但是還未互相連接。
cilium clustermesh status --context kind-c1
cilium clustermesh status --context kind-c2
8 連接集羣
在 c1 集羣上執行 cilium clustermesh connect
命令連接 c2 集羣。只需要在一個集羣上執行即可。
cilium clustermesh connect --context kind-c1 --destination-context kind-c2
查看 Cilium Cluster Mesh 狀態,此時 c1 和 c1 集羣已經建立了 Cluster Mesh 連接。
cilium clustermesh status --context kind-c1
cilium clustermesh status --context kind-c2
現在我們已經成功建立了集羣間的互聯,接下來驗證一下 Cluster Mesh 模式下的負載均衡和網絡策略。
9 負載均衡
9.1 全局負載均衡
在集羣中部署兩個應用,其中 x-wing 是客戶端,rebel-base 是服務端,要求對 rebel-base 服務實現全局負載均衡。需要保證每個集羣中的 rebel-base 服務名稱相同並且在相同的命名空間中,然後添加 io.cilium/global-service: "true"
聲明爲全局服務,這樣 Cilium 便會自動對兩個集羣中的 Pod 執行負載均衡。
apiVersion: v1
kind: Service
metadata:
name: rebel-base
annotations:
io.cilium/global-service: "true" # 啓用全局負載均衡
spec:
type: ClusterIP
ports:
- port: 80
selector:
name: rebel-bas
在 c1 和 c2 集羣創建應用服務。
kubectl apply -f cluster1.yaml --context kind-c1
kubectl apply -f cluster2.yaml --context kind-c2
查看服務。
kubectl --context kind-c1 get pod
kubectl --context kind-c1 get svc
kubectl --context kind-c2 get pod
kubectl --context kind-c2 get svc
for i in {1..10}; do kubectl exec --context kind-c1 -ti deployment/x-wing -- curl rebel-base; done
9.2 禁用全局服務共享
默認情況下,全局服務將在多個集羣中的後端進行負載均衡。如果想要禁止本集羣的服務被共享給其他集羣,可以設置 io.cilium/shared-service: "false"
註解來實現。
kubectl annotate service rebel-base \
io.cilium/shared-service="false" --overwrite --context kind-c1
在 c1 集羣可以訪問到兩個集羣的 rebel-base 服務。
for i in {1..10}; do kubectl exec --context kind-c1 -ti deployment/x-wing -- curl rebel-base; done
但是此時 c2 集羣就只能訪問到本集羣的 rebel-base 服務了。
for i in {1..10}; do kubectl exec --context kind-c2 -ti deployment/x-wing -- curl rebel-base; done
將 c1 集羣 rebel-base 服務的註解 io.cilium/shared-service
去掉。
kubectl annotate service rebel-base io.cilium/shared-service- --context kind-c1
現在 c2 集羣可以重新訪問兩個集羣的 rebel-base 服務了。
for i in {1..10}; do kubectl exec --context kind-c2 -ti deployment/x-wing -- curl rebel-base; done
10 網絡策略
創建 CiliumNetworkPolicy 策略只允許 c1 集羣中帶有 x-wing 標籤的 Pod 訪問 c2 集羣中帶有 rebel-base 標籤的 Pod。集羣名字是在 5 安裝 Cilium 章節中通過 --cluster-name
參數指定的,也可以在 cilium-config Configmap 中找到。除了應用服務之間的流量,還需注意放行 DNS 的流量,否則無法直接通過 Service 名字進行訪問。
# networkpolicy.yaml
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: "allow-dns"
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
- matchPattern: "*"
---
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "allow-cross-cluster"
spec:
description: "Allow x-wing in cluster1 to contact rebel-base in cluster2"
endpointSelector:
matchLabels:
name: x-wing
io.cilium.k8s.policy.cluster: cluster1
egress:
- toEndpoints:
- matchLabels:
name: rebel-base
io.cilium.k8s.policy.cluster: cluster2
Kubernetes 的網絡策略不會自動發佈到所有集羣,你需要在每個集羣上下發 NetworkPolicy
或 CiliumNetworkPolicy
。
kubectl --context kind-c1 apply -f networkpolicy.yaml
kubectl --context kind-c2 apply -f networkpolicy.yaml
在 c1 集羣上訪問 rebel-base 服務,可以看到只有分發到 c2 集羣上的請求才可以成功得到響應。
kubectl exec --context kind-c1 -ti deployment/x-wing -- curl rebel-base
11 Troubleshooting
在啓用 Cluster Mesh 的時候遇到以下報錯。
cilium clustermesh status --context kind-c1
查看 Pod 信息發現拉取的鏡像不存在。
kubectl --context kind-c1 describe pod -n kube-system clustermesh-apiserver-754c5479dd-zsg8t
到 Cilium 鏡像倉庫上看了下發現鏡像後面的 sha256 值對不上。
編輯 clustermesh-apiserver Deployment 的鏡像,將鏡像版本後面的 shasum 值去掉即可。
kubectl edit --context kind-c1 deployment -n kube-system clustermesh-apiserver
kubectl edit --context kind-c2 deployment -n kube-system clustermesh-apiserver
12 參考資料
-
[1] Kind: https://kind.sigs.k8s.io/
-
[2] 防火牆規則: https://docs.cilium.io/en/stable/operations/system_requirements/#firewall-requirements
-
[3] cluster_mesh: https://github.com/cr7258/kubernetes-guide/tree/master/cilium/cluster_mesh
-
[4] MetalLB: https://metallb.universe.tf/
-
[5] 深入瞭解 Cilium 多集羣: https://cloudnative.to/blog/deep-dive-into-cilium-multi-cluster/
-
[6] API server for Cilium ClusterMesh: https://github.com/cilium/cilium/tree/master/clustermesh-apiserver
-
[7] Setting up Cluster Mesh: https://docs.cilium.io/en/stable/gettingstarted/clustermesh/clustermesh/#gs-clustermesh
-
[8] BurlyLuo/clustermesh: https://github.com/BurlyLuo/clustermesh
-
[9] eCHO Episode 41: Cilium Clustermesh: https://www.youtube.com/watch?v=VBOONHW65NU&t=2653s
-
[10] Deep Dive into Cilium Multi-cluster: https://cilium.io/blog/2019/03/12/clustermesh
-
[11] Multi Cluster Networking with Cilium and Friends: https://cilium.io/blog/2022/04/12/cilium-multi-cluster-networking
-
[12] Kubernetes Multi-Cluster Networking -Cilium Cluster Mesh: https://itnext.io/kubernetes-multi-cluster-networking-cilium-cluster-mesh-bca0f5367d84
-
[13] A multi-cluster shared services architecture with Amazon EKS using Cilium ClusterMesh: https://aws.amazon.com/cn/blogs/containers/a-multi-cluster-shared-services-architecture-with-amazon-eks-using-cilium-clustermesh/
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/szlBkBjCIVE4mmtP4EiEzA