Karmada-Cluster 组件详解
Karmada Cluster 组件详解目录
[*]一、使用背景
[*]二、Cluster API 定义
[*]三、使用方式
[*]四、源码原理
[*]五、总结
一、使用背景
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 mapstring `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: mapstring{
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) 收藏一下 不知道什么时候能用到 分享、互助 让互联网精神温暖你我 用心讨论,共获提升! 前排留名,哈哈哈 谢谢楼主提供! 很好很强大我过来先占个楼 待编辑 这个有用。 收藏一下 不知道什么时候能用到 分享、互助 让互联网精神温暖你我 谢谢楼主提供! 懂技术并乐意极积无私分享的人越来越少。珍惜 感谢分享 热心回复! 谢谢分享,辛苦了 谢谢分享,试用一下 热心回复! 感谢分享 热心回复! 热心回复!
页:
[1]
2