- 后端
- 消息队列
- 微服务
- 消息路由
【免费下载链接】CAP
Distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern
本文围绕 CAP(基于 Outbox 模式的分布式事务与事件总线框架)Dashboard 的 Kubernetes(K8s)服务发现能力展开,讲解如何通过UseK8sDiscovery()让 Dashboard 自动发现集群内各 CAP 服务节点、授予 Pod 访问 Kubernetes API 所需的 RBAC 权限、使用标签控制节点可见性与端口选择,以及如何将 Dashboard 作为独立 Pod 部署。读完本文,你将掌握一套可直接落地的 K8s 环境下 CAP Dashboard 多节点数据查看的完整配置方案。
背景:为什么需要 Kubernetes 服务发现
CAP Dashboard 默认只能查看当前进程所在节点的发布/订阅消息数据。在多副本、多节点部署的微服务架构中,运维与排查人员往往需要跨节点查看数据。自 CAP 7.2.0 起,Dashboard 内置了基于 Kubernetes 的服务发现机制:进入 Dashboard 的Nodes页面,选择命名空间后,CAP 会调用 Kubernetes API 列出该命名空间下的所有 Service;点击Switch(切换)按钮后,Dashboard 会先探测目标节点上的 CAP 服务是否可用,可用则通过网关代理切换到该节点查看其数据。
这一能力对应的实现位于仓库 DotNetCore.CAP.Dashboard.K8s 项目中,其核心是K8sNodeDiscoveryProvider,它实现统一的服务发现接口 INodeDiscoveryProvider,提供GetNodes、GetNamespaces、ListServices等能力,供 Dashboard 的 Nodes 页面消费。
快速开始:启用 K8s 服务发现
在配置 CAP 时同时调用UseDashboard()与UseK8sDiscovery()即可启用:
services.AddCap(x => { // ... 其他 CAP 配置(如消息存储、传输) x.UseDashboard(); x.UseK8sDiscovery(); });UseK8sDiscovery()是无参重载,对应源码见 K8sDiscoveryOptionsExtensions.cs,其内部会注册K8sDiscoveryOptions为单例,并注册GatewayProxyAgent、IHttpRequester、IHttpClientCache、IRequestMapper以及INodeDiscoveryProvider(实现为K8sNodeDiscoveryProvider),从而打通“发现节点 → 代理请求”的完整链路。
启用后,Dashboard 会尝试自动检测自身是否运行在 Kubernetes 集群内部(通过默认的KubernetesClientConfiguration.BuildDefaultConfig()加载集群内配置,见 K8sDiscoveryOptions.cs)。如果运行在集群内部,则必须为 Pod 授予 Kubernetes API 访问权限,否则节点列表无法加载。
ShowOnlyExplicitVisibleNodes:默认是否列出所有 Service
ShowOnlyExplicitVisibleNodes用于控制 Nodes 页面默认是否列出命名空间内的每一个 K8s Service:
- 文档说明的默认值为
false:默认列出所有 Service; - 当前仓库源码 K8sDiscoveryOptions.cs 的构造函数中实际初始化为
true,即默认只列出带有dotnetcore.cap.visibility: show标签的 Service。
两种配置行为差异明显,建议在部署时显式设置该选项,避免依赖默认值产生歧义:
services.AddCap(x => { // ... x.UseDashboard(); x.UseK8sDiscovery(opt => { opt.ShowOnlyExplicitVisibleNodes = true; }); });从源码 K8sNodeDiscoveryProvider.cs 的FilterNodesByTags逻辑可以看到该选项的实际处理:当选项为true时,只有携带dotnetcore.cap.visibility: show标签的 Service 才会出现在节点列表中;而显式携带hide标签的 Service 无论如何都会被过滤掉。当选项为false时,只有显式标记为hide的 Service 会被隐藏,其余全部列出。
授予 Pod 访问 Kubernetes API 的权限
组件运行在集群内部时需要调用 Kubernetes API 列出命名空间与 Service,因此若 Deployment 关联的 ServiceAccount 没有对应权限,需要授予namespaces、services资源的get、list(文档示例中同时包含watch)权限。
典型做法是:先创建ServiceAccount与ClusterRole并设置权限,再通过ClusterRoleBinding绑定,最后在 Deployment 中通过serviceAccountName指定。完整示例 YAML 如下(来自官方文档,可直接套用):
apiVersion: v1 kind: ServiceAccount metadata: name: api-access --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: ns-svc-reader rules: - apiGroups: [""] resources: ["namespaces", "services"] verbs: ["get", "watch", "list"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: read-pods subjects: - kind: ServiceAccount name: api-access namespace: default roleRef: kind: ClusterRole name: ns-svc-reader apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: api-access-deployment spec: replicas: 1 selector: matchLabels: app: api-access-app template: metadata: labels: app: api-access-app spec: serviceAccountName: api-access containers: - name: api-access-container image: your_image --- apiVersion: v1 kind: Service metadata: name: api-access-service spec: selector: app: api-access-app ports: - protocol: TCP port: 80 targetPort: 80提示:Dashboard 实际读取的是集群内 ServiceAccount 的令牌与 CA 证书(
BuildDefaultConfig()),因此确保承载 Dashboard 的 Pod 以正确的 ServiceAccount 运行是关键。
8.3.0 起:使用 Role 限定命名空间内权限
从版本8.3.0开始,可以使用Role替代ClusterRole,让 Dashboard 仅能发现其自身所在命名空间内的 Service,遵循最小权限原则。Role的作用域限定在单个命名空间内。将上述示例中的ClusterRole与ClusterRoleBinding替换为如下内容即可:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: ns-svc-reader rules: - apiGroups: [""] resources: ["services"] verbs: ["get", "watch", "list"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: read-pods subjects: - kind: ServiceAccount name: api-access namespace: default roleRef: kind: ClusterRole name: ns-svc-reader apiGroup: rbac.authorization.k8s.io需要注意的是,文档中的 Role 方案示例依然通过ClusterRoleBinding将 Role 绑定到 ServiceAccount(将 Role 与命名空间内的 ServiceAccount 绑定时也可使用同命名空间的RoleBinding,效果等同且作用域更收敛)。采用 Role 后,GetNamespaces返回的候选列表会受限——源码 K8sNodeDiscoveryProvider.cs 显示:当命名空间列表 API 调用失败时,会回退到返回当前K8SClientConfig.Namespace,保证 Dashboard 仍能正常工作。
通过标签控制节点列表与端口
Kubernetes 标签(Labels)是控制 Dashboard 节点列表最灵活的手段,所有 CAP 相关标签统一使用dotnetcore.cap前缀(源码中定义为TagPrefix,见 K8sNodeDiscoveryProvider.cs)。
节点可见性:dotnetcore.cap.visibility
- 取值:
show|hide - 示例:
dotnetcore.cap.visibility: show或dotnetcore.cap.visibility: hide
hide优先级最高——无论ShowOnlyExplicitVisibleNodes如何设置,携带hide标签的 Service 都不会出现在列表中(对应 IsNodeHidden 的实现);当选项为true时,未携带任何 visibility 标签或值不是show的 Service 同样被隐藏。
端口选择:dotnetcore.cap.portName
默认情况下,每个 K8s Service 使用其端口列表中的第一个端口(索引 0)作为节点端口。当 Service 暴露多个端口时,可通过端口名称精确指定:
- 取值:字符串(对应 Service 端口的
name字段) - 示例:
dotnetcore.cap.portName: grpc或dotnetcore.cap.portName: http
端口选择:dotnetcore.cap.portIndex
若未设置portName,或设置的portName在 Service 端口列表中找不到匹配项,则会尝试按索引匹配:
- 取值:以字符串表示的数组下标,如
'2'、'14' - 示例:
dotnetcore.cap.portIndex: '1'或dotnetcore.cap.portIndex: '3'
若索引越界,则回退到第一个端口(索引 0)。
端口解析的完整优先级可在源码 GetPortByNameOrIndex 中确认:先按portName查找,命中则返回;未命中则按portIndex查找;仍未命中则回退到Ports[0]。标签解析过程位于 FilterNodesByTags,其中portIndex值需要能被int.TryParse成功解析才会生效,多个同名标签同时存在时以最后一个为准。
一个完整的带标签 Service 示例
为便于理解,下面给出一个同时使用可见性与端口标签的 Service 配置:
apiVersion: v1 kind: Service metadata: name: cap-node labels: dotnetcore.cap.visibility: show dotnetcore.cap.portName: http spec: selector: app: cap-node ports: - name: grpc protocol: TCP port: 50051 targetPort: 50051 - name: http protocol: TCP port: 80 targetPort: 80在该配置下(ShowOnlyExplicitVisibleNodes = true),cap-node会出现在节点列表中,且 Dashboard 通过http://cap-node.<namespace>:80访问其 CAP 服务。
独立使用 Dashboard:无需配置 CAP 的纯查看 Pod
在 Dashboard 仅用于跨节点查看数据的场景下,可以将它作为独立的 Pod 部署,而待查看的业务服务无需再配置cap.UseK8sDiscovery()。只需调用:
services.AddCapDashboardStandalone();该扩展方法位于 ServiceCollectionExtensions.cs,其内部同时注册了DashboardOptionsExtension与K8sDiscoveryOptionsExtension,并且支持两个可选参数分别配置 Dashboard 与 K8s 发现选项:
services.AddCapDashboardStandalone( opt => { /* Dashboard 配置 */ }, opt => { opt.ShowOnlyExplicitVisibleNodes = true; });同样,承载独立 Dashboard 的 Pod 也需要为其 ServiceAccount 配置上文提到的 Kubernetes API 访问权限。
源码级工作原理小结
从仓库实现看,K8s 服务发现的完整数据流如下:
- Nodes 页面请求命名空间列表与节点列表;
- K8sNodeDiscoveryProvider 通过
KubernetesClient(当前项目引用KubernetesClient19.0.2,见 DotNetCore.CAP.Dashboard.K8s.csproj)调用ListNamespacedServiceAsync、ReadNamespacedServiceAsync、ListNamespaceAsync等 API; - 每个 Service 被映射为 Node 对象,其中
Address形如http://<service>.<namespace>,端口按标签规则解析(见 ListServices); - 点击 Switch 后,Dashboard 通过网关代理(
GatewayProxyAgent)探测并转发请求到目标节点的 CAP Dashboard 接口。
值得注意的是,节点计数会被写入CapCache.Global(60 秒缓存),供 Dashboard 的 Nodes 页面展示节点数量;任何一次 API 调用异常都会被捕获并记录日志,返回空列表,不会导致 Dashboard 整体崩溃(见 GetNodes)。
总结
- 在
AddCap中启用UseK8sDiscovery(),即可在 Dashboard Nodes 页面按命名空间发现并切换查看各 CAP 节点的数据; - 务必为运行 Dashboard 的 Pod 配置 RBAC 权限:集群范围可用
ClusterRole,自 8.3.0 起可用Role收敛到单命名空间; - 通过
dotnetcore.cap.visibility、dotnetcore.cap.portName、dotnetcore.cap.portIndex三个标签,可精确控制节点的显示/隐藏与端口选择; - 纯查看场景可使用
AddCapDashboardStandalone()将 Dashboard 独立部署,业务服务无需改动。
完整的英文原版文档见 docs/content/user-guide/en/monitoring/kubernetes.md,相关实现可在 src/DotNetCore.CAP.Dashboard.K8s 目录下深入阅读。
- 后端
- 消息队列
- 微服务
- 消息路由
【免费下载链接】CAP
Distributed transaction solution in micro-service base on eventually consistency, also an eventbus with Outbox pattern
相关推荐
Talos Linux DiscoveryServiceConfig 配置指南:为 Kubernetes 集群配置节点发现服务
Talos Linux DiscoveryServiceConfig 配置指南:为 Kubernetes 集群配置节点发现服务 导读 DiscoveryServ
云原生操作系统容器编排bark!命令行全攻略:stream、receive与stats三大核心功能详解
bark!命令行全攻略:stream、receive与stats三大核心功能详解 bark!是一款专为本地网络设计的低延迟多接收器同步音频流工具,支持48kHz
kubernetes-handbook 实战:Kubernetes Dashboard 插件的安装、RBAC 授权与访问配置指南
kubernetes handbook 实战:Kubernetes Dashboard 插件的安装、RBAC 授权与访问配置指南 导读 本文基于 kuberne
教程云原生容器编排
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考