ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cilium ClusterMesh 中的 Multi-Cluster Services API(MCS-API)实现深度解析

Cilium ClusterMesh 中的 Multi-Cluster Services API(MCS-API)实现深度解析 Cilium ClusterMesh 中的 Multi-Cluster Services APIMCS-API实现深度解析【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/ciliumMulti-Cluster Services APIMCS-API是 Kubernetes 社区定义的、将单一集群的 Service 概念扩展到多集群场景的标准 API。本文以 pkg/clustermesh/mcsapi/README.md 为骨架结合 Cilium 仓库中pkg/clustermesh/mcsapi目录下的控制器源码、类型定义与测试深入讲解 Cilium 如何通过三个 reconciler 控制器、一个集群间共享 store 以及派生 Service 机制把 MCS-API 的ServiceExport/ServiceImport资源无缝接入既有 ClusterMesh 数据面。读完本文你将掌握 MCS-API 在 Cilium 中的完整数据流、冲突解决策略、派生 Service 命名规则、启用方式与可观测手段能够独立排查多集群服务导入/导出问题。MCS-API 是什么从 Service 到多集群服务MCS-APIMulti-Cluster Services API是一套标准 API用于将 Kubernetes 的 Service 概念扩展至多个集群。它建立在两个新的 CRD 之上ServiceExport一个轻量资源标记同命名空间、同名的 Service 需要被导出到其他集群。它本身不包含任何服务规格仅仅是一个导出意图声明。ServiceImport完全由实现方在 Cilium 中由一个 controller 管理维护的资源表示所有被导出 Service 的聚合视图通常由导入方集群本地集群消费。在 Cilium 的代码库中这两个 CRD 的启用、安装与校验集中在 cell.go控制器启动时会检查serviceimports与serviceexports两个 GroupVersionKind 对应的 CRD 是否已存在若未安装且配置要求自动安装则通过 crdinstall.go 中基于 mcs-api 官方预生成 CRD 二进制mcsapicrd.ServiceImportCRD/mcsapicrd.ServiceExportCRD的createCustomResourceDefinitions完成创建与版本升级。注KEP-1645Multi-Cluster Services API 的增强提案定义了该 API 的语义与约束包括下文会提到的冲突解决规则本仓库的conformance子目录还提供了对 MCS-API 的符合性测试入口见 conformance_test.go 的TestConformance。Cilium 中的实现架构共享 Store 三个控制器Cilium 对 MCS-API 的实现并不像某些实现那样在各集群之间直接读写对方 API Server而是复用了 ClusterMesh 自身的跨集群同步通道集群间通过 kvstoreClusterMesh API Server交换信息。整体架构由以下几部分组成MCSAPIServiceSpec结构体承载被导出服务同名的 Service ServiceExport的字段定义在 types/mcsapiservicespec.go。集群间同步MCSAPIServiceSpec像其他 ClusterMesh 结构体一样被同步到 ClusterMesh API Server各集群再从中拉取远端信息。mcsAPIServiceImportReconciler控制器从所有集群拉取 Service 导出信息重构出本地的ServiceImport资源。mcsAPIServiceReconciler控制器根据ServiceImport创建名为derived-$hash的内部 Service以触发普通 global Service 的既有机制ClusterIP 生成、远端 Endpoint 同步到 BPF Map、EndpointSliceSync 等并把派生 Service 的 IP 回写到ServiceImport。mcsAPIEndpointSliceMirrorReconciler控制器把本地 Service 的 EndpointSlice 镜像到派生 Service确保本地端点能被远程集群访问。DNS 支持依赖 multicluster CoreDNS 插件该插件查询ServiceImport与 EndpointSlice 资源来完成跨集群 DNS 解析。下图完整展示了这一数据流源自 README 中的流程图核心数据结构MCSAPIServiceSpec与 kvstore 同步MCSAPIServiceSpec是 Cilium 内部用于跨集群传递被导出服务信息的载体定义在 types/mcsapiservicespec.go其字段完整覆盖了 MCS-API 关心的服务属性字段类型说明Clusterstring服务所在集群名称Name/Namespacestring对应 ServiceExport / ServiceImport 资源的名称与命名空间Annotations/Labelsmap从 ServiceExport 的spec.exportedAnnotations/spec.exportedLabels复制而来ExportCreationTimestampmetav1.TimeServiceExport 的创建时间用于冲突解决谁更早谁优先Ports[]mcsapiv1beta1.ServicePort以 MCS API 格式表示的 Service 端口列表TypeServiceImportType只能是ClusterSetIP或HeadlessSessionAffinitycorev1.ServiceAffinity仅支持ClientIP与None默认Headless 类型时忽略SessionAffinityConfig*corev1.SessionAffinityConfig会话保持配置如 ClientIP 超时时间IPFamilies[]corev1.IPFamilyServiceImport 分配的 IP 协议族InternalTrafficPolicy*ServiceInternalTrafficPolicyLocal或Cluster默认控制节点上 ClusterIP 流量的分发范围TrafficDistribution*string流量分发偏好如PreferClose、PreferSameZone、PreferSameNode该结构体通过 kvstore 共享 store 跨集群同步store 前缀为ServiceExportStorePrefix即kvstore.BaseKeyPrefix/state/serviceexports/v1见 mcsapiservicespec.go且被标记为STABLE API——修改其结构或 key 格式会破坏向后兼容性。每个对象的 kvstore key 由GetKeyName()生成格式为cluster/namespace/name。值得注意的细节反序列化校验Unmarshal会先做 JSON 解析再调用validate()检查各必填字段与枚举合法性如 Type 必须为ClusterSetIP或Headless、SessionAffinity 必须为ClientIP或None、InternalTrafficPolicy / TrafficDistribution 取值必须合法见 mcsapiservicespec.go。额外校验器ValidatingMCSAPIServiceSpec支持注入ClusterNameValidator校验 cluster 字段与预期一致和NamespacedNameValidator校验 key 与 NamespacedName 匹配防止跨集群数据串扰见 mcsapiservicespec.go。本地服务转换FromCiliumServiceToMCSAPIServiceSpec负责把本地的 slim Service ServiceExport 转换为MCSAPIServiceSpec其中ClusterIP: None的服务会被判定为Headless类型否则为ClusterSetIP见 mcsapiservicespec.go。导出合法性检查CheckLocalSvcValidForExport明确拒绝ExternalName类型的 Service 导出返回ServiceExportReasonInvalidServiceType其 slim 版本CheckLocalSlimSvcValidForExport逻辑必须与其保持一致源码注释中明确要求两者同步维护见 mcsapiservicespec.go。远端数据的订阅由serviceExportObserver完成见 observer.go它会根据远端集群的CiliumClusterConfig能力声明决定是否启用——只有远端集群声明支持ServiceExportsEnabled且本地启用了 MCS-API 时才注册 watch否则会 Drain 掉已有数据并记录警告Remote cluster does not support MCS-API service export resources。每个远端服务的更新/删除事件都会同步写入本地的globalServiceExports缓存并通过RemoteObjectSource触发控制器。控制器一mcsAPIServiceImportReconciler——导入与冲突解决这是 MCS-API 实现中最核心的控制器实现在 serviceimport_controller.go。它的职责是根据来自远端集群经 kvstore与本地的全部 ServiceExport及对应 Service自动创建/更新ServiceImport资源同时维护本地ServiceExport的状态条件。触发源控制器通过SetupWithManager注册对以下资源的 watch见 serviceimport_controller.goServiceImport主资源ForServiceExport的变化Service的变化Namespace的变化用于在命名空间标签/配置变化时重排队导入导出远端服务的 raw source来自共享 store 的远端事件。命名空间门控每个命名空间是否可导出/可导入取决于isNamespaceGlobal判断见 serviceimport_controller.go其依据是cmnamespace.IsGlobalNamespace与GlobalNamespacesByDefault配置。若命名空间不是 global 而本地存在 ServiceExport控制器会写入ValidFalsereason 为NamespaceNotGlobal与ReadyFalse条件若命名空间不是 globalServiceImport的Ready条件也会被置为Falsereason 同样为NamespaceNotGlobal见 serviceimport_controller.go。冲突解决策略导入时处理README 特别强调了一个与部分其他实现不同的设计决策Cilium 在导入时import time处理冲突而不是在导出方检查。原因在于 Cilium 的导出路径是把自己的信息更新到本地 ClusterMesh API Server而导入路径是聚合所有 ClusterMesh API Server 的信息——冲突只有在聚合时才能被完整发现。不过冲突信息仍会以条件形式回写到导出方的ServiceExport对象上。冲突解决的基准规则是按ExportCreationTimestamp从旧到新排序以最旧最早创建的 ServiceExport 为准。排序函数orderSvcExportByPriority在时间戳相同时还会按集群名排序保证结果确定性见 serviceimport_controller.go。具体冲突检查分三个层次端口合并mergePortsserviceimport_controller.go按端口号协议合并所有导出的端口若出现同名端口定义不一致、同名端口冲突appProtocol不一致或某集群端口与最旧导出的端口集合不匹配则记录ServiceExportReasonPortConflict并采用最旧导出方的端口定义。IP 协议族交集intersectIPFamiliesserviceimport_controller.go对所有导出的 IPFamilies 取交集而非并集——因为期望所有 Pod 在导出的每个 IP 族都有端点交集能保证客户端无论用哪个 IP 协议都能到达全部 Pod若取并集可能只能到达 Pod 的一个子集。若某集群与现有交集无公共 IP 族会跳过该集群并报告ServiceExportReasonIPFamilyConflict。为空 IPFamilies 的导出会被跳过以兼容 Cilium 1.18 及更早版本。其余字段一致性checkConflictExportserviceimport_controller.go对type、sessionAffinity、sessionAffinityConfig.clientIP、annotations、labels、internalTrafficPolicy、trafficDistribution七个字段逐一比对任一字段有集群与最旧导出不一致即返回对应 reason如TypeConflict、SessionAffinityConflict、AnnotationsConflict等消息形如Conflicting field. N/M clusters disagree. Using value from oldest service export in cluster cluster.ServiceImport 的生成与状态回写合并后的结果会写入ServiceImport.SpecPorts、IPFamilies、Type、SessionAffinity、InternalTrafficPolicy、TrafficDistribution并以最旧导出方的 Labels/Annotations 为准同时会设置annotation.SupportedIPFamilies内部注解记录本地集群实际支持的 IP 族filterSupportedIPFamilies会根据本地是否启用 IPv4/IPv6 过滤见 serviceimport_controller.go。随后通过createOrUpdateServiceImport基于controllerutil.CreateOrUpdate幂等地创建或更新资源。ServiceImport.Status会记录status.clusters当前支撑该 ServiceImport 的所有集群列表status.endpointSliceObjects根据annotation.GlobalServiceSyncEndpointSlices注解或 Headless 类型判断 EndpointSlice 对象是否存在getEndpointSliceObjectsStatus见 serviceimport_controller.goReady条件本地不支持任何导入的 IP 族时为FalsereasonIPFamilyNotSupported已存在派生 Service 注解时为TruereasonReady否则为FalsereasonPending等待派生 Service 创建。本地ServiceExport的Valid、Ready、Conflict三个条件也在该控制器内维护合法则ValidTrue、ReadyTrue有冲突则ConflictTrue并携带具体 reason 与描述否则ConflictFalsereasonNoConflicts。控制器二mcsAPIServiceReconciler——派生 Service 与 IP 回写ServiceImport本身不会直接驱动数据面真正的接入点是派生 Servicederived Service。mcsAPIServiceReconciler实现在 service_controller.go负责把ServiceImport转成一个普通的、带 Cilium global 注解的 Service从而免费继承 ClusterMesh 既有的全部机制。命名规则derived-$hash派生 Service 的名字由derivedName函数生成service_controller.gofunc derivedName(name types.NamespacedName) string { hash : sha256.New() hash.Write([]byte(name.String())) return derived- strings.ToLower(base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString(hash.Sum(nil)))[:10] }即对namespace/name做 SHA-256再用无填充的 Base32HEX 编码、小写取前 10 个字符。该函数来自 mcs-api 官方仓库的common.go保证了与生态实现的一致性。派生 Service 的关键属性在Reconcile中service_controller.go派生 Service 会被构造为Type: ClusterIPIPFamilyPolicy: PreferDualStack始终偏好双栈实际 IP 族以supported-ip-families注解为准若 ServiceImport 为Headless类型则ClusterIP: NoneSelector置空map[string]string{}端口从 ServiceImport 继承OwnerReference 指向 ServiceImportctrl.SetControllerReference保证 ServiceImport 删除时派生 Service 被级联清理注解复制自 ServiceImport并强制追加service.cilium.io/global: trueannotation.GlobalService正是这个注解让它进入 ClusterMesh 的 global Service 处理流程触发远端 Endpoint 到 BPF Map 的同步、EndpointSliceSync 等既有能力见 pkg/annotation/k8s.go标签复制自 ServiceImport并追加multicluster.x-k8s.io/service-namemcsapiv1beta1.LabelServiceName指向原始服务名。双栈与 Headless 迁移getBaseDerivedServiceservice_controller.go会处理两类边界情况强制双栈迁移对于 Cilium 1.18 或更早版本创建的旧派生 Service强制把IPFamilyPolicy改为PreferDualStackHeadless 切换如果派生 Service 已存在但它的 headless 属性与当前 ServiceImport 类型不一致例如从 ClusterSetIP 切换为 Headless会先删除旧 Service 再以新的形态重建避免直接更新被 API Server 拒绝。IP 回写创建/更新派生 Service 后patchServiceImportservice_controller.go会把两件事写回 ServiceImport注解multicluster.x-k8s.io/derived-serviceDerivedServiceAnnotation指向派生 Service 名spec.ips更新为派生 Service 的 ClusterIPs——IP 的选取顺序严格跟随supported-ip-families注解getDesiredIPs会按 IP 族顺序从 ClusterIPs 中挑 IPv4/IPv6见 service_controller.go。这样消费ServiceImport的 DNS 插件等组件就能拿到最终的虚拟 IP。控制器三mcsAPIEndpointSliceMirrorReconciler——本地 EndpointSlice 镜像多集群服务不仅要有 IP还要把每个集群的端点Endpoints彼此可见。远端端点由 ClusterMesh 既有流程负责而本地端点的对外可见性则由mcsAPIEndpointSliceMirrorReconciler承担实现在 endpointslice_mirror_controller.go。该控制器把本地 Service 的每个 EndpointSlice镜像到派生 Service 对应的 EndpointSlice命名规则为derivedServiceName - 本地EndpointsSlice后缀getLocalDerivedEndpointSliceKey见 endpointslice_mirror_controller.go并打上endpointslice-local-mcsapi-controller.cilium.io的endpointslice.kubernetes.io/managed-by标签。镜像过程包含三层过滤IP 族过滤只镜像与派生 Service 支持的 IP 族supported-ip-families注解匹配的 EndpointSliceshouldMirrorLocalEndpointSlice见 endpointslice_mirror_controller.go端口过滤getFilteredPortsendpointslice_mirror_controller.go按端口名把本地 Service 端口与派生 Service 端口对齐若某端口发生冲突端口号或协议不一致则该端口会被跳过——既不会导给本地也不会导给远端镜像产物维护若全部端口被过滤掉、或本地 EndpointSlice 被删除/不再可镜像控制器会清理对应的派生 EndpointSlice对无法回溯到源 EndpointSlice 的被篡改派生 EndpointSlice会走reconcileMalformedDerivedEndpointSlice路径带 UID/ResourceVersion 前置条件删除之见 endpointslice_mirror_controller.go。派生 EndpointSlice 同样以派生 Service 为 Owner并带有multicluster.x-k8s.io/service-name、multicluster.x-k8s.io/source-cluster等标签便于下游识别其来源。如何启用配置项与 CRD 安装MCS-API 支持在 Cilium Operator 中通过两个布尔 flag 控制定义于 types/config.goFlag默认值说明--clustermesh-enable-mcs-apifalse启用 ClusterMesh MCS-API 支持--clustermesh-mcs-api-install-crdstrue是否自动安装并管理 MCS-API CRD仅在启用 MCS-API 时生效只有当EnableMCSAPI InstallCRDs都为真时Operator 才会通过newMCSAPICRDs注册 CRD 安装函数见 cell.go若未启用自动安装则控制器启动时会主动检查所需 CRD 是否存在缺失即报错退出见 cell.go。从模块组织看整个 MCS-API 功能被封装为 Hive 的一个 cellmcsapi见 cell.go依赖 Operator 的 ClusterMesh 组件、控制器运行时 Manager、kvstore store 工厂等并在 bootstrap 时等待 ClusterMesh 的 observer 同步完成后才注册 ServiceImport 控制器job.OneShot(mcsapi-main)见 cell.go。因此启用前提还包括已部署 ClusterMesh含 kvstoremesh、命名空间已标记为 global或配置了GlobalNamespacesByDefault以及按官方文档安装 multicluster CoreDNS 插件用于 DNS 解析。相关注解速查MCS-API 实现依赖或写入以下 Cilium 注解常量定义见 pkg/annotation/k8s.go注解值作用service.cilium.io/globaltrue标记派生 Service 为 global Service接入 ClusterMesh 数据面service.cilium.io/global-sync-endpoint-slicestrue是否把远端集群的 EndpointSlice 同步到本地 Kubernetes APIHEADLESS 类型默认同步service.cilium.io/sharedtrue/false是否分享本地端点false时仅暴露远端端点service.cilium.io/affinitylocal/remote/none端点亲和偏好默认nonecilium.io/supported-ip-familiesIP 族列表MCS-API 内部注解记录本地集群支持并使用的 IP 族multicluster.x-k8s.io/derived-service派生 Service 名由 mcs-api 控制器写入 ServiceImport指向派生 Service可观测性与验证Prometheus 指标MCS-API 提供两类指标见 metrics.go按远端集群统计的导出数量cilium_operator_clustermesh_remote_cluster_service_exports{target_cluster...}Metrics.TotalServiceExports由 observer 在 kvstore watch 时维护由mcsAPICollector收集的本地集群资源指标subsystemmcsapicilium_operator_mcsapi_serviceexport_info{serviceexport,namespace}cilium_operator_mcsapi_serviceexport_status_condition{serviceexport,namespace,condition,status,reason}cilium_operator_mcsapi_serviceimport_info{serviceimport,namespace}cilium_operator_mcsapi_serviceimport_status_condition{serviceimport,namespace,condition,status,reason}cilium_operator_mcsapi_serviceimport_status_clusters{serviceimport,namespace}当前支撑该 ServiceImport 的集群数这些指标与ServiceExport/ServiceImport的status.conditions一一对应可直接用于告警例如Conflict条件为 True、Ready条件长期为 False。符合性测试仓库在 conformance/conformance_test.go 中通过testutils.MCSAPIConformanceTest运行 mcs-api 官方的 MCS-API 符合性测试此外serviceimport_controller_test.go、service_controller_test.go 与 endpointslice_mirror_controller_test.go 分别覆盖了端口合并冲突、IP 族交集、派生 Service 创建与镜像等关键逻辑是理解各控制器行为的绝佳样例。小结与排障线索回顾 Cilium 中 MCS-API 的完整闭环本地/远端集群的用户创建ServiceServiceExportCilium 把它转换为MCSAPIServiceSpec写入各自 ClusterMesh API Serverkvstore导入方集群通过 observer 拉取所有集群的导出信息mcsAPIServiceImportReconciler按最旧优先原则做冲突解决聚合生成ServiceImportmcsAPIServiceReconciler依据ServiceImport创建derived-$hash派生 Service带service.cilium.io/global: true使其进入既有 ClusterMesh global Service 流程并把 IP 回写ServiceImportmcsAPIEndpointSliceMirrorReconciler把本地 EndpointSlice 镜像到派生 Service完成端点互通multicluster CoreDNS 插件消费ServiceImport与 EndpointSlice提供跨集群 DNS 名称解析。排查问题时可按此链路逐层检查先看ServiceExport的Valid/Conflict条件确认是否被ExternalName、命名空间非 global 或端口/字段冲突阻断再看ServiceImport的Ready条件与status.clusters确认是否已聚合到预期集群、IP 族是否被本地支持最后确认派生 Service 的service.cilium.io/global注解与multicluster.x-k8s.io/derived-service注解是否就位并结合上文列出的 Prometheus 指标判断异常阶段。【免费下载链接】ciliumeBPF-based Networking, Security, and Observability项目地址: https://gitcode.com/GitHub_Trending/ci/cilium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表