Karmada-Agent 组件详解
Karmada Agent 组件详解
目录
一、使用背景
1.1 为什么需要 Karmada Agent?
Karmada Agent 是部署在成员集群中的组件,它是 Karmada 多集群系统的执行终端。Agent 的主要作用是:
- 资源分发执行:接收控制平面的 Work 对象,将资源应用到成员集群
- 状态反向同步:收集成员集群的资源状态,同步回控制平面
- 集群注册(Pull 模式):主动连接控制平面,完成集群注册
- 健康心跳:通过 Lease 机制向控制平面发送心跳,证明 Agent 存活
1.2 Push vs Pull 模式
Karmada 支持两种同步模式,Agent 用于 Pull 模式:
Push 模式
- 执行位置:控制平面(Controller Manager 的 Execution Controller)
- 连接方向:控制平面 → 成员集群 API
- 适用场景:网络可达、控制平面可直接访问成员集群
- 特点:无需在成员集群部署额外组件
Pull 模式
- 执行位置:成员集群(Agent 中的 Execution Controller)
- 连接方向:成员集群 Agent → 控制平面 API
- 适用场景:网络隔离、安全限制、控制平面无法直接访问成员集群
- 特点:需要在成员集群部署 Agent
1.3 Agent 在系统架构中的位置
Karmada 控制平面
│
├── API Server (存储 Work 对象)
│
└── ExecutionSpace (karmada-es-{cluster-name})
│
└── Work 对象 (为每个集群创建)
│
▼ (Pull 模式)
成员集群 (member1)
│
├── Karmada Agent ⭐
│ ├── Execution Controller (应用 Work 到集群)
│ ├── Work Status Controller (同步资源状态)
│ └── Cluster Status Controller (同步集群状态)
│
└── 实际资源 (Deployment、Service 等)
二、架构设计
2.1 组件职责
Agent 包含多个控制器,共同完成多集群协调任务:
核心控制器
| 控制器 | 作用 | 输入 | 输出 |
|---|---|---|---|
| Execution Controller | 执行资源分发 | Work 对象 | 成员集群中的实际资源 |
| Work Status Controller | 同步资源状态 | 成员集群资源状态 | Work.Status |
| Cluster Status Controller | 同步集群状态 | 成员集群信息 | Cluster.Status |
可选控制器
| 控制器 | 作用 | 说明 |
|---|---|---|
| Service Export Controller | 服务导出 | 用于 MultiClusterService |
| EndpointSlice Collect Controller | 端点收集 | 收集 EndpointSlice 用于 MCS |
| Cert Rotation Controller | 证书轮转 | 自动更新访问凭证(可选) |
2.2 Agent 的双向通信
控制平面 成员集群
│ │
│ │
├── Work 对象 ────────────────────►│ Agent 监听 Work
│ │
│ ├─► Execution Controller
│ │ 将资源应用到集群
│ │
│ ├─► Work Status Controller
│ │ 收集资源状态
│ │
│◄──────────────── Work.Status ────┤ 更新 Work 状态
│ │
│◄────────────── Cluster.Status ───┤ Cluster Status Controller
│ │ 收集集群状态
│ │
├── Lease 对象 ◄───────────────────┤ 心跳机制(Pull 模式)
│ │
2.3 ExecutionSpace 隔离
Agent 只监听自己集群对应的 ExecutionSpace 中的 Work:
- ExecutionSpace 命名规则:
karmada-es-{cluster-name} - 隔离机制:每个集群有独立的命名空间,Work 对象隔离存放
- Agent 监听范围:仅监听自己集群的 ExecutionSpace
三、使用方式
3.1 Pull 模式集群注册
Step 1: 在控制平面创建 Bootstrap Token
# 使用 karmadactl 创建 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: 在成员集群执行注册
# 在成员集群执行注册命令
karmadactl register 172.18.0.5:5443 \
--token t8xfio.640u9gp9obc72v5d \
--discovery-token-ca-cert-hash sha256:9cfa542ff48f43793d1816b1dd0a78ad574e349d8f6e005e6e32e8ab528e4244 \
--kubeconfig=<成员集群的 kubeconfig> \
--cluster-name=member1 \
--cluster-provider=aliyun \
--cluster-region=cn-hangzhou
注册流程:
- Agent 使用 Bootstrap Token 连接控制平面
- 创建 Cluster 对象
- 创建访问凭证(Secret)
- 在成员集群部署 Agent Deployment
Step 3: 验证注册
# 在控制平面查看集群
kubectl get clusters --kubeconfig=<karmada-config>
# 查看 Agent 状态
kubectl get pods -n karmada-system \
--kubeconfig=<member-cluster-config> \
-l app=karmada-agent
3.2 手动部署 Agent
准备 kubeconfig
# 从控制平面获取 kubeconfig
# 保存为 secret
kubectl create secret generic karmada-agent-config \
--from-file=karmada.config=<path-to-karmada-kubeconfig> \
-n karmada-system \
--kubeconfig=<member-cluster-config>
部署 Agent
apiVersion: apps/v1
kind: Deployment
metadata:
name: karmada-agent
namespace: karmada-system
spec:
replicas: 1
selector:
matchLabels:
app: karmada-agent
template:
metadata:
labels:
app: karmada-agent
spec:
serviceAccountName: karmada-agent-sa
containers:
- name: karmada-agent
image: docker.io/karmada/karmada-agent:latest
command:
- /bin/karmada-agent
- --karmada-kubeconfig=/etc/kubeconfig/karmada-kubeconfig
- --karmada-context=karmada-apiserver
- --cluster-name=member1
- --cluster-api-endpoint=https://member1-api.example.com:6443
- --cluster-status-update-frequency=10s
- --metrics-bind-address=:8080
- --health-probe-bind-address=0.0.0.0:10357
volumeMounts:
- name: kubeconfig
mountPath: /etc/kubeconfig
volumes:
- name: kubeconfig
secret:
secretName: karmada-agent-config
创建 RBAC
Agent 需要以下权限:
# ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: karmada-agent
rules:
# 控制平面权限:读写 Work、Cluster 等
- apiGroups: ['work.karmada.io']
resources: ['works']
verbs: ['*']
- apiGroups: ['cluster.karmada.io']
resources: ['clusters', 'clusters/status']
verbs: ['*']
# 成员集群权限:所有资源的读写权限
- apiGroups: ['*']
resources: ['*']
verbs: ['*']
---
# ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: karmada-agent
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: karmada-agent
subjects:
- kind: ServiceAccount
name: karmada-agent-sa
namespace: karmada-system
3.3 常用配置参数
核心参数
# 必需参数
--karmada-kubeconfig # 连接控制平面的 kubeconfig 路径
--karmada-context # kubeconfig 中的 context 名称
--cluster-name # 成员集群名称
# 集群信息(可选,但建议配置)
--cluster-api-endpoint # 成员集群 API 地址
--cluster-provider # 云提供商(用于调度)
--cluster-region # 区域(用于调度)
--cluster-zones # 可用区列表(用于调度)
# 性能调优
--concurrent-work-syncs=5 # 并发处理 Work 的数量
--cluster-status-update-frequency=10s # 状态更新频率
--cluster-api-qps=40 # 访问成员集群 API 的 QPS
--kube-api-qps=40 # 访问控制平面 API 的 QPS
# 控制器配置
--controllers=* # 启用的控制器列表
3.4 高可用部署
多副本部署
spec:
replicas: 2 # 部署多个副本
template:
spec:
# 启用 Leader Election
# 通过 --leader-elect=true 自动启用
Leader Election:
- Agent 使用 Leader Election 确保只有一个实例工作
- 其他实例作为备用,Leader 故障时自动切换
健康检查
livenessProbe:
httpGet:
path: /healthz
port: 10357
scheme: HTTP
initialDelaySeconds: 15
periodSeconds: 15
readinessProbe:
httpGet:
path: /healthz
port: 10357
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
3.5 监控和调试
查看 Agent 日志
# 查看 Agent Pod 日志
kubectl logs -n karmada-system \
-l app=karmada-agent \
--tail=100 \
--kubeconfig=<member-cluster-config>
# 查看特定控制器日志(通过日志级别)
kubectl logs -n karmada-system \
-l app=karmada-agent \
--kubeconfig=<member-cluster-config> \
| grep "execution-controller"
查看指标
# Agent 暴露 metrics 在 :8080 端口
kubectl port-forward -n karmada-system \
-l app=karmada-agent 8080:8080 \
--kubeconfig=<member-cluster-config>
# 访问 metrics
curl http://localhost:8080/metrics
检查 Agent 连接状态
# 在控制平面查看集群状态
kubectl get cluster member1 -o yaml \
--kubeconfig=<karmada-config>
# 检查 Ready 条件
kubectl get cluster member1 \
-o jsonpath='{.status.conditions[?(@.type=="Ready")]}' \
--kubeconfig=<karmada-config>
四、源码原理
4.1 Agent 启动流程
代码位置:cmd/agent/app/agent.go
主函数入口
func run(ctx context.Context, opts *options.Options) error {
// Step 1: 加载配置
controlPlaneRestConfig, err := apiclient.RestConfig(
opts.KarmadaContext, opts.KarmadaKubeConfig,
)
clusterConfig, err := controllerruntime.GetConfig() // 成员集群配置
// Step 2: 注册集群到控制平面(Pull 模式)
registerOption := util.ClusterRegisterOption{
ClusterName: opts.ClusterName,
ClusterAPIEndpoint: opts.ClusterAPIEndpoint,
ClusterProvider: opts.ClusterProvider,
ClusterRegion: opts.ClusterRegion,
ClusterZones: opts.ClusterZones,
ControlPlaneConfig: controlPlaneRestConfig,
ClusterConfig: clusterConfig,
}
// 获取集群 ID
registerOption.ClusterID, err = util.ObtainClusterID(clusterKubeClient)
// 创建凭证
clusterSecret, impersonatorSecret, err := util.ObtainCredentialsFromMemberCluster(...)
// 注册集群(创建 Cluster 对象)
err = util.RegisterClusterInControllerPlane(
registerOption, controlPlaneKubeClient,
generateClusterInControllerPlane,
)
// Step 3: 创建 Controller Manager
executionSpace := names.GenerateExecutionSpaceName(opts.ClusterName)
controllerManager, err := controllerruntime.NewManager(
controlPlaneRestConfig, // 连接到控制平面
controllerruntime.Options{
Cache: cache.Options{
DefaultNamespaces: map[string]cache.Config{
executionSpace: {}, // 只监听自己的 ExecutionSpace
},
},
LeaderElection: opts.LeaderElection.LeaderElect,
LeaderElectionID: fmt.Sprintf("karmada-agent-%s", opts.ClusterName),
LeaderElectionNamespace: opts.LeaderElection.ResourceNamespace,
},
)
// Step 4: 设置控制器
if err = setupControllers(ctx, controllerManager, opts); err != nil {
return err
}
// Step 5: 启动 Controller Manager
return controllerManager.Start(ctx)
}
关键点:
- Agent 连接到控制平面的 API Server,而不是成员集群
- Cache 配置为只监听自己的 ExecutionSpace
- 使用 Leader Election 实现高可用
4.2 控制器初始化
代码位置:cmd/agent/app/agent.go:setupControllers
func setupControllers(ctx context.Context, mgr controllerruntime.Manager, opts *options.Options) error {
// Step 1: 创建 Informer Manager(用于缓存控制平面的资源)
controlPlaneInformerManager := genericmanager.NewSingleClusterInformerManager(...)
// Step 2: 创建 Resource Interpreter
resourceInterpreter := resourceinterpreter.NewResourceInterpreter(...)
resourceInterpreter.Start(ctx)
// Step 3: 创建 Object Watcher(用于操作成员集群资源)
objectWatcher := objectwatcher.NewObjectWatcher(
mgr.GetClient(),
mgr.GetRESTMapper(),
util.NewClusterDynamicClientSetForAgent, // 连接到成员集群
clusterClientOption,
resourceInterpreter,
)
// Step 4: 创建控制器上下文
controllerContext := controllerscontext.Context{
Mgr: mgr,
ObjectWatcher: objectWatcher,
ResourceInterpreter: resourceInterpreter,
// ... 其他配置
}
// Step 5: 启动所有控制器
return controllers.StartControllers(controllerContext, controllersDisabledByDefault)
}
控制器注册
func init() {
controllers["clusterStatus"] = startClusterStatusController
controllers["execution"] = startExecutionController
controllers["workStatus"] = startWorkStatusController
controllers["serviceExport"] = startServiceExportController
controllers["certRotation"] = startCertRotationController
controllers["endpointsliceCollect"] = startEndpointSliceCollectController
}
4.3 Execution Controller - 资源分发
代码位置:pkg/controllers/execution/execution_controller.go
Reconcile 流程
func (c *Controller) Reconcile(ctx context.Context, req controllerruntime.Request) (controllerruntime.Result, error) {
// 1. 获取 Work 对象(从控制平面的 ExecutionSpace)
work := &workv1alpha1.Work{}
if err := c.Client.Get(ctx, req.NamespacedName, work); err != nil {
return controllerruntime.Result{}, err
}
// 2. 从 Work 的 Namespace 提取集群名称
// Work 位于 karmada-es-{cluster-name} 命名空间
clusterName, err := names.GetClusterName(work.Namespace)
// 3. 获取成员集群信息
cluster, err := util.GetCluster(c.Client, clusterName)
// 4. 如果是删除操作
if !work.DeletionTimestamp.IsZero() {
return c.handleWorkDelete(ctx, work, cluster)
}
// 5. 检查是否暂停分发
if util.IsWorkSuspendDispatching(work) {
return controllerruntime.Result{}, nil
}
// 6. 检查集群是否就绪
if !util.IsClusterReady(&cluster.Status) {
return controllerruntime.Result{}, fmt.Errorf("cluster(%s) not ready", cluster.Name)
}
// 7. 同步 Work 到成员集群
return c.syncWork(ctx, clusterName, work)
}
syncWork - 同步资源到集群
func (c *Controller) syncWork(ctx context.Context, clusterName string, work *workv1alpha1.Work) error {
var errs []error
syncSucceedNum := 0
// 遍历 Work 中的所有 Manifest
for _, manifest := range work.Spec.Workload.Manifests {
// 1. 反序列化 Manifest
workload := &unstructured.Unstructured{}
err := workload.UnmarshalJSON(manifest.Raw)
if err != nil {
errs = append(errs, err)
continue
}
// 2. 创建或更新资源到成员集群
if err = c.tryCreateOrUpdateWorkload(ctx, clusterName, workload); err != nil {
errs = append(errs, err)
continue
}
syncSucceedNum++
}
// 3. 更新 Work 的 Applied 条件
if len(errs) > 0 {
return c.updateAppliedCondition(ctx, work,
metav1.ConditionFalse, "AppliedFailed", ...)
}
return c.updateAppliedCondition(ctx, work,
metav1.ConditionTrue, "AppliedSuccessful", ...)
}
tryCreateOrUpdateWorkload - 资源操作
func (c *Controller) tryCreateOrUpdateWorkload(
ctx context.Context,
clusterName string,
workload *unstructured.Unstructured,
) error {
// 1. 构造 FederatedKey(用于标识资源)
fedKey, err := keys.FederatedKeyFunc(clusterName, workload)
// 2. 尝试从成员集群获取资源(通过 Informer 缓存)
clusterObj, err := helper.GetObjectFromCache(
c.RESTMapper, c.InformerManager, fedKey,
)
if err != nil {
if !apierrors.IsNotFound(err) {
return err
}
// 3. 资源不存在,创建
err = c.ObjectWatcher.Create(ctx, clusterName, workload)
metrics.CountCreateResourceToCluster(...)
return err
}
// 4. 资源已存在,更新
operationResult, err := c.ObjectWatcher.Update(ctx, clusterName, workload, clusterObj)
metrics.CountUpdateResourceToCluster(...)
return err
}
ObjectWatcher 的作用:
- 封装了对成员集群资源的操作(Create/Update/Delete)
- 使用成员集群的 kubeconfig 连接成员集群 API
- 支持冲突检测和重试
4.4 Work Status Controller - 状态同步
代码位置:pkg/controllers/status/work_status_controller.go
工作原理
// Work Status Controller 监听成员集群的资源变化
// 当资源状态改变时,同步到控制平面的 Work.Status
func (c *WorkStatusController) Reconcile(ctx context.Context, req controllerruntime.Request) (controllerruntime.Result, error) {
// 1. 获取 Work 对象
workObject := &workv1alpha1.Work{}
// 2. 从 Work.Spec 获取期望的资源信息
// 3. 从成员集群获取实际资源状态
observedObj, err := c.getObservedWorkload(ctx, fedKey, workObject)
// 4. 检查资源是否需要更新(防止成员集群中的意外修改)
needUpdate := c.ObjectWatcher.NeedsUpdate(clusterName, desiredObj, observedObj)
if needUpdate {
// 如果成员集群中的资源被意外修改,重新应用期望状态
c.ObjectWatcher.Update(ctx, clusterName, desiredObj, observedObj)
}
// 5. 同步状态到 Work
return c.reflectStatus(ctx, workObject, observedObj)
}
关键功能:
- 状态收集:从成员集群获取资源的实际状态
- 状态反射:将状态写入 Work.Status
- 一致性保证:检测成员集群中的意外修改并纠正
4.5 Cluster Status Controller - 集群状态同步
代码位置:pkg/controllers/status/cluster_status_controller.go
状态收集流程
func (c *ClusterStatusController) syncClusterStatus(
ctx context.Context,
cluster *clusterv1alpha1.Cluster,
) error {
// 1. 创建成员集群的客户端
clusterClient, err := c.ClusterClientSetFunc(
cluster.Name, c.Client, c.ClusterClientOption,
)
// 2. 检查集群健康状态
online, healthy := getClusterHealthStatus(clusterClient)
observedReadyCondition := generateReadyCondition(online, healthy)
// 3. 如果集群不健康,直接更新状态并返回
if !online && readyCondition.Status != metav1.ConditionTrue {
return updateStatusCondition(ctx, c.Client, cluster, readyCondition)
}
// 4. 收集详细状态信息
if online && healthy && readyCondition.Status == metav1.ConditionTrue {
// 4.1 获取 Kubernetes 版本
kubernetesVersion, err := getKubernetesVersion(clusterClient)
// 4.2 获取 API 资源列表
apiEnablements, err := getAPIEnablements(clusterClient)
// 4.3 获取节点摘要
nodeSummary, err := getNodeSummary(nodes)
// 4.4 获取资源摘要(可分配、已分配、等待分配)
resourceSummary, err := getResourceSummary(nodes, pods)
// 4.5 更新 Cluster.Status
cluster.Status.KubernetesVersion = kubernetesVersion
cluster.Status.APIEnablements = apiEnablements
cluster.Status.NodeSummary = nodeSummary
cluster.Status.ResourceSummary = resourceSummary
}
// 5. 更新状态到控制平面
return c.updateStatusIfNeeded(ctx, cluster, currentClusterStatus, readyCondition)
}
Pull 模式的 Lease 机制
对于 Pull 模式的集群,Agent 通过 Lease 对象发送心跳:
// 在 Cluster Status Controller 中
if cluster.Spec.SyncMode == clusterv1alpha1.Pull {
// 初始化 Lease Controller
c.initLeaseController(cluster)
}
// Lease Controller 定期更新 Lease 对象
// 控制平面的 Cluster Controller 通过检查 Lease 来判断 Agent 是否存活
Lease 机制:
- Agent 在控制平面创建/更新 Lease 对象
- Lease 包含
RenewTime字段,定期更新 - 控制平面检查 Lease 的更新时间,判断 Agent 是否存活
4.6 双客户端架构
Agent 使用双客户端架构,分别连接控制平面和成员集群:
// 控制平面客户端(用于读取 Work、更新 Work.Status)
controlPlaneRestConfig, err := apiclient.RestConfig(
opts.KarmadaContext, opts.KarmadaKubeConfig,
)
controlPlaneKubeClient := kubeclientset.NewForConfigOrDie(controlPlaneRestConfig)
karmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
// 成员集群客户端(用于操作成员集群资源)
clusterConfig, err := controllerruntime.GetConfig() // 使用 Pod 的 ServiceAccount
clusterKubeClient := kubeclientset.NewForConfigOrDie(clusterConfig)
// ObjectWatcher 使用成员集群客户端
objectWatcher := objectwatcher.NewObjectWatcher(
mgr.GetClient(), // 控制平面客户端
mgr.GetRESTMapper(),
util.NewClusterDynamicClientSetForAgent, // 成员集群客户端工厂
...
)
4.7 ObjectWatcher - 资源操作封装
代码位置:pkg/util/objectwatcher/objectwatcher.go
ObjectWatcher 封装了对成员集群资源的操作:
type ObjectWatcher interface {
// 创建资源
Create(ctx context.Context, clusterName string, obj *unstructured.Unstructured) error
// 更新资源(支持冲突检测)
Update(ctx context.Context, clusterName string, desired, observed *unstructured.Unstructured) (operationResult string, error)
// 删除资源
Delete(ctx context.Context, clusterName string, obj *unstructured.Unstructured) error
// 检查是否需要更新
NeedsUpdate(clusterName string, desired, observed *unstructured.Unstructured) bool
}
关键特性:
- 冲突检测:检测成员集群中的意外修改
- 重试机制:自动重试失败的操作
- 资源转换:使用 Resource Interpreter 转换资源格式
- 批量操作:支持批量创建/更新资源
五、总结
5.1 Agent 的核心价值
- Pull 模式支持:实现网络隔离场景下的多集群管理
- 资源执行终端:将控制平面的决策转换为实际资源
- 状态反向同步:实现控制平面与成员集群的状态一致性
- 集群注册代理:自动完成集群注册和凭证管理
5.2 关键设计模式
| 模式 | 说明 |
|---|---|
| 双客户端架构 | 分别连接控制平面(读 Work)和成员集群(写资源) |
| ExecutionSpace 隔离 | 每个集群有独立的命名空间,Work 对象隔离 |
| Leader Election | 支持多副本高可用部署 |
| Lease 心跳 | Pull 模式下通过 Lease 证明 Agent 存活 |
| 状态缓存 | 使用 Informer 缓存减少 API 调用 |
5.3 Agent vs 控制平面的 Execution Controller
| 特性 | Agent (Pull 模式) | Execution Controller (Push 模式) |
|---|---|---|
| 部署位置 | 成员集群 | 控制平面 |
| 连接方向 | 成员集群 → 控制平面 | 控制平面 → 成员集群 |
| 网络要求 | 成员集群可访问控制平面 | 控制平面可访问成员集群 |
| 适用场景 | 网络隔离、安全限制 | 网络可达 |
| 心跳机制 | Lease 对象 | 不需要 |
5.4 工作流程总结
用户创建 Deployment + PropagationPolicy
↓
控制平面:Detector → ResourceBinding → Scheduler → Work
↓
Work 存储在 ExecutionSpace (karmada-es-member1)
↓
成员集群:Agent 的 Execution Controller 监听 Work
↓
Agent 从 Work.Spec.Workload.Manifests 提取资源
↓
Agent 使用成员集群客户端创建/更新资源
↓
成员集群:资源创建成功
↓
Agent 的 Work Status Controller 收集资源状态
↓
Agent 更新 Work.Status 到控制平面
↓
控制平面:Work.Status 被聚合到 ResourceBinding.Status
参考资源
- 源码位置:
- Agent 入口:
cmd/agent/app/agent.go - Execution Controller:
pkg/controllers/execution/execution_controller.go - Work Status Controller:
pkg/controllers/status/work_status_controller.go - Cluster Status Controller:
pkg/controllers/status/cluster_status_controller.go - ObjectWatcher:
pkg/util/objectwatcher/objectwatcher.go
- Agent 入口:
- 官方文档:https://karmada.io/docs/
- 部署清单:
artifacts/agent/karmada-agent.yaml

浙公网安备 33010602011771号