Karmada-Cluster 组件详解
Karmada Cluster 组件详解
目录
一、使用背景
1.1 为什么需要 Cluster 资源?
在 Karmada 多集群管理系统中,Cluster 是代表成员集群的核心资源对象。它的主要作用是:
- 集群注册与发现:将 Kubernetes 集群注册到 Karmada 控制平面
- 集群生命周期管理:管理集群的加入、健康检查、故障处理、删除等
- 集群属性定义:记录集群的地理位置(Region/Zone)、云提供商、资源模型等信息
- 调度决策依据:为 Scheduler 提供集群信息,用于资源分发决策
- 状态同步:收集和展示成员集群的实时状态(节点、资源等)
1.2 在多集群架构中的位置
Karmada 控制平面
│
├── Cluster (成员集群1) ──┐
├── Cluster (成员集群2) ──┼──> ResourceBinding ──> Work ──> 实际资源
└── Cluster (成员集群3) ──┘
Cluster 是 Karmada 与成员集群之间的桥梁,所有资源分发都必须基于已注册的 Cluster。
二、Cluster API 定义
2.1 基本结构
Cluster 是一个集群级(ClusterScope)的 CRD 资源,定义在 pkg/apis/cluster/v1alpha1/types.go:
// Cluster represents the desired state and status of a member cluster.
type Cluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec 定义了集群的期望状态(配置信息)
Spec ClusterSpec `json:"spec"`
// Status 表示集群的实际状态(运行时信息)
Status ClusterStatus `json:"status,omitempty"`
}
2.2 ClusterSpec - 期望配置
ClusterSpec 定义了集群的配置信息:
核心字段
type ClusterSpec struct {
// ID: 集群唯一标识符
// 1. 优先从 ClusterProperty API 获取
// 2. 否则使用 kube-system namespace 的 UID
ID string `json:"id,omitempty"`
// SyncMode: 同步模式(Push 或 Pull)
// - Push: 控制平面主动推送资源到成员集群
// - Pull: 成员集群的 Agent 主动拉取资源
SyncMode ClusterSyncMode `json:"syncMode"`
// APIEndpoint: 成员集群的 API 地址
APIEndpoint string `json:"apiEndpoint,omitempty"`
// SecretRef: 访问成员集群的凭证(包含 token 和 caBundle)
SecretRef *LocalSecretReference `json:"secretRef,omitempty"`
// ImpersonatorSecretRef: Impersonator 的凭证(用于 Pull 模式)
ImpersonatorSecretRef *LocalSecretReference `json:"impersonatorSecretRef,omitempty"`
// 连接配置
InsecureSkipTLSVerification bool `json:"insecureSkipTLSVerification,omitempty"`
ProxyURL string `json:"proxyURL,omitempty"`
ProxyHeader map[string]string `json:"proxyHeader,omitempty"`
// 集群属性(用于调度)
Provider string `json:"provider,omitempty"` // 云提供商(如 aws, alibaba)
Region string `json:"region,omitempty"` // 区域
Zones []string `json:"zones,omitempty"` // 可用区列表
// Taints: 集群污点(用于调度决策)
Taints []corev1.Taint `json:"taints,omitempty"`
// ResourceModels: 资源模型(用于资源估算和调度)
ResourceModels []ResourceModel `json:"resourceModels,omitempty"`
}
SyncMode 详解
const (
// Push 模式:控制平面主动推送
// - 控制器在控制平面运行,直接连接成员集群 API
// - 适合网络可达的场景
Push ClusterSyncMode = "Push"
// Pull 模式:成员集群主动拉取
// - Agent 在成员集群运行,拉取控制平面的资源
// - 适合网络受限或安全隔离的场景
Pull ClusterSyncMode = "Pull"
)
2.3 ClusterStatus - 运行时状态
ClusterStatus 记录了集群的实时状态:
type ClusterStatus struct {
// KubernetesVersion: Kubernetes 版本
KubernetesVersion string `json:"kubernetesVersion,omitempty"`
// APIEnablements: 集群支持的 API 资源列表
APIEnablements []APIEnablement `json:"apiEnablements,omitempty"`
// Conditions: 集群条件状态
Conditions []metav1.Condition `json:"conditions,omitempty"`
// NodeSummary: 节点摘要
NodeSummary *NodeSummary `json:"nodeSummary,omitempty"`
// ResourceSummary: 资源摘要(可分配、已分配、等待分配)
ResourceSummary *ResourceSummary `json:"resourceSummary,omitempty"`
// RemedyActions: 需要执行的修复操作
RemedyActions []string `json:"remedyActions,omitempty"`
}
Conditions 类型
const (
// ClusterConditionReady: 集群是否就绪
ClusterConditionReady = "Ready"
// ClusterConditionCompleteAPIEnablements: API 启用是否完整
ClusterConditionCompleteAPIEnablements = "CompleteAPIEnablements"
)
ResourceSummary 结构
type ResourceSummary struct {
// Allocatable: 可分配资源总量(所有节点的总和)
Allocatable corev1.ResourceList `json:"allocatable,omitempty"`
// Allocating: 等待调度的资源(Pending Pods)
Allocating corev1.ResourceList `json:"allocating,omitempty"`
// Allocated: 已分配的资源(已调度的 Pods)
Allocated corev1.ResourceList `json:"allocated,omitempty"`
// AllocatableModelings: 资源模型统计
AllocatableModelings []AllocatableModeling `json:"allocatableModelings,omitempty"`
}
三、使用方式
3.1 注册集群(Push 模式)
使用 karmadactl join 命令注册集群:
# 基本用法
karmadactl join CLUSTER_NAME \
--cluster-kubeconfig=<成员集群的 kubeconfig> \
--kubeconfig=<Karmada 控制平面的 kubeconfig>
# 完整示例
karmadactl join member1 \
--cluster-kubeconfig=$HOME/.kube/member1.config \
--cluster-namespace=karmada-cluster \
--cluster-provider=aliyun \
--cluster-region=cn-hangzhou \
--cluster-zones=cn-hangzhou-a,cn-hangzhou-b \
--kubeconfig=$HOME/.kube/karmada.config
工作原理:
- 读取成员集群的 kubeconfig
- 提取集群 ID(优先从 ClusterProperty,否则使用 kube-system UID)
- 创建访问凭证(Secret)
- 在控制平面创建 Cluster 对象
- Cluster Controller 检测到新集群,创建 ExecutionSpace(命名空间)
3.2 注册集群(Pull 模式)
Pull 模式需要成员集群主动注册:
# Step 1: 在控制平面创建 bootstrap token
karmadactl token create --print-register-command \
--kubeconfig=<Karmada 控制平面的 kubeconfig>
# 输出示例:
# karmadactl register 172.18.0.5:5443 \
# --token t8xfio.640u9gp9obc72v5d \
# --discovery-token-ca-cert-hash sha256:9cfa542ff48f43793d1816b1dd0a78ad574e349d8f6e005e6e32e8ab528e4244
# Step 2: 在成员集群执行注册命令(指定成员集群的 kubeconfig)
karmadactl register 172.18.0.5:5443 \
--token t8xfio.640u9gp9obc72v5d \
--discovery-token-ca-cert-hash sha256:9cfa542ff48f43793d1816b1dd0a78ad574e349d8f6e005e6e32e8ab528e4244 \
--kubeconfig=<成员集群的 kubeconfig>
Pull 模式特点:
- 成员集群主动连接控制平面
- 需要在成员集群部署 karmada-agent
- 适合网络隔离场景
3.3 查看集群
# 列出所有集群
kubectl get clusters
# 查看集群详细信息
kubectl get cluster <cluster-name> -o yaml
# 查看集群状态
kubectl describe cluster <cluster-name>
3.4 删除集群
# 删除集群(会触发优雅删除流程)
kubectl delete cluster <cluster-name>
删除流程:
- 从所有 ResourceBinding 和 ClusterResourceBinding 中移除该集群
- 删除该集群相关的所有 Work 对象
- 删除 ExecutionSpace 命名空间
- 删除 Cluster 对象
3.5 手动创建 Cluster(YAML)
也可以直接通过 YAML 创建:
apiVersion: cluster.karmada.io/v1alpha1
kind: Cluster
metadata:
name: member1
spec:
syncMode: Push
apiEndpoint: https://member1-api.example.com:6443
secretRef:
namespace: karmada-cluster
name: member1
provider: aliyun
region: cn-hangzhou
zones:
- cn-hangzhou-a
- cn-hangzhou-b
taints: [] # 可以添加污点来阻止调度
四、源码原理
4.1 Cluster Controller 架构
Cluster Controller 负责管理 Cluster 资源的生命周期,代码位于 pkg/controllers/cluster/cluster_controller.go。
核心结构
type Controller struct {
client.Client // Kubernetes 客户端
EventRecorder record.EventRecorder
// 健康检查配置
ClusterMonitorPeriod time.Duration // 监控周期(默认 5s)
ClusterMonitorGracePeriod time.Duration // 优雅期(默认 40s)
ClusterStartupGracePeriod time.Duration // 启动优雅期(默认 1min)
CleanupCheckInterval time.Duration // 清理检查间隔(10s)
// 集群健康状态缓存
clusterHealthMap *clusterHealthMap
RateLimiterOptions ratelimiterflag.Options
}
4.2 核心工作流程
4.2.1 Reconcile 主流程
func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Request) (controllerruntime.Result, error) {
// 1. 获取 Cluster 对象
cluster := &clusterv1alpha1.Cluster{}
if err := c.Client.Get(ctx, req.NamespacedName, cluster); err != nil {
if apierrors.IsNotFound(err) {
return controllerruntime.Result{}, nil
}
return controllerruntime.Result{}, err
}
// 2. 判断是否为删除操作
if !cluster.DeletionTimestamp.IsZero() {
return c.removeCluster(ctx, cluster)
}
// 3. 同步集群(创建/更新)
return c.syncCluster(ctx, cluster)
}
4.2.2 syncCluster - 集群同步
func (c *Controller) syncCluster(ctx context.Context, cluster *clusterv1alpha1.Cluster) (controllerruntime.Result, error) {
// Step 1: 创建 ExecutionSpace(执行空间)
// ExecutionSpace 是一个命名空间,格式为: karmada-es-{cluster-name}
// 用于存放该集群相关的 Work 对象
err := c.createExecutionSpace(ctx, cluster)
if err != nil {
c.EventRecorder.Event(cluster, corev1.EventTypeWarning,
events.EventReasonCreateExecutionSpaceFailed, err.Error())
return controllerruntime.Result{}, err
}
// Step 2: 根据集群条件添加污点
// - Ready=False: 添加 NotReady taint
// - Ready=Unknown: 添加 Unreachable taint
// - Ready=True: 移除所有调度相关的污点
err = c.taintClusterByCondition(ctx, cluster)
if err != nil {
return controllerruntime.Result{}, err
}
// Step 3: 确保 Finalizer 存在
// Finalizer 用于在删除时执行清理逻辑
return c.ensureFinalizer(ctx, cluster)
}
关键点:
- ExecutionSpace:每个集群都有一个独立的命名空间,用于隔离该集群的 Work 对象
- Taint 机制:根据集群健康状态自动添加污点,调度器会据此决策是否调度到该集群
4.2.3 createExecutionSpace - 创建执行空间
func (c *Controller) createExecutionSpace(ctx context.Context, cluster *clusterv1alpha1.Cluster) error {
// 生成执行空间名称:karmada-es-{cluster-name}
executionSpaceName := names.GenerateExecutionSpaceName(cluster.Name)
executionSpaceObj := &corev1.Namespace{}
err := c.Client.Get(ctx, types.NamespacedName{Name: executionSpaceName}, executionSpaceObj)
if err != nil {
if !apierrors.IsNotFound(err) {
return err
}
// 创建新的执行空间
executionSpace := &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: executionSpaceName,
Labels: map[string]string{
util.KarmadaSystemLabel: util.KarmadaSystemLabelValue,
},
},
}
err = c.Client.Create(ctx, executionSpace)
if err != nil {
return err
}
klog.V(2).InfoS("Created execution space", "cluster", cluster.Name, "namespace", executionSpaceName)
}
return nil
}
执行空间的作用:
- 隔离不同集群的 Work 对象
- 便于管理和查询特定集群的工作负载
- 支持 RBAC 权限隔离
4.2.4 taintClusterByCondition - 污点管理
func (c *Controller) taintClusterByCondition(ctx context.Context, cluster *clusterv1alpha1.Cluster) error {
currentReadyCondition := meta.FindStatusCondition(cluster.Status.Conditions,
clusterv1alpha1.ClusterConditionReady)
if currentReadyCondition != nil {
switch currentReadyCondition.Status {
case metav1.ConditionFalse:
// 集群不健康,添加 NotReady 污点
err = c.updateClusterTaints(ctx,
[]*corev1.Taint{NotReadyTaintTemplateForSched},
[]*corev1.Taint{UnreachableTaintTemplateForSched},
cluster)
case metav1.ConditionUnknown:
// 集群不可达,添加 Unreachable 污点
err = c.updateClusterTaints(ctx,
[]*corev1.Taint{UnreachableTaintTemplateForSched},
[]*corev1.Taint{NotReadyTaintTemplateForSched},
cluster)
case metav1.ConditionTrue:
// 集群健康,移除所有调度污点
err = c.updateClusterTaints(ctx,
nil,
[]*corev1.Taint{NotReadyTaintTemplateForSched, UnreachableTaintTemplateForSched},
cluster)
}
}
return err
}
污点定义:
var (
// UnreachableTaintTemplateForSched: 集群不可达时的污点
UnreachableTaintTemplateForSched = &corev1.Taint{
Key: clusterv1alpha1.TaintClusterUnreachable, // "cluster.karmada.io/unreachable"
Effect: corev1.TaintEffectNoSchedule,
}
// NotReadyTaintTemplateForSched: 集群不健康时的污点
NotReadyTaintTemplateForSched = &corev1.Taint{
Key: clusterv1alpha1.TaintClusterNotReady, // "cluster.karmada.io/not-ready"
Effect: corev1.TaintEffectNoSchedule,
}
)
4.2.5 removeCluster - 集群删除
func (c *Controller) removeCluster(ctx context.Context, cluster *clusterv1alpha1.Cluster) (controllerruntime.Result, error) {
// Step 1: 删除 ExecutionSpace
if err := c.removeExecutionSpace(ctx, cluster); err != nil {
klog.ErrorS(err, "Failed to remove execution space", "cluster", cluster.Name)
return controllerruntime.Result{}, err
}
// Step 2: 检查 ExecutionSpace 是否已删除
if exist, err := c.ExecutionSpaceExistForCluster(ctx, cluster.Name); err != nil {
return controllerruntime.Result{}, err
} else if exist {
// 如果还存在,等待下次重试
return controllerruntime.Result{RequeueAfter: c.CleanupCheckInterval}, nil
}
// Step 3: 从健康状态缓存中删除
c.clusterHealthMap.delete(cluster.Name)
// Step 4: 检查集群是否已从所有 Binding 中移除
if done, err := c.isTargetClusterRemoved(ctx, cluster); err != nil {
return controllerruntime.Result{}, err
} else if !done {
// 如果还有 Binding 引用该集群,等待下次重试
return controllerruntime.Result{RequeueAfter: c.CleanupCheckInterval}, nil
}
// Step 5: 移除 Finalizer,允许 Cluster 对象被删除
return c.removeFinalizer(ctx, cluster)
}
删除流程说明:
- 检查依赖:确保没有 ResourceBinding/ClusterResourceBinding 引用该集群
- 清理资源:删除 ExecutionSpace 及其中的所有 Work 对象
- 移除 Finalizer:允许 Kubernetes 真正删除 Cluster 对象
4.2.6 monitorClusterHealth - 健康监控
Cluster Controller 启动一个后台 goroutine 定期监控集群健康状态:
func (c *Controller) Start(ctx context.Context) error {
klog.InfoS("Starting cluster health monitor")
// 启动周期性健康检查
go wait.UntilWithContext(ctx, func(ctx context.Context) {
if err := c.monitorClusterHealth(ctx); err != nil {
klog.ErrorS(err, "Error monitoring cluster health")
}
}, c.ClusterMonitorPeriod)
<-ctx.Done()
return nil
}
健康检查逻辑:
func (c *Controller) monitorClusterHealth(ctx context.Context) error {
// 1. 列出所有集群
clusterList := &clusterv1alpha1.ClusterList{}
if err = c.Client.List(ctx, clusterList); err != nil {
return err
}
// 2. 遍历每个集群检查健康状态
for i := range clusterList.Items {
cluster := &clusterList.Items[i]
err = c.tryUpdateClusterHealth(ctx, cluster)
if err != nil {
klog.ErrorS(err, "Failed to update health", "cluster", cluster.Name)
continue
}
}
return nil
}
健康状态更新逻辑:
func (c *Controller) tryUpdateClusterHealth(ctx context.Context, cluster *clusterv1alpha1.Cluster) error {
// 1. 获取上次的健康状态
clusterHealth := c.clusterHealthMap.getDeepCopy(cluster.Name)
// 2. 获取当前 Ready 条件
currentReadyCondition := meta.FindStatusCondition(cluster.Status.Conditions,
clusterv1alpha1.ClusterConditionReady)
// 3. 对于 Pull 模式,检查 Lease 对象
if cluster.Spec.SyncMode == clusterv1alpha1.Pull {
observedLease := &coordinationv1.Lease{}
err := c.Client.Get(ctx,
client.ObjectKey{Namespace: util.NamespaceClusterLease, Name: cluster.Name},
observedLease)
// 如果 Lease 更新了,说明 Agent 还在运行
if err == nil && observedLease.Spec.RenewTime.After(clusterHealth.probeTimestamp.Time) {
clusterHealth.probeTimestamp = metav1.Now()
}
}
// 4. 检查是否超时
gracePeriod := c.ClusterMonitorGracePeriod
if currentReadyCondition == nil {
gracePeriod = c.ClusterStartupGracePeriod // 新集群给更长的优雅期
}
if metav1.Now().After(clusterHealth.probeTimestamp.Add(gracePeriod)) {
// 超时未收到更新,标记为 Unknown
// 更新 Cluster.Status.Conditions
// ...
}
return nil
}
关键点:
- Pull 模式:通过 Lease 对象判断 Agent 是否存活
- 超时检测:如果超过优雅期未收到状态更新,将集群标记为 Unknown
- 状态缓存:使用
clusterHealthMap缓存健康状态,避免频繁访问 API Server
4.3 Cluster Status Controller
Cluster Status Controller 负责收集和更新集群的状态信息,代码位于 pkg/controllers/status/cluster_status_controller.go。
主要职责
- 连接测试:定期连接成员集群 API,检查是否可达
- 状态收集:
- Kubernetes 版本
- API 资源列表(APIEnablements)
- 节点摘要(总节点数、就绪节点数)
- 资源摘要(可分配、已分配、等待分配的资源)
- 条件更新:更新 Cluster.Status.Conditions
核心流程
func (c *ClusterStatusController) syncClusterStatus(ctx context.Context, cluster *clusterv1alpha1.Cluster) error {
// 1. 创建成员集群的客户端
clusterClient, err := c.ClusterClientSetFunc(cluster.Name, c.Client, c.ClusterClientOption)
if err != nil {
return setStatusCollectionFailedCondition(ctx, c.Client, cluster,
fmt.Sprintf("failed to create a ClusterClient: %v", err))
}
// 2. 检查集群健康状态
online, healthy := getClusterHealthStatus(clusterClient)
observedReadyCondition := generateReadyCondition(online, healthy)
// 3. 应用阈值调整(避免频繁状态切换)
readyCondition := c.clusterConditionCache.thresholdAdjustedReadyCondition(
cluster, &observedReadyCondition)
// 4. 如果集群离线,直接更新状态并返回
if !online && readyCondition.Status != metav1.ConditionTrue {
return updateStatusCondition(ctx, c.Client, cluster, *readyCondition)
}
// 5. 收集详细状态信息
if online && healthy && readyCondition.Status == metav1.ConditionTrue {
// 收集 Kubernetes 版本
kubernetesVersion, err := clusterClient.Discovery().ServerVersion()
// 收集 API 资源列表
apiEnablements, err := c.collectAPIEnablement(clusterClient)
// 收集节点摘要
nodeSummary, err := c.collectNodeSummary(clusterClient)
// 收集资源摘要
resourceSummary, err := c.collectResourceSummary(clusterClient, cluster)
// 更新 Cluster.Status
cluster.Status.KubernetesVersion = kubernetesVersion.GitVersion
cluster.Status.APIEnablements = apiEnablements
cluster.Status.NodeSummary = nodeSummary
cluster.Status.ResourceSummary = resourceSummary
}
// 6. 更新 Ready 条件
return updateStatusCondition(ctx, c.Client, cluster, *readyCondition)
}
4.4 关键设计模式
4.4.1 Finalizer 模式
Cluster 使用 Finalizer 确保删除时完成清理:
const ClusterControllerFinalizer = "karmada.io/cluster-controller"
func (c *Controller) ensureFinalizer(ctx context.Context, cluster *clusterv1alpha1.Cluster) (controllerruntime.Result, error) {
if controllerutil.ContainsFinalizer(cluster, util.ClusterControllerFinalizer) {
return controllerruntime.Result{}, nil
}
controllerutil.AddFinalizer(cluster, util.ClusterControllerFinalizer)
return controllerruntime.Result{}, c.Client.Update(ctx, cluster)
}
4.4.2 索引优化
为了快速查询引用特定集群的 Binding,使用索引:
// 注册索引
indexregistry.RegisterResourceBindingIndexByFieldCluster(ctx, mgr)
indexregistry.RegisterClusterResourceBindingIndexByFieldCluster(ctx, mgr)
// 使用索引查询
rbList := &workv1alpha2.ResourceBindingList{}
err := c.List(ctx, rbList, client.MatchingFieldsSelector{
Selector: fields.OneTermEqualSelector(
indexregistry.ResourceBindingIndexByFieldCluster,
cluster.Name),
})
4.4.3 状态缓存
使用内存缓存集群健康状态,减少 API Server 压力:
type clusterHealthMap struct {
sync.RWMutex
clusterHealths map[string]*clusterHealthData
}
type clusterHealthData struct {
probeTimestamp metav1.Time
status *clusterv1alpha1.ClusterStatus
lease *coordinationv1.Lease
}
五、总结
5.1 Cluster 的核心价值
- 统一抽象:将异构的 Kubernetes 集群统一抽象为 Cluster 对象
- 生命周期管理:完整的注册、监控、故障处理、删除流程
- 调度决策支持:提供集群属性、状态、污点等信息供调度器使用
- 状态可视化:实时展示集群的运行状态和资源使用情况
5.2 关键概念
| 概念 | 说明 |
|---|---|
| ExecutionSpace | 每个集群的执行空间(命名空间),存放该集群的 Work 对象 |
| SyncMode | Push(控制平面推送)或 Pull(成员集群拉取) |
| Taint | 根据健康状态自动添加污点,影响调度决策 |
| Finalizer | 确保删除时完成资源清理 |
| Conditions | 集群条件状态(Ready、CompleteAPIEnablements) |
5.3 与其他组件的关系
Cluster
├── 被 Scheduler 使用(集群选择)
├── 被 Binding Controller 使用(创建 Work 到对应 ExecutionSpace)
├── 被 Execution Controller 使用(连接成员集群 API)
├── 被 Status Controller 更新(状态同步)
└── 被 Cluster Controller 管理(生命周期)
参考资源
- 源码位置:
- API 定义:
pkg/apis/cluster/v1alpha1/types.go - Cluster Controller:
pkg/controllers/cluster/cluster_controller.go - Cluster Status Controller:
pkg/controllers/status/cluster_status_controller.go
- API 定义:
- 官方文档:https://karmada.io/docs/
- 命令参考:
karmadactl join --helpkarmadactl register --help

浙公网安备 33010602011771号