K8s 多集群編排平臺 Karmada 入門
Karmada(Kubernetes Armada)是 CNCF 孵化的一個 Kubernetes 管理系統,使您能夠在多個 Kubernetes 集群和云中運行云原生應用程序,而無需更改應用程序。通過使用 Kubernetes 原生 API 并提供先進的調度功能,Karmada 實現了真正的開放式、多云 Kubernetes。

Karmada 旨在為多云和混合云場景下的多集群應用程序管理提供即插即用的自動化,具有集中式多云管理、高可用性、故障恢復和流量調度等關鍵功能。
特性
- 兼容 K8s 原生 API
從單集群到多集群的無侵入式升級
現有 K8s 工具鏈的無縫集成
- 開箱即用
- 針對場景內置策略集,包括:Active-active、Remote DR、Geo Redundant 等。
- 在多集群上進行跨集群應用程序自動伸縮、故障轉移和負載均衡。
- 避免供應商鎖定
- 與主流云提供商集成
- 在集群之間自動分配、遷移
- 未綁定專有供應商編排
- 集中式管理
- 位置無關的集群管理
- 支持公有云、本地或邊緣上的集群。
- 豐富多集群調度策略
- 集群親和性、實例在多集群中的拆分調度/再平衡,
- 多維 HA:區域/AZ/集群/提供商
- 開放和中立
- 由互聯網、金融、制造業、電信、云提供商等聯合發起。
- 目標是與 CNCF 一起進行開放治理。
Karmada 架構
Karmada 的架構非常類似于單個 Kubernetes 集群,他們都有一個控制平面、一個 APIServer、一個調度器和一組控制器,而且 Karmada 完全兼容 K8s 的原生 API 操作,便于各種 K8s 集群的接入。

Karmada 架構
所以同樣 Karmada 的核心是其控制平面,一個完整且可工作的 Karmada 控制平面由以下組件組成。其中 karmada-agent 可以是可選的,這取決于集群注冊模式。
karmada-apiserver
APIServer 是 Karmada 控制平面的一個組件,對外暴露 Karmada API 以及 Kubernetes 原生 API,APIServer 是 Karmada 控制平面的前端。
Karmada APIServer 是直接使用 Kubernetes 的 kube-apiserver 實現的,因此 Karmada 與 Kubernetes API 自然兼容。這也使得 Karmada 更容易實現與 Kubernetes 生態系統的集成,例如允許用戶使用 kubectl 來操作 Karmada、與 ArgoCD 集成、與 Flux 集成等等。
karmada-aggregated-apiserver
聚合 API 服務器是使用 Kubernetes API 聚合層技術實現的擴展 API 服務器。它提供了集群 API 以及相應的子資源,例如 cluster/status 和 cluster/proxy,實現了聚合 Kubernetes API Endpoint 等可以通過 karmada-apiserver 訪問成員集群的高級功能。
kube-controller-manager
kube-controller-manager 由一組控制器組成,Karmada 只是從 Kubernetes 的官方版本中挑選了一些控制器,以保持與原生控制器一致的用戶體驗和行為。值得注意的是,并非所有的原生控制器都是 Karmada 所需要的。
注意:當用戶向 Karmada APIServer 提交 Deployment 或其他 Kubernetes 標準資源時,它們只記錄在 Karmada 控制平面的 etcd 中。隨后,這些資源會向成員集群同步。然而,這些部署資源不會在 Karmada 控制平面集群中進行 reconcile 過程(例如創建 Pod)。
karmada-controller-manager
Karmada 控制器管理器運行了各種自定義控制器進程。控制器負責監視 Karmada 對象,并與底層集群的 API 服務器通信,以創建原生的 Kubernetes 資源。
karmada-scheduler
karmada-scheduler 負責將 Kubernetes 原生 API 資源對象(以及 CRD 資源)調度到成員集群。
調度器依據策略約束和可用資源來確定哪些集群對調度隊列中的資源是可用的,然后調度器對每個可用集群進行打分排序,并將資源綁定到最合適的集群。
karmada-webhook
karmada-webhook 是用于接收 karmada/Kubernetes API 請求的 HTTP 回調,并對請求進行處理。你可以定義兩種類型的 karmada-webhook,即驗證性質的 webhook 和修改性質的 webhook。修改性質的準入 webhook 會先被調用。它們可以更改發送到 Karmada API 服務器的對象以執行自定義的設置默認值操作。
在完成了所有對象修改并且 Karmada API 服務器也驗證了所傳入的對象之后,驗證性質的 webhook 會被調用,并通過拒絕請求的方式來強制實施自定義的策略。
etcd
一致且高可用的鍵值存儲,用作 Karmada 的所有 Karmada/Kubernetes 資源對象數據的后臺數據庫。
如果你的 Karmada 使用 etcd 作為其后臺數據庫,請確保你針對這些數據有一份備份計劃。
karmada-agent
Karmada 有 Push 和 Pull 兩種集群注冊模式,karmada-agent 應部署在每個 Pull 模式的成員集群上。它可以將特定集群注冊到 Karmada 控制平面,并將工作負載清單從 Karmada 控制平面同步到成員集群。此外,它也負責將成員集群及其資源的狀態同步到 Karmada 控制平面。
插件(Addons)
- karmada-scheduler-estimator
Karmada 調度估計器為每個成員集群運行精確的調度預估,它為調度器提供了更準確的集群資源信息。
注意:早期的 Karmada 調度器只支持根據集群資源的總量來決策可調度副本的數量。在這種情況下,當集群資源的總量足夠但每個節點資源不足時,會發生調度失敗。為了解決這個問題,引入了估計器組件,該組件根據資源請求計算每個節點的可調度副本的數量,從而計算出真正的整個集群的可調度副本的數量。
- karmada-descheduler
Karmada 重調度組件負責定時檢測所有副本(默認為兩分鐘),并根據成員集群中副本實例狀態的變化觸發重新調度。
該組件是通過調用 karmada-scheduler-estimator 來感知有多少副本實例狀態發生了變化,并且只有當副本的調度策略為動態劃分時,它才會發揮作用。
- karmada-search
Karmada 搜索組件以聚合服務的形式,提供了在多云環境中進行全局搜索和資源代理等功能。
其中,全局搜索能力是用來跨多個集群緩存資源對象和事件,以及通過搜索 API 對外提供圖形化的檢索服務;資源代理能力使用戶既可以訪問 Karmada 控制平面所有資源,又可以訪問成員集群中的所有資源。
CLI 工具
- karmadactl
Karmada 提供了一個命令行工具 karmadactl,用于使用 Karmada API 與 Karmada 的控制平面進行通信。
你可以使用 karmadactl 執行成員集群的添加/剔除,將成員集群標記/取消標記為不可調度,等等。
- kubectl karmada
kubectl karmada 以 kubectl 插件的形式提供功能,但它的實現與 karmadactl 完全相同。
安裝
首先要注意我們使用 Karmada 管理的多集群包含兩類:
- host 集群:即由 karmada 控制面構成的集群,接受用戶提交的工作負載部署需求,將之同步到 member 集群,并從 member 集群同步工作負載后續的運行狀況。
- member 集群:由一個或多個 K8s 集群構成,負責運行用戶提交的工作負載
所以首先我們需要準備幾個 K8s 集群用于測試,其中 host 集群就是我們要安裝 Karmada 的集群,這里我們可以使用 KinD 部署一個 host 集群以及兩個 member 集群,用于測試 Karmada 的多集群管理功能,當然首先需要在你的測試環境中安裝 Docker 和 KinD。
$ docker version
Client:
Cloud integration: v1.0.29
Version: 20.10.21
API version: 1.41
Go version: go1.18.7
Git commit: baeda1f
Built: Tue Oct 25 18:01:18 2022
OS/Arch: darwin/arm64
Context: orbstack
Experimental: true
Server: Docker Engine - Community
Engine:
Version: 25.0.5
API version: 1.44 (minimum version 1.24)
Go version: go1.21.8
Git commit: e63daec
Built: Tue Mar 19 15:05:27 2024
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: v1.7.13
GitCommit: 7c3aca7a610df76212171d200ca3811ff6096eb8
runc:
Version: 1.1.12
GitCommit: 51d5e94601ceffbbd85688df1c928ecccbfa4685
docker-init:
Version: 0.19.0
GitCommit: de40ad0
$ kind version
kind v0.20.0 go1.20.4 darwin/arm64然后,我們可以使用 Karmada 官方提供的 create-cluster.sh 腳本來創建兩個 member 集群。
$ git clone https://github.com/karmada-io/karmada.git
$ cd karmada
# 創建 host 集群
$ hack/create-cluster.sh host $HOME/.kube/host.config
$ kubectl get nodes --context host --kubeconfig /Users/cnych/.kube/host.config
NAME STATUS ROLES AGE VERSION
host-control-plane Ready control-plane 63s v1.27.3
# 創建 member1 集群
$ hack/create-cluster.sh member1 $HOME/.kube/member1.config
$ kubectl get nodes --context member1 --kubeconfig /Users/cnych/.kube/member1.config
NAME STATUS ROLES AGE VERSION
member1-control-plane Ready control-plane 115s v1.27.3
# 創建 member2 集群
$ hack/create-cluster.sh member2 $HOME/.kube/member2.config
$ kubectl get nodes --context member2 --kubeconfig /Users/cnych/.kube/member2.config
NAME STATUS ROLES AGE VERSION
member2-control-plane Ready control-plane 29s v1.27.3到這里我們就準備好了一個 host 集群和兩個 member 集群,接下來我們就可以在 host 集群上安裝 Karmada 了。安裝 Karmada 的方法有很多,可以直接使用官方的 CLI 工具,也可以使用 Helm Chart 方式,還可以使用 Operator 方式等等,如果需要定制化安裝,使用 Helm Chart 的方式會更加靈活。由于官方提供的 CLI 工具并不只是用于安裝 Karmada,還可以用于管理 Karmada 集群,所以無論如何我們都可以先安裝 CLI 工具 - karmadactl,karmadactl 是允許你控制 Karmada 控制面的 Karmada 命令行工具,此外還提供一個 kubectl 插件 kubectl-karmada,盡管這兩個工具的名字不同,但其關聯的命令和選項完全相同,所以無論使用哪一個都是一樣的,在實際使用中,你可以根據自己的需求選擇一個 CLI 工具。
直接使用下面的命令即可一鍵安裝 karmadactl:
$ sudo ./hack/install-cli.sh
[INFO] Downloading metadata https://api.github.com/repos/karmada-io/karmada/releases/latest
[INFO] Using 1.9.1 as release
[INFO] Downloading hash https://github.com/karmada-io/karmada/releases/download/v1.9.1/karmadactl-darwin-arm64.tgz.sha256
[INFO] Downloading binary https://github.com/karmada-io/karmada/releases/download/v1.9.1/karmadactl-darwin-arm64.tgz
[INFO] Verifying binary download
[INFO] Installing karmadactl to /usr/local/bin/karmadactl
$ karmadactl version
karmadactl version: version.Info{GitVersion:"v1.9.1", GitCommit:"b57bff17d6133deb26d9c319714170a915d4fa54", GitTreeState:"clean", BuildDate:"2024-04-30T02:03:53Z", GoVersion:"go1.20.11", Compiler:"gc", Platform:"darwin/arm64"}安裝 kubectl-karmada 與安裝 karmadactl 相同,你只需要添加一個 kubectl-karmada 參數即可:
$ sudo ./hack/install-cli.sh kubectl-karmada
[INFO] Downloading metadata https://api.github.com/repos/karmada-io/karmada/releases/latest
[INFO] Using 1.9.1 as release
[INFO] Downloading hash https://github.com/karmada-io/karmada/releases/download/v1.9.1/kubectl-karmada-darwin-arm64.tgz.sha256
[INFO] Downloading binary https://github.com/karmada-io/karmada/releases/download/v1.9.1/kubectl-karmada-darwin-arm64.tgz
[INFO] Verifying binary download
[INFO] Installing kubectl-karmada to /usr/local/bin/kubectl-karmada
$ kubectl karmada version
kubectl karmada version: version.Info{GitVersion:"v1.9.1", GitCommit:"b57bff17d6133deb26d9c319714170a915d4fa54", GitTreeState:"clean", BuildDate:"2024-04-30T02:03:52Z", GoVersion:"go1.20.11", Compiler:"gc", Platform:"darwin/arm64"}接下來我們就可以在 host 集群上安裝 Karmada 了,我們已將 host 集群的 kubeconfig 文件放到了 $HOME/.kube/config。直接執行以下命令即可進行安裝:
# --kube-image-mirror-country 用于指定鏡像國內源
# --etcd-storage-mode 用于指定 etcd 存儲模式,支持 emptyDir、hostPath、PVC,默認為 hostPath
$ sudo kubectl karmada init --kube-image-mirror-country=cn --etcd-storage-mode PVC --storage-classes-name standard --kubecnotallow=$HOME/.kube/host.config
I0516 15:56:35.549617 98690 deploy.go:244] kubeconfig file: /Users/cnych/.kube/host.config, kubernetes: https://192.168.247.4:6443
I0516 15:56:35.586638 98690 deploy.go:264] karmada apiserver ip: [192.168.247.4]
I0516 15:56:36.330162 98690 cert.go:246] Generate ca certificate success.
I0516 15:56:36.368464 98690 cert.go:246] Generate karmada certificate success.
I0516 15:56:36.453671 98690 cert.go:246] Generate apiserver certificate success.
I0516 15:56:36.535924 98690 cert.go:246] Generate front-proxy-ca certificate success.
I0516 15:56:36.666694 98690 cert.go:246] Generate front-proxy-client certificate success.
I0516 15:56:36.716602 98690 cert.go:246] Generate etcd-ca certificate success.
I0516 15:56:36.772838 98690 cert.go:246] Generate etcd-server certificate success.
I0516 15:56:36.905275 98690 cert.go:246] Generate etcd-client certificate success.
I0516 15:56:36.905808 98690 deploy.go:360] download crds file:https://github.com/karmada-io/karmada/releases/download/v1.9.1/crds.tar.gz
Downloading...[ 100.00% ]
Download complete.
I0516 15:56:39.224167 98690 deploy.go:620] Create karmada kubeconfig success.
I0516 15:56:39.300133 98690 idempotency.go:267] Namespace karmada-system has been created or updated.
I0516 15:56:39.352865 98690 idempotency.go:291] Service karmada-system/etcd has been created or updated.
I0516 15:56:39.353105 98690 deploy.go:426] Create etcd StatefulSets
I0516 15:57:02.386423 98690 deploy.go:435] Create karmada ApiServer Deployment
I0516 15:57:02.412127 98690 idempotency.go:291] Service karmada-system/karmada-apiserver has been created or updated.
I0516 15:57:33.480629 98690 deploy.go:450] Create karmada aggregated apiserver Deployment
I0516 15:57:33.488145 98690 idempotency.go:291] Service karmada-system/karmada-aggregated-apiserver has been created or updated.
I0516 15:57:48.545482 98690 idempotency.go:267] Namespace karmada-system has been created or updated.
I0516 15:57:48.547067 98690 deploy.go:85] Initialize karmada bases crd resource `/etc/karmada/crds/bases`
I0516 15:57:48.549059 98690 deploy.go:240] Attempting to create CRD
I0516 15:57:48.569222 98690 deploy.go:250] Create CRD cronfederatedhpas.autoscaling.karmada.io successfully.
# ......省略部分輸出
I0516 15:57:49.963201 98690 deploy.go:96] Initialize karmada patches crd resource `/etc/karmada/crds/patches`
I0516 15:57:50.372020 98690 deploy.go:108] Create MutatingWebhookConfiguration mutating-config.
I0516 15:57:50.379939 98690 webhook_configuration.go:362] MutatingWebhookConfiguration mutating-config has been created or updated successfully.
I0516 15:57:50.379957 98690 deploy.go:113] Create ValidatingWebhookConfiguration validating-config.
I0516 15:57:50.387416 98690 webhook_configuration.go:333] ValidatingWebhookConfiguration validating-config has been created or updated successfully.
I0516 15:57:50.387434 98690 deploy.go:119] Create Service 'karmada-aggregated-apiserver' and APIService 'v1alpha1.cluster.karmada.io'.
I0516 15:57:50.390795 98690 idempotency.go:291] Service karmada-system/karmada-aggregated-apiserver has been created or updated.
I0516 15:57:50.394479 98690 check.go:42] Waiting for APIService(v1alpha1.cluster.karmada.io) condition(Available), will try
I0516 15:57:51.506085 98690 tlsbootstrap.go:49] [bootstrap-token] configured RBAC rules to allow Karmada Agent Bootstrap tokens to post CSRs in order for agent to get long term certificate credentials
I0516 15:57:51.508289 98690 tlsbootstrap.go:63] [bootstrap-token] configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Karmada Agent Bootstrap Token
I0516 15:57:51.511340 98690 tlsbootstrap.go:77] [bootstrap-token] configured RBAC rules to allow certificate rotation for all agent client certificates in the member cluster
I0516 15:57:51.635344 98690 deploy.go:143] Initialize karmada bootstrap token
I0516 15:57:51.656584 98690 deploy.go:468] Create karmada kube controller manager Deployment
I0516 15:57:51.671152 98690 idempotency.go:291] Service karmada-system/kube-controller-manager has been created or updated.
I0516 15:57:58.728859 98690 deploy.go:482] Create karmada scheduler Deployment
I0516 15:58:10.763913 98690 deploy.go:493] Create karmada controller manager Deployment
I0516 15:58:22.787659 98690 deploy.go:504] Create karmada webhook Deployment
I0516 15:58:22.798328 98690 idempotency.go:291] Service karmada-system/karmada-webhook has been created or updated.
------------------------------------------------------------------------------------------------------
█████ ████ █████████ ███████████ ██████ ██████ █████████ ██████████ █████████
??███ ███? ███?????███ ??███?????███ ??██████ ██████ ███?????███ ??███????███ ███?????███
?███ ███ ?███ ?███ ?███ ?███ ?███?█████?███ ?███ ?███ ?███ ??███ ?███ ?███
?███████ ?███████████ ?██████████ ?███??███ ?███ ?███████████ ?███ ?███ ?███████████
?███??███ ?███?????███ ?███?????███ ?███ ??? ?███ ?███?????███ ?███ ?███ ?███?????███
?███ ??███ ?███ ?███ ?███ ?███ ?███ ?███ ?███ ?███ ?███ ███ ?███ ?███
█████ ??████ █████ █████ █████ █████ █████ █████ █████ █████ ██████████ █████ █████
????? ???? ????? ????? ????? ????? ????? ????? ????? ????? ?????????? ????? ?????
------------------------------------------------------------------------------------------------------
Karmada is installed successfully.
Register Kubernetes cluster to Karmada control plane.
Register cluster with 'Push' mode
Step 1: Use "kubectl karmada join" command to register the cluster to Karmada control plane. --cluster-kubeconfig is kubeconfig of the member cluster.
(In karmada)~# MEMBER_CLUSTER_NAME=$(cat ~/.kube/config | grep current-context | sed 's/: /\n/g'| sed '1d')
(In karmada)~# kubectl karmada --kubeconfig /etc/karmada/karmada-apiserver.config join ${MEMBER_CLUSTER_NAME} --cluster-kubecnotallow=$HOME/.kube/config
Step 2: Show members of karmada
(In karmada)~# kubectl --kubeconfig /etc/karmada/karmada-apiserver.config get clusters
Register cluster with 'Pull' mode
Step 1: Use "kubectl karmada register" command to register the cluster to Karmada control plane. "--cluster-name" is set to cluster of current-context by default.
(In member cluster)~# kubectl karmada register 192.168.247.4:32443 --token rflrr9.iisxtboo8dsz8jsv --discovery-token-ca-cert-hash sha256:008fb63e3b17c3e399f9688eca0978ab3a50dbe5d5b8d4f32c6bfd1fab12a1d8
Step 2: Show members of karmada
(In karmada)~# kubectl --kubeconfig /etc/karmada/karmada-apiserver.config get clusters安裝正常的話會看到如上所示的輸出信息。默認 Karmada 會安裝在 host 集群的 karmada-system 命名空間中:
$ kubectl get pods -n karmada-system --kubeconfig ~/.kube/host.config
NAME READY STATUS RESTARTS AGE
etcd-0 1/1 Running 0 35m
karmada-aggregated-apiserver-5fddf66847-nnfzv 1/1 Running 0 34m
karmada-apiserver-6b6f5b45-fkbk4 1/1 Running 0 35m
karmada-controller-manager-bbdf689db-rc67z 1/1 Running 0 34m
karmada-scheduler-78f854fbd4-m24c8 1/1 Running 0 34m
karmada-webhook-77b9945cf9-mkjrk 1/1 Running 0 33m
kube-controller-manager-5c4975bf8d-6tx5r 1/1 Running 0 34m如上所示 Karmada 控制平面相關 Pod 都已經正常運行,接下來我們就可以將兩個 member 集群注冊到 Karmada 控制平面中了,注冊集群有兩種方式,一種是 Push 模式,一種是 Pull 模式:
- Push:Karmada 控制平面將直接訪問成員集群的 kube-apiserver 以獲取集群狀態并部署清單。
- Pull:Karmada 控制平面不會訪問成員集群,而是將其委托給名為 Karmada-agent 的額外組件。
我們這里的集群都使用的 KinD 搭建的,所以使用 Push 模式更方便,對于無法直接訪問成員集群的環境下面可以使用 Pull 模式。
我們可以使用 kubectl karmada join 命令來注冊集群到 Karmada 控制平面。
sudo kubectl karmada --kubeconfig /etc/karmada/karmada-apiserver.config join member1 --cluster-kubecnotallow=$HOME/.kube/member1.config
sudo kubectl karmada --kubeconfig /etc/karmada/karmada-apiserver.config join member2 --cluster-kubecnotallow=$HOME/.kube/member2.config注冊成功后可以查看注冊的集群列表:
$ sudo kubectl --kubeconfig /etc/karmada/karmada-apiserver.config get clusters
NAME VERSION MODE READY AGE
member1 v1.27.3 Push True 12m
member2 v1.27.3 Push True 2s到這里我們就完成了 Karmada 的安裝和集群注冊,接下來我們就可以使用 Karmada 來管理多集群了。
資源分發
接下來我們創建一個 Deployment 資源,然后使用 Karmada 將其分發到 member1 和 member2 集群中。首先創建如下所示的 Deployment 資源:
# nginx-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9要注意我們需要使用 Karmada 控制平面的 kubeconfig 文件來創建資源對象,因為 Karmada 控制平面會將資源對象分發到成員集群中,所以在應用資源對象時需要使用 --kubeconfig /etc/karmada/karmada-apiserver.config 參數。
# karmada-apiserver 是與 Karmada 控制面交互時要使用的主要 kubeconfig
$ kubectl apply -f nginx-demo.yaml --kubeconfig /etc/karmada/karmada-apiserver.config
$ kubectl get pods --kubeconfig ~/.kube/member1.config
No resources found in default namespace.
$ kubectl get pods --kubeconfig ~/.kube/member2.config
No resources found in default namespace.現在成員集群 member1 和 member2 下面并沒有對應的對象。要進行資源分發我們需要使用一個名為 PropagationPolicy(或者 ClusterPropagationPolicy)的資源對象,該資源對象定義了如何將資源分發到成員集群中。比如我們要將上面的 Deployment 對象分發到 member1 和 member2 集群中,我們可以創建如下所示的 PropagationPolicy 對象:
# nginx-propagation.yaml
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: nginx-propagation
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: nginx
placement:
clusterAffinity:
clusterNames:
- member1
- member2
replicaScheduling:
replicaDivisionPreference: Weighted
replicaSchedulingType: Divided
weightPreference:
staticWeightList:
- targetCluster:
clusterNames:
- member1
weight: 1
- targetCluster:
clusterNames:
- member2
weight: 1在上面的 PropagationPolicy 對象中,首先我們通過 resourceSelectors 屬性指定了要分發的資源對象,然后通過 placement 字段,指定了資源對象的分發策略。
其中 .spec.placement.clusterAffinity 字段表示對特定集群集合的調度限制,沒有該限制,任何集群都可以成為調度候選者,該字段包含以下幾個屬性:
- LabelSelector:用于選擇集群的標簽,matchLabels 和 matchExpressions 兩種方式都支持。
- FieldSelector:按字段選擇成員集群的過濾器。
- ClusterNames:直接指定所選的集群。
- ExcludeClusters:排除指定的集群。
比如我們這里直接通過 clusterNames 屬性指定了 member1 和 member2 集群,這意味著 Deployment 對象 nginx 可以被分發到 member1 和 member2 集群中。
此外我們還可以設置 ClusterAffinities 字段來聲明多個集群組。調度器將按照它們在規范中出現的順序逐一評估這些組,不滿足調度限制的組將被忽略,這意味著該組中的所有集群都不會被選擇。如果沒有一個組滿足調度限制,則調度失敗,這意味著不會選擇任何集群。
另外還要注意 ClusterAffinities 不能與 ClusterAffinity 共存。如果 ClusterAffinity 和 ClusterAffinities 均未設置,則任何集群都可以作為調度候選者。
比如現在我們有兩個分組的集群,其中本地數據中心的私有集群可以是主要的集群,云提供商提供的托管集群可以是次組。因此,Karmada 調度程序更愿意將工作負載調度到主集群組,并且只有在主組不滿足限制(例如缺乏資源)的情況下才會考慮第二組集群,那么就可以配置如下所示的 PropagationPolicy 對象:
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: test-propagation
spec:
#...
placement:
clusterAffinities: # 逐一評估這些組
- affinityName: local-clusters
clusterNames:
- local-member1
- local-member2
- affinityName: cloud-clusters
clusterNames:
- public-cloud-member1
- public-cloud-member2
#...又比如對于災難恢復的場景,集群可以分為 primary 集群和 backup 集群,工作負載將首先調度到主集群,當主集群發生故障(例如數據中心斷電)時,Karmada 調度程序可以遷移工作負載到備份集群。這種情況下可以配置如下所示的 PropagationPolicy 對象:
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: test-propagation
spec:
#...
placement:
clusterAffinities:
- affinityName: primary-clusters
clusterNames:
- member1
- affinityName: backup-clusters
clusterNames:
- member1
- member2
#...現在我們已經指定了分發的集群,那么具體應該如何調度呢?哪一個集群應該有多少副本呢?這就需要指定調度策略了。和原生 Kubernetes 類似,Karmada 支持多種調度策略,比如支持容忍污點、權重等。
通過 .spec.placement.clusterTolerations 字段可以設置容忍度,與 kubernetes 一樣,容忍需要與集群上的污點結合使用。在集群上設置一個或多個污點后,無法在這些集群上調度或運行工作負載,除非策略明確聲明可以容忍這些污點。Karmada 目前支持效果為 NoSchedule 和 NoExecute 的污點。我們可以使用 karmadactl taint 命令來設置集群的污點:
# 為集群 foo 設置包含鍵 dedicated、值 special-user 和效果 NoSchedule 的污點
# 如果具有該鍵和效果的污點已經存在,則其值將按指定替換
karmadactl taint clusters foo dedicated=special-user:NoSchedule為了調度到上述集群,我們需要在 PropagationPolicy 中聲明以下內容:
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: nginx-propagation
spec:
#...
placement:
clusterTolerations:
- key: dedicated
value: special-user
Effect: NoSchedule我們常常使用 NoExecute 污點來實現多集群故障轉移。
然后更多的時候我們需要設置副本調度策略,我們可以通過 .spec.placement.replicaScheduling 字段來設置副本調度策略,該字段表示將規范中具有副本的資源傳播到成員集群時處理副本數量的調度策略。Karmada 一共提供了兩種副本調度類型,用于確定 Karmada 傳播資源時如何調度副本:
- Duplicated:從資源中將相同的副本復制到每個候選成員集群。
- Divided:根據有效候選成員集群的數量將副本劃分為若干部分,每個集群的確切副本由 ReplicaDivisionPreference 確定。
ReplicaDivisionPreference 用于描述當 ReplicaSchedulingType 為 Divided 時副本如何被劃分,也提供了兩種副本劃分方式:
- Aggregated:將副本盡可能少地劃分到集群,同時在劃分過程中尊重集群的資源可用性。
- Weighted:根據 WeightPreference 按權重劃分副本,一共有兩種方式。StaticWeightList 根據權重靜態分配副本到目標集群,可以通過 ClusterAffinity 選擇目標集群。DynamicWeight 指定生成動態權重列表的因子,如果指定,StaticWeightList 將被忽略。
上面我們創建的 Nginx 的 PropagationPolicy 對象中,我們指定了 ReplicaDivisionPreference 為 Weighted,ReplicaSchedulingType 為 Divided,weightPreference 為 1,表示兩個集群的權重相同,這意味著副本將均勻地傳播到 member1 和 member2。
我們這里直接應用傳播策略資源對象即可:
$ sudo kubectl apply -f samples/nginx/propagationpolicy.yaml --kubeconfig /etc/karmada/karmada-apiserver.config
propagationpolicy.policy.karmada.io/nginx-propagation created
$ sudo kubectl get propagationpolicy --kubeconfig /etc/karmada/karmada-apiserver.config
NAME AGE
nginx-propagation 31s當創建 PropagationPolicy 對象后,Karmada 控制平面 watch 到過后就會自動將資源對象分發到成員集群中,我們可以查看 Deployment 對象的狀態:
$ sudo kubectl describe deploy nginx --kubeconfig /etc/karmada/karmada-apiserver.config
# ......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ApplyPolicySucceed 2m17s (x2 over 2m17s) resource-detector Apply policy(default/nginx-propagation) succeed
Normal SyncWorkSucceed 2m17s (x3 over 2m17s) binding-controller Sync work of resourceBinding(default/nginx-deployment) successful.
Normal ScheduleBindingSucceed 2m17s default-scheduler Binding has been scheduled successfully.
Normal SyncSucceed 2m17s execution-controller Successfully applied resource(default/nginx) to cluster member2
Normal SyncSucceed 2m17s execution-controller Successfully applied resource(default/nginx) to cluster member1
Normal AggregateStatusSucceed 2m2s (x9 over 2m17s) resource-binding-status-controller Update resourceBinding(default/nginx-deployment) with AggregatedStatus successfully.可以看到 Deployment 對象已經成功分發到了 member1 和 member2 集群中,我們也可以查看 member1 和 member2 集群中的 Pod 對象來進行驗證:
$ kubectl get pods --kubeconfig ~/.kube/member1.config
NAME READY STATUS RESTARTS AGE
nginx-77b4fdf86c-54qhc 1/1 Running 0 2m59s
$ kubectl get pods --kubeconfig ~/.kube/member2.config
NAME READY STATUS RESTARTS AGE
nginx-77b4fdf86c-9x98b 1/1 Running 0 3m24s和我們聲明的副本調度策略一樣,兩個 Pod 對象均勻地分布在 member1 和 member2 集群中。
分發 CRD
除了內置的資源對象之外,Karmada 還支持分發自定義資源對象(CRD)。這里我們以 Karmada 倉庫中的 guestbook 為例進行說明。
首先進入 Karmada 倉庫的 guestbook 目錄下:
? cd samples/guestbook
? guestbook git:(master) ll
total 48
-rw-r--r-- 1 cnych staff 1.8K May 16 11:26 README.md
-rw-r--r-- 1 cnych staff 135B May 16 11:26 guestbook.yaml
-rw-r--r-- 1 cnych staff 353B May 16 11:26 guestbooks-clusterpropagationpolicy.yaml
-rw-r--r-- 1 cnych staff 2.7K May 16 11:26 guestbooks-crd.yaml
-rw-r--r-- 1 cnych staff 455B May 16 11:26 guestbooks-overridepolicy.yaml
-rw-r--r-- 1 cnych staff 255B May 16 11:26 guestbooks-propagationpolicy.yaml然后在 Karmada 的控制平面上創建 Guestbook CRD:
sudo kubectl apply -f guestbooks-crd.yaml --kubeconfig /etc/karmada/karmada-apiserver.config該 CRD 應該被應用到 karmada-apiserver。
然后我們可以創建一個 ClusterPropagationPolicy 對象,將 Guestbook CRD 分發到 member1,如下所示:
# guestbooks-clusterpropagationpolicy.yaml
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
name: example-policy
spec:
resourceSelectors:
- apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: guestbooks.webapp.my.domain
placement:
clusterAffinity:
clusterNames:
- member1需要注意的是 CustomResourceDefinition 是全局資源,所以我們使用 ClusterPropagationPolicy 對象來分發,該對象的配置和 PropagationPolicy 對象類似,注意 resourceSelectors 字段中的 apiVersion 和 kind 需要設置為 apiextensions.k8s.io/v1 和 CustomResourceDefinition,name 字段需要設置為 Guestbook CRD 的名稱。
然后我們直接創建 ClusterPropagationPolicy 對象即可:
sudo kubectl apply -f guestbooks-clusterpropagationpolicy.yaml --kubeconfig /etc/karmada/karmada-apiserver.config應用后正常就會將 Guestbook CRD 對象分發到 member1 集群中。
$ sudo kubectl karmada get crd --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER CREATED AT ADOPTION
guestbooks.webapp.my.domain member1 2024-05-18T11:56:10Z Y
$ kubectl get crd --kubeconfig ~/.kube/member1.config
NAME CREATED AT
guestbooks.webapp.my.domain 2024-05-18T11:56:10Z
$ kubectl get crd --kubeconfig ~/.kube/member2.config
No resources found接下來我們就可以部署分發 Guestbook CRD 對象了,我們可以創建一個 Guestbook CR 對象:
# guestbook.yaml
apiVersion: webapp.my.domain/v1
kind: Guestbook
metadata:
name: guestbook-sample
spec:
size: 2
configMapName: test
alias: Name同樣在 Karmada 控制平面上應用該 Guestbook CR 對象即可:
$ sudo kubectl apply -f guestbook.yaml --kubeconfig /etc/karmada/karmada-apiserver.config然后就可以創建 PropagationPolicy 對象,將 guestbook-sample 分發到 member1 集群:
# guestbooks-propagationpolicy.yaml
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: example-policy
spec:
resourceSelectors:
- apiVersion: webapp.my.domain/v1
kind: Guestbook
placement:
clusterAffinity:
clusterNames:
- member1上面的 PropagationPolicy 對象和我們之前創建的類似,只是這里的 resourceSelectors 字段中的 apiVersion 和 kind 需要設置為 webapp.my.domain/v1 和 Guestbook(我們自己的 CRD)。同樣直接應用該 PropagationPolicy 對象即可:
$ sudo kubectl apply -f guestbooks-propagationpolicy.yaml --kubeconfig /etc/karmada/karmada-apiserver.config應用后就可以將 guestbook-sample 這個 Guestbook CR 對象分發到 member1 集群中了。
$ kubectl get guestbook --kubeconfig ~/.kube/member1.config
NAME AGE
guestbook-sample 39s可以看到 CRD 的分發和普通資源對象的分發原理是一樣的,只是需要先將 CRD 對象分發到成員集群中。
有的時候我們可能需要對分發的資源到不同集群進行一些覆蓋操作,這個時候我們就可以使用 OverridePolicy 和 ClusterOverridePolicy 對象,用于聲明資源傳播到不同集群時的覆蓋規則。
比如我們創建一個 OverridePolicy 對象,用于覆蓋 member1 中 guestbook-sample 的 size 字段,如下所示:
apiVersion: policy.karmada.io/v1alpha1
kind: OverridePolicy
metadata:
name: guestbook-sample
spec:
resourceSelectors:
- apiVersion: webapp.my.domain/v1
kind: Guestbook
overrideRules:
- targetCluster:
clusterNames:
- member1
overriders:
plaintext:
- path: /spec/size
operator: replace
value: 4
- path: /metadata/annotations
operator: add
value: { "OverridePolicy": "test" }上面的對象中通過 resourceSelectors 字段指定了要覆蓋的資源對象,然后通過 overrideRules 字段指定了覆蓋規則,targetCluster 字段指定了目標集群,overriders 字段指定了覆蓋規則,這里我們將 guestbook-sample 的 size 字段覆蓋為 4,同時添加了一個 OverridePolicy: test 的注解。
我們直接應用該 OverridePolicy 對象即可:
$ sudo kubectl apply -f guestbooks-overridepolicy.yaml --kubeconfig /etc/karmada/karmada-apiserver.config創建完成后可以查看 member1 集群中的 guestbook-sample 對象來進行驗證:
$ kubectl get guestbook guestbook-sample --kubeconfig ~/.kube/member1.config -oyaml
apiVersion: webapp.my.domain/v1
kind: Guestbook
metadata:
annotations:
OverridePolicy: test
# ......
name: guestbook-sample
namespace: default
resourceVersion: "82669"
uid: 5893b85d-3946-44a0-b210-d67bd021cb65
spec:
alias: Name
configMapName: test
size: 4可以看到 guestbook-sample 對象的 size 字段已經被覆蓋為 4,同時添加了一個 OverridePolicy: test 的注解,證明覆蓋操作成功。
Karmada 提供了多種聲明覆蓋規則的方案:
- ImageOverrider:覆蓋工作負載的鏡像。
- CommandOverrider:覆蓋工作負載的命令。
- ArgsOverrider:覆蓋工作負載的參數。
- LabelsOverrider:覆蓋工作負載的標簽。
- AnnotationsOverrider:覆蓋工作負載的注釋。
- PlaintextOverrider:用于覆蓋任何類型資源的通用工具。
PlaintextOverrider
上面我們使用的是 PlaintextOverrider 覆蓋規則,可以覆蓋任何類型資源的字段。PlaintextOverrider 可以根據路徑、運算符和值覆蓋目標字段,就像 kubectl patch 一樣。允許的操作如下:
- add:向資源追加一個或多個元素。
- remove:從資源中刪除一個或多個元素。
- replace:替換資源中的一個或多個元素。
ImageOverrider
ImageOverrider 用于覆蓋工作負載的鏡像,用于覆蓋格式為 [registry/]repository[:tag|@digest](例如 /spec/template/spec/containers/0/image )的鏡像。允許的操作如下:
- add:將注冊表、存儲庫或 tag/digest 附加到容器中的鏡像。
- remove:從容器中的鏡像中刪除注冊表、存儲庫或 tag/digest。
- replace:替換容器中鏡像的注冊表、存儲庫或 tag/digest。
比如我們需要創建一個如下所示的 Deployment 對象:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
#...
spec:
template:
spec:
containers:
- image: myapp:1.0.0
name: myapp當工作負載傳播到特定集群時添加注冊表,可以使用如下所示的 OverridePolicy 對象:
apiVersion: policy.karmada.io/v1alpha1
kind: OverridePolicy
metadata:
name: example
spec:
#...
overrideRules:
- overriders:
imageOverrider:
- component: Registry
operator: add
value: test-repo上面的覆蓋規則表示添加 test-repo 這個鏡像倉庫到 myapp 的鏡像中,這樣在傳播到集群時就會變成 test-repo/myapp:1.0.0。
containers:
- image: test-repo/myapp:1.0.0
name: myappreplace 和 remove 操作也是類似的,只是分別用于替換和刪除鏡像中的某些字段。
跨集群彈性伸縮
在 Karmada 中,我們可以使用 FederatedHPA 來實現跨多個集群擴展/縮小工作負載的副本,旨在根據需求自動調整工作負載的規模。

FederatedHPA
當負載增加時,如果 Pod 的數量低于配置的最大值,則 FederatedHPA 擴展工作負載(例如 Deployment、StatefulSet 或其他類似資源)的副本數。當負載減少時,如果 Pod 的數量高于配置的最小值,則 FederatedHPA 縮小工作負載的副本數。
FederatedHPA 是作為 Karmada API 資源和控制器實現的,該資源確定了控制器的行為。FederatedHPA 控制器運行在 Karmada 控制平面中,定期調整其目標(例如 Deployment)的所需規模,以匹配觀察到的指標,例如平均 CPU 利用率、平均內存利用率或任何其他自定義指標。

FederatedHPA實現原理
為了實現跨集群的自動擴縮容,Karmada 引入了 FederatedHPA 控制器和 karmada-metrics-adapter,它們的工作方式如下:
- HPA 控制器定期通過指標 API metrics.k8s.io 或 custom.metrics.k8s.io 使用標簽選擇器查詢指標。
- karmada-apiserver 獲取指標 API 查詢結果,然后通過 API 服務注冊將其路由到 karmada-metrics-adapter。
- karmada-metrics-adapter 將從目標集群(Pod 所在的集群)查詢指標。收集到指標后,它會對這些指標進行聚合并返回結果。
- HPA 控制器將根據指標計算所需的副本數,并直接擴展/縮小工作負載的規模。然后,karmada-scheduler 將這些副本調度到成員集群中。
注意:要使用此功能,Karmada 版本必須為 v1.6.0 或更高版本。
下面我們就來演示如何使用 FederatedHPA 控制器來實現跨集群的自動擴縮容。首先至少需要兩個成員集群,我們需要在成員集群中安裝 ServiceExport 和 ServiceImport 來啟用多集群服務。在 Karmada 控制平面上安裝 ServiceExport 和 ServiceImport 后(init 安裝后會自動安裝),我 們可以創建 ClusterPropagationPolicy 將這兩個 CRD 傳播到成員集群。
# propagate-service-export-import.yaml
# propagate ServiceExport CRD
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
name: serviceexport-policy
spec:
resourceSelectors:
- apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: serviceexports.multicluster.x-k8s.io
placement:
clusterAffinity:
clusterNames:
- member1
- member2
---
# propagate ServiceImport CRD
apiVersion: policy.karmada.io/v1alpha1
kind: ClusterPropagationPolicy
metadata:
name: serviceimport-policy
spec:
resourceSelectors:
- apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
name: serviceimports.multicluster.x-k8s.io
placement:
clusterAffinity:
clusterNames:
- member1
- member2直接應用該 ClusterPropagationPolicy 對象即可:
$ sudo kubectl apply -f propagate-service-export-import.yaml --kubeconfig /etc/karmada/karmada-apiserver.config應用后就可以在 member1 和 member2 集群中創建 ServiceExport 和 ServiceImport 對象了。
另外我們還需要為成員集群安裝 metrics-server 來提供 metrics API,通過運行以下命令來安裝:
hack/deploy-k8s-metrics-server.sh $HOME/.kube/member1.config member1
hack/deploy-k8s-metrics-server.sh $HOME/.kube/member2.config member2最后我們還需要在 Karmada 控制平面中安裝 karmada-metrics-adapter 以提供指標 API,通過運行以下命令來安裝它:
sudo hack/deploy-metrics-adapter.sh ~/.kube/host.config host /etc/karmada/karmada-apiserver.config karmada-apiserver需要注意使用 karmada init 安裝的 Karmada 控制平面,需要將 karmada-cert 這個 Secret 對象重新拷貝創建一個名為 karmada-cert-secret 的 Secret 對象。
部署后在 Karmada 控制平面中就會有 karmada-metrics-adapter 這個 Pod 對象。
接下來我們在 member1 和 member2 中部署 Deployment(1 個副本)和 Service 對象,如下所示:
# nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
resources:
requests:
cpu: 25m
memory: 64Mi
limits:
cpu: 25m
memory: 64Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
ports:
- port: 80
targetPort: 80
selector:
app: nginx
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: nginx-propagation
spec:
resourceSelectors:
- apiVersion: apps/v1
kind: Deployment
name: nginx
- apiVersion: v1
kind: Service
name: nginx-service
placement:
clusterAffinity:
clusterNames:
- member1
- member2
replicaScheduling:
replicaDivisionPreference: Weighted
replicaSchedulingType: Divided
weightPreference:
staticWeightList:
- targetCluster:
clusterNames:
- member1
weight: 1
- targetCluster:
clusterNames:
- member2
weight: 1直接應用上面的資源對象即可:
$ sudo kubectl apply -f nginx.yaml --kubeconfig /etc/karmada/karmada-apiserver.config
deployment.apps/nginx configured
service/nginx-service created
propagationpolicy.policy.karmada.io/nginx-propagation configured
$ sudo kubectl karmada get pods --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER READY STATUS RESTARTS AGE
nginx-5c54b4855f-ztmnk member1 1/1 Running 0 43s
$ sudo kubectl karmada get svc --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ADOPTION
nginx-service member2 ClusterIP 100.171.35.78 <none> 80/TCP 52s Y
nginx-service member1 ClusterIP 100.91.124.245 <none> 80/TCP 52s Y然后讓我們在 Karmada 控制平面中部署一個 FederatedHPA 對象,用來自動擴縮容,如下所示:
# nginx-federatedhpa.yaml
apiVersion: autoscaling.karmada.io/v1alpha1
kind: FederatedHPA
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 1
maxReplicas: 10
behavior:
scaleDown:
stabilizationWindowSeconds: 10
scaleUp:
stabilizationWindowSeconds: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 10上面的 FederatedHPA 對象中,我們指定了 scaleTargetRef 字段為 Deployment 對象 nginx,minReplicas 和 maxReplicas 分別為 1 和 10,metrics 字段中指定了 CPU 利用率為 10% 時進行擴縮容。同樣直接應用該 FederatedHPA 對象即可:
$ sudo kubectl apply -f nginx-federatedhpa.yaml --kubeconfig /etc/karmada/karmada-apiserver.config
$ sudo kubectl get fhpa --kubeconfig /etc/karmada/karmada-apiserver.config
NAME REFERENCE-KIND REFERENCE-NAME MINPODS MAXPODS REPLICAS AGE
nginx Deployment nginx 1 10 1 19s我們還需要一個多集群服務將請求路由到 member1 和 member2 集群中的 pod。首先在 Karmada 控制平面上創建 ServiceExport 對象,然后創建 PropagationPolicy 以將 ServiceExport 對象傳播到 member1 和 member2 集群。
# nginx-serviceexport.yaml
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
metadata:
name: nginx-service
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: serve-export-policy
spec:
resourceSelectors:
- apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceExport
name: nginx-service
placement:
clusterAffinity:
clusterNames:
- member1
- member2然后在 Karmada 控制平面上創建 ServiceImport 對象,然后創建 PropagationPolicy 以將 ServiceImport 對象傳播到 member1 集群。
# nginx-serviceimport.yaml
apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceImport
metadata:
name: nginx-service
spec:
type: ClusterSetIP
ports:
- port: 80
protocol: TCP
---
apiVersion: policy.karmada.io/v1alpha1
kind: PropagationPolicy
metadata:
name: serve-import-policy
spec:
resourceSelectors:
- apiVersion: multicluster.x-k8s.io/v1alpha1
kind: ServiceImport
name: nginx-service
placement:
clusterAffinity:
clusterNames:
- member1直接應用上面的資源對象即可:
$ sudo kubectl apply -f nginx-serviceexport.yaml --kubeconfig /etc/karmada/karmada-apiserver.config
$ sudo kubectl apply -f nginx-serviceimport.yaml --kubeconfig /etc/karmada/karmada-apiserver.config部署完成后,可以查看多集群服務:
$ sudo kubectl karmada get svc --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ADOPTION
nginx-service member2 ClusterIP 100.171.35.78 <none> 80/TCP 6m36s Y
derived-nginx-service member1 ClusterIP 100.91.3.68 <none> 80/TCP 17s Y
nginx-service member1 ClusterIP 100.91.124.245 <none> 80/TCP 6m36s Y接下來我們在 member1 集群使用 hey 工具來進行 http 負載測試,模擬請求增加,從而觸發 Pod 的 CPU 使用率增加:
$ wget https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64
$ chmod +x hey_linux_amd64
$ docker cp hey_linux_amd64 member1-control-plane:/usr/local/bin/hey然后我們可以使用 hey 請求多集群服務以增加 nginx pod 的 CPU 使用率。
$ docker exec member1-control-plane hey -c 1000 -z 1m http://100.91.3.68
Summary:
Total: 61.4678 secs
Slowest: 4.7916 secs
Fastest: 0.0244 secs
Average: 0.9024 secs
Requests/sec: 1090.3758
Total data: 41219145 bytes
Size/request: 615 bytes
Response time histogram:
0.024 [1] |
0.501 [23047] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.978 [23117] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
1.455 [8696] |■■■■■■■■■■■■■■■
1.931 [5681] |■■■■■■■■■■
2.408 [3352] |■■■■■■
2.885 [1534] |■■■
3.361 [832] |■
3.838 [375] |■
4.315 [318] |■
4.792 [70] |
Latency distribution:
10% in 0.2733 secs
25% in 0.4264 secs
50% in 0.6478 secs
75% in 1.1603 secs
90% in 1.9114 secs
95% in 2.3694 secs
99% in 3.4382 secs
Details (average, fastest, slowest):
DNS+dialup: 0.0019 secs, 0.0244 secs, 4.7916 secs
DNS-lookup: 0.0000 secs, 0.0000 secs, 0.0000 secs
req write: 0.0006 secs, 0.0000 secs, 0.1423 secs
resp wait: 0.7861 secs, 0.0002 secs, 4.6641 secs
resp read: 0.0553 secs, 0.0000 secs, 1.3870 secs
Status code distribution:
[200] 67023 responses等一會兒,副本就會開始擴容了,我們可以查看 FederatedHPA 對象的狀態來了解副本的變化:
$ sudo kubectl describe fhpa nginx --kubeconfig /etc/karmada/karmada-apiserver.config
Name: nginx
Namespace: default
Labels: <none>
Annotations: <none>
API Version: autoscaling.karmada.io/v1alpha1
Kind: FederatedHPA
# ...
Spec:
Behavior:
Scale Down:
Policies:
Period Seconds: 15
Type: Percent
Value: 100
Select Policy: Max
Stabilization Window Seconds: 10
Scale Up:
Policies:
Period Seconds: 15
Type: Pods
Value: 4
Period Seconds: 15
Type: Percent
Value: 100
Select Policy: Max
Stabilization Window Seconds: 10
Max Replicas: 10
Metrics:
Resource:
Name: cpu
Target:
Average Utilization: 10
Type: Utilization
Type: Resource
Min Replicas: 1
Scale Target Ref:
API Version: apps/v1
Kind: Deployment
Name: nginx
Status:
Conditions:
Last Transition Time: 2024-05-19T01:43:16Z
Message: recommended size matches current size
Reason: ReadyForNewScale
Status: True
Type: AbleToScale
Last Transition Time: 2024-05-19T01:43:16Z
Message: the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
Reason: ValidMetricFound
Status: True
Type: ScalingActive
Last Transition Time: 2024-05-19T01:45:16Z
Message: the desired replica count is less than the minimum replica count
Reason: TooFewReplicas
Status: True
Type: ScalingLimited
Current Metrics:
Resource:
Current:
Average Utilization: 0
Average Value: 0
Name: cpu
Type: Resource
Current Replicas: 1
Desired Replicas: 1
Last Scale Time: 2024-05-19T01:45:16Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 2m7s federatedHPA-controller New size: 5; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 112s federatedHPA-controller New size: 10; reason: cpu resource utilization (percentage of request) above target
Normal SuccessfulRescale 67s federatedHPA-controller New size: 3; reason: All metrics below target
Normal SuccessfulRescale 52s federatedHPA-controller New size: 1; reason: All metrics below target同時可以查看 member1 和 member2 集群中的 Pod 對象:
$ sudo kubectl karmada get pods --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER READY STATUS RESTARTS AGE
nginx-5c54b4855f-4p6wq member1 1/1 Running 0 40s
nginx-5c54b4855f-kdwpc member1 1/1 Running 0 2m6s
nginx-5c54b4855f-l4vm4 member1 1/1 Running 0 40s
nginx-5c54b4855f-t4ghv member1 1/1 Running 0 25s
nginx-5c54b4855f-vbj9c member1 1/1 Running 0 25s
nginx-5c54b4855f-hx2xn member2 1/1 Running 0 25s
nginx-5c54b4855f-kfnbh member2 1/1 Running 0 40s
nginx-5c54b4855f-rmbv9 member2 1/1 Running 0 40s
nginx-5c54b4855f-wfd92 member2 1/1 Running 0 25s
nginx-5c54b4855f-wwsvq member2 1/1 Running 0 25s可以看到 Pod 的副本數已經擴容到 10 個了。同樣當負載測試結束后,Pod 的副本數會自動縮小為 1 個副本。
$ sudo kubectl karmada get pods --kubeconfig /etc/karmada/karmada-apiserver.config
NAME CLUSTER READY STATUS RESTARTS AGE
nginx-5c54b4855f-kdwpc member1 1/1 Running 0 5m25s到這里我們就完成了使用 FederatedHPA 進行跨集群的自動擴縮容,除此之外我們還可以使用 CronFederatedHPA 用于定期自動縮放操作,它可以縮放具有 scale 子資源的工作負載或 Karmada FederatedHPA。典型的場景是在可預見的流量高峰到來前提前擴容工作負載。例如,如果我知道每天早上 9 點會突發流量洪峰,我們就可以提前半個小時擴容相關服務,以處理高峰負載并確保服務持續可用性。在 Karmada 控制平面內運行的 CronFederatedHPA 控制器根據預定義的 cron 計劃來伸縮工作負載的副本或 FederatedHPA 的最小/最大副本數。
比如我們有一個如下所示的 CronFederatedHPA 對象:
apiVersion: autoscaling.karmada.io/v1alpha1
kind: CronFederatedHPA
metadata:
name: nginx-cronfhpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
rules:
- name: "scale-up"
schedule: "*/1 * * * *"
targetReplicas: 5
suspend: false其中表達式 */1 * * * * 的意思是 nginx deployment 的副本應該每分鐘更新為 5 個,確保了處理接下來的流量突發流量洪峰。
除了這些使用場景之外,Karmada 還有很多實踐場景,比如跨集群的災備、多集群網絡、多集群服務治理、多集群 CI/CD 等等,這些場景都可以通過 Karmada 來實現,更多最佳實踐方案可以參考 Karmada 官方文檔以了解更多。
參考鏈接:https://karmada.io/zh/docs/。
































