• 关于dapr跨k8s集群服务调用的可行性方案


    背景

    现在有多个k8s集群,在每个集群中部署一个dapr服务。不同k8s集群中的服务,无法跨集群实现服务调用。

    假设集群中pod的ip是互通的。(前提条件,必须!!!)

    命名解析

    介绍

    Name resolvers provide a common way to interact with different name resolvers, which are used to return the address or IP of other services your applications may connect to.

    命名解析器提供了一种与不同命名解析器互动的通用方法,这些解析器用于返回你的应用程序可能要连接到的其他服务的地址或IP。

    接口定义

    兼容的名称解析器需要实现 nameresolution.go 文件中的 Resolver 接口。

    1. // Resolver是命名解析器的接口。
    2. type Resolver interface {
    3. // Init initializes name resolver.
    4. Init(metadata Metadata) error
    5. // ResolveID resolves name to address.
    6. ResolveID(req ResolveRequest) (string, error)
    7. }
    8. // ResolveRequest 表示服务发现解析器请求。
    9. type ResolveRequest struct {
    10. ID string
    11. Namespace string
    12. Port int
    13. Data map[string]string
    14. }

    使用方式

    命名解析在service invoke 流程中的使用方式

    解析地址

    name resolver 被调用的地方只有一个:

    1. func (d *directMessaging) getRemoteApp(appID string) (remoteApp, error) {
    2. // 从appID中获取id和namespace
    3. // appID 可能是类似 "appID.namespace" 的格式
    4. id, namespace, err := d.requestAppIDAndNamespace(appID)
    5. if err != nil {
    6. return remoteApp{}, err
    7. }
    8. // 执行 resolver 的解析
    9. request := nr.ResolveRequest{ID: id, Namespace: namespace, Port: d.grpcPort}
    10. address, err := d.resolver.ResolveID(request)
    11. if err != nil {
    12. return remoteApp{}, err
    13. }
    14. // 返回 remoteApp 的地址
    15. return remoteApp{
    16. namespace: namespace,
    17. id: id,
    18. address: address,
    19. }, nil
    20. }

    解析出来的地址在 directMessaging 的 Invoke() 中使用,用来执行远程调用

    1. // Invoke takes a message requests and invokes an app, either local or remote.
    2. func (d *directMessaging) Invoke(ctx context.Context, targetAppID string, req *invokev1.InvokeMethodRequest) (*invokev1.InvokeMethodResponse, error) {
    3. app, err := d.getRemoteApp(targetAppID)
    4. if err != nil {
    5. return nil, err
    6. }
    7. // 如果目标应用的 id 和 namespace 都和 directMessaging 的一致,则执行 invokeLocal()
    8. if app.id == d.appID && app.namespace == d.namespace {
    9. return d.invokeLocal(ctx, req)
    10. }
    11. // 这是在带有重试机制的情况下调用 invokeRemote
    12. return d.invokeWithRetry(ctx, retry.DefaultLinearRetryCount, retry.DefaultLinearBackoffInterval, app, d.invokeRemote, req)
    13. }

    daprd启动时,注入了3中命名解释器。这里是针对k8s环境下的dapr

    kubernetes 命名解析实现

    kubernetes 的实现超级简单,直接按照 Kubernetes services 的格式要求,拼出一个 Kubernetes services 的 name 即可:

    1. // ResolveID resolves name to address in Kubernetes.
    2. func (k *resolver) ResolveID(req nameresolution.ResolveRequest) (string, error) {
    3. // Dapr requires this formatting for Kubernetes services
    4. return fmt.Sprintf("%s-dapr.%s.svc.%s:%d", req.ID, req.Namespace, k.clusterDomain, req.Port), nil
    5. }
    其中, req.ID 和 req.Namespace 对应到 Kubernetes 的 service name 和 namespace,注意这里的 Kubernetes service 是在 ID 后面加了 “-dapr” 后缀。Port 来自请求参数,简单拼接而已。

    注意这里的service格式,其实是普通的k8s service经过dapr的injector注入后生成新的service,本质上就是k8s的一个service。

    clusterDomain 的设置

    clusterDomain 稍微复杂一点,默认值是 “cluster.local”,在构建 Resolver 时设置:

    1. const (
    2. DefaultClusterDomain = "cluster.local"
    3. )
    4. type resolver struct {
    5. logger logger.Logger
    6. clusterDomain string
    7. }
    8. // NewResolver creates Kubernetes name resolver.
    9. func NewResolver(logger logger.Logger) nameresolution.Resolver {
    10. return &resolver{
    11. logger: logger,
    12. clusterDomain: DefaultClusterDomain,
    13. }
    14. }

    k8s service如何解析到服务的ip地址

    我们知道k8s service,可以通过对应的endpoint,可以获取到后端服务的对应pod的ip地址。这个时候,如果我们在集群A中手动创建集群B的Service,以及对应的endpoint,那么,就可以在集群A中调用集群B的服务。从而实现dapr跨集群服务。或者在etcd中存储其他服务的ip地址,通过etcd可以获取其他集群中服务的ip地址。

    最后

    本文的思路只针对k8s环境,且要求多个集群ip互通,只支持dapr的服务调用,其他功能不支持。条件比较严格,思路未经实现仅供参考。

    github上也提出了类似的需求的issue,https://github.com/dapr/dapr/issues/5389,有兴趣的同学,可以一起讨论下。

  • 相关阅读:
    Uni-app 与 Taro 对比分析(移动端快速搭建能力平台调研)
    C++对象模型(14)-- 构造函数语义学:拷贝构造函数和赋值运算赋
    使用Windows平台的Hyper-V虚拟机安装CentOS7的详细过程
    UVM field automation机制
    二叉排序树的删除操作的实现(思路分析)
    第一百六十一回 Sliver综合示例
    排序算法的总结
    dp吗,对啊
    论文阅读 - Natural Language is All a Graph Needs
    codegeex2-6b-int4 部署
  • 原文地址:https://blog.csdn.net/cbmljs/article/details/127560282