Spring Cloud Kubernetes跨命名空间服务发现异常排查
跨命名空间服务发现问题排查与解决
问题背景
在Kubernetes的welcoming和default两个命名空间中运行Spring Boot应用,服务配置如下:
SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0: welcoming SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_1: default SPRING_CLOUD_KUBERNETES_ENABLED: true SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE: SERVICE SPRING_CLOUD_KUBERNETES_RELOAD_ENABLED: true SPRING_CLOUD_LOADBALANCER_CACHE_ENABLED: true
当welcoming命名空间的retail-onboarding服务通过RestTemplate调用default命名空间的audit-service时,抛出服务实例找不到的错误,尽管日志显示Kubernetes发现客户端已列出该服务:
2024-07-08T08:51:59.290Z DEBUG [retail-onboarding,,] 1 --- [nio-8080-exec-3] .c.k.f.d.Fabric8DiscoveryServicesAdapter : searching in namespaces : [welcoming, default] with filter : null 2024-07-08T08:51:59.336Z DEBUG [retail-onboarding,,] 1 --- [io-8080-exec-10] o.s.c.k.f.d.KubernetesDiscoveryClient : will return services : [retail-onboarding, audit-service, ingress-nginx-controller, ingress-nginx-controller-admission, kubernetes,] 2024-07-08T08:52:22.099Z ERROR [retail-onboarding,,] 1 --- [nio-8080-exec-9] c.b.f.i.a.RunWithoutAuthorizationAspect : Exception thrown when invoking join point com.backbase.audit.client.exceptions.InternalServerErrorException: java.lang.IllegalArgumentException: Service Instance cannot be null, serviceId: audit-service Caused by: java.lang.IllegalArgumentException: Service Instance cannot be null, serviceId: audit-service
切换为SPRING_CLOUD_KUBERNETES_DISCOVERY_ALL_NAMESPACES: true后,服务调用恢复正常。已配置跨命名空间服务发现的ClusterRole和ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: cross-namespace-service-discovery rules: - apiGroups: [""] resources: ["pods", "services", "endpoints"] verbs: ["get", "list", "watch"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cross-namespace-service-discovery-binding subjects: - kind: ServiceAccount name: default namespace: welcoming roleRef: kind: ClusterRole name: cross-namespace-service-discovery apiGroup: rbac.authorization.k8s.io --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cross-namespace-service-discovery-binding subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: ClusterRole name: cross-namespace-service-discovery apiGroup: rbac.authorization.k8s.io
问题原因分析
- 配置格式不兼容:
SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0/1这种索引式配置属于旧版Spring Boot绑定规则,在较新的Spring Cloud Kubernetes版本中无法被正确解析,导致指定的命名空间未被实际扫描。 - RBAC配置冲突:两个ClusterRoleBinding使用了相同的名称
cross-namespace-service-discovery-binding,后创建的绑定会覆盖前一个,导致welcoming命名空间的ServiceAccount未获得跨命名空间访问权限。 - 负载均衡缓存干扰:启用缓存后,若初始配置未生效,缓存中会保留旧的服务发现数据,即使后续配置修正,也无法立即获取跨命名空间的服务实例。
- 实例元数据缺失:虽然Discovery Client能列出服务,但可能因权限问题未拉取到
default命名空间的endpoints元数据,导致负载均衡器找不到可用实例。
解决方案
1. 修正命名空间配置格式
改用逗号分隔的标准配置格式,确保新旧版本都能正确解析:
SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES: welcoming,default
2. 修复RBAC绑定冲突
修改ClusterRoleBinding的名称,避免覆盖:
# welcoming命名空间的绑定 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cross-namespace-service-discovery-binding-welcoming subjects: - kind: ServiceAccount name: default namespace: welcoming roleRef: kind: ClusterRole name: cross-namespace-service-discovery apiGroup: rbac.authorization.k8s.io --- # default命名空间的绑定 apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: cross-namespace-service-discovery-binding-default subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: ClusterRole name: cross-namespace-service-discovery apiGroup: rbac.authorization.k8s.io
3. 清理并优化负载均衡缓存
- 重启
retail-onboarding服务清除本地缓存; - 配置合理的缓存过期时间,避免旧数据干扰:
SPRING_CLOUD_LOADBALANCER_CACHE_TTL: 30s
4. 验证权限与服务状态
- 检查
welcoming命名空间的ServiceAccount权限:
kubectl config set-context --current --namespace=welcoming kubectl auth can-i list endpoints --namespace=default
返回yes则权限正常。
- 确认
audit-service的endpoints存在可用实例:
kubectl get endpoints audit-service -n default
总结
核心问题是配置格式不兼容和RBAC绑定名称冲突,修正这两点后配合缓存清理,即可实现跨命名空间服务的可靠发现与调用。
内容的提问来源于stack exchange,提问作者Tarun Bharti
相关产品推荐
相关产品推荐

