0 改造迁移 Dubbo 到 Istio

2020-07-15 17:13:28 浏览数 (1)

本文试验了一种方法,不修改 dubbo 的代码,只通过部署的方式将 Dubbo 应用部署到 Istio 中,并实现 Istio 集群中的实例与集群外的实例相互调用,和谐共存。

下面是这种方法的架构图:

架构图架构图

从图中可以看出,所有的 Dubbo 应用注册都注册到了 zk 中,并可以实现集群内外的互访。在集群内部,通过 接口和服务名的映射实现集群内的互访。

其中的关键点是,Istio 集群内 Dubbo 应用启动的时候,指定一个接口和服务名的映射关系文件:

代码语言:txt复制
java –jar -Ddubbo.resolve.file=services.properties app-fat.jar

并且,这个参数映射的优先级高于其他的配置方法。

下面是这一实验过程:

传统 dubbo 应用部署

先上代码为敬,也可以跳过代码看关键点:

代码语言:txt复制
# 创建命名空间,无 sidecar 注入
apiVersion: v1
kind: Namespace
metadata:
  name: dubbo
spec:
  finalizers:
    - kubernetes

---
# 在 dubbo 中部署 zk
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: zk
  namespace: dubbo
  labels:
    app: zk
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: zk
    spec:
      containers:
        - name: zk
          image: zookeeper:3.6.1
          ports:
            - containerPort: 2181
              name: client
---
# 通过 service 连接 zk
apiVersion: v1
kind: Service
metadata:
  name: zk
  namespace: dubbo
  labels:
    name: zk
spec:
  ports:
  - name: client
    port: 2181
    targetPort: 2181
  selector:
    app: zk
---
# 在 dubbo 中的 provider
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-provider
  namespace: dubbo
  labels:
    app: hello-dubbo-provider
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-dubbo-provider
      version: v1
  template:
    metadata:
      labels:
        app: hello-dubbo-provider
        version: v1
    spec:
      containers:
        - name: hello-dubbo-provider
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-provider:2.0.1
          command: ["java","-jar","hello-dubbo-provider-fat.jar"]
          env:
            - name: ns
              value: "dubbo"
          ports:
            - containerPort: 20880
              protocol: TCP

---
# 部署 hello-dubbo-consumer, 没有 sidecar
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-consumer
  namespace: dubbo
  labels:
    app: hello-dubbo-consumer
    version: v1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-dubbo-consumer
      version: v1
  template:
    metadata:
      labels:
        app: hello-dubbo-consumer
        version: v1
    spec:
      restartPolicy: Always
      containers:
        - name: hello-dubbo-consumer
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-consumer:1.0.4
          command: ["java","-jar","hello-dubbo-consumer-fat.jar"]
          ports:
            - containerPort: 20880
              protocol: TCP

上面的文件部署了一个普通的 K8S 命名空间,未指定 sidecar 注入。部署了 zk,provider 和 consumer,也可以使用虚拟部署(腾讯云TKE 打通了 pod 网络 和 node 网络)。部署后,直接可以调用。

在 Istio 中部署

继续上代码先,建议跳过代码看关键:

代码语言:txt复制
# 创建命名空间,有 sidecar 注入
apiVersion: v1
kind: Namespace
metadata:
  name: dubbo-mesh
  labels:
    istio-injection: enabled
spec:
  finalizers:
    - kubernetes


---
# hello-dubbo-provider 服务
apiVersion: v1
kind: Service
metadata:
  name: hello-dubbo-provider
  namespace: dubbo-mesh
  labels:
    name: hello-dubbo-provider
spec:
  ports:
  - name: dubbo-rpc
    protocol: TCP
    port: 20880
    targetPort: 20880
  selector:
    app: hello-dubbo-provider

---
# 部署 hello-dubbo-provider 应用,有sidecar
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-provider
  namespace: dubbo-mesh
  labels:
    app: hello-dubbo-provider
    version: v1-mesh
spec:
  replicas: 2
  selector:
    matchLabels:
      app: hello-dubbo-provider
      version: v1-mesh
  template:
    metadata:
      labels:
        app: hello-dubbo-provider
        version: v1-mesh
    spec:
      containers:
        - name: hello-dubbo-provider
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-provider:2.0.1
          command: ["java","-jar","hello-dubbo-provider-fat.jar"]
          env:
            - name: ns
              value: "dubbo-mesh"
          ports:
            - containerPort: 20880
              protocol: TCP

---
# 动态配置,将接口和服务的映射放入 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: services-list
  namespace: dubbo-mesh
data:
  services: |-
    tencent.demo.DemoService=dubbo://hello-dubbo-provider:20880
---
# 部署 hello-dubbo-consumer, 有 sidecar
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-consumer
  namespace: dubbo-mesh
  labels:
    app: hello-dubbo-consumer
    version: v1-mesh
spec:
  replicas: 3
  selector:
    matchLabels:
      app: hello-dubbo-consumer
      version: v1-mesh
  template:
    metadata:
      labels:
        app: hello-dubbo-consumer
        version: v1-mesh
    spec:
      restartPolicy: Always
      containers:
        - name: hello-dubbo-consumer
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-consumer:1.0.4
          command: ["java","-jar","-Ddubbo.resolve.file=services.properties", "hello-dubbo-consumer-fat.jar"]
          volumeMounts:
            - name: services-conf
              mountPath: /app/services.properties
              subPath: services.properties
      volumes:
          - name: services-conf
            configMap:
              name: services-list
              items:
                - key: services
                  path: services.properties

上面的部署代码:

  • 部署了一个自动注入 sidecar 的命名空间:dubbo-mesh。
  • 部署了 Consumer 和 Provider,使用了同样的镜像。
  • 将 services.properties 的信息写入了 ConfigMap 中,并通过 volumes 映射文件到程序工作目录。
  • 在启动脚本中加入参数 -Ddubbo.resolve.file=services.properties。

现在 Istio 集群中的 consumer 调用 tencent.demo.DemoService 接口的时候,就会使用集群内的服务名:hello-dubbo-provider 了。

调用结果

下面是调用结果:

在dubbo集群中的 Consumer 日志:

代码语言:txt复制
2020-07-15T08:34:07.033484467Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.0.93
2020-07-15T08:34:12.034650941Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.0.93
2020-07-15T08:34:17.04025799Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.1.14
2020-07-15T08:34:22.041549659Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.1.14
2020-07-15T08:34:27.04354781Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.67
2020-07-15T08:34:32.044685931Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.0.94
2020-07-15T08:34:37.045901507Z 你好:哈哈, V2 来自 dubbo 空间 @ 172.24.1.143

所有的 Provider 实例都被调用到了。

在 dubbo-mesh 中的 Consumer 的日志:

代码语言:txt复制
2020-07-15T08:42:59.733141083Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.5
2020-07-15T08:43:04.735234844Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.5
2020-07-15T08:43:09.737490538Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.5
2020-07-15T08:43:14.740803604Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.5
2020-07-15T08:43:19.743157701Z 你好:哈哈, V2 来自 dubbo-mesh 空间 @ 172.24.2.5

集群内的应用通过服务名调用,只能调用到集群内的 Provider。

但在去掉 services.properties 映射后,Istio 集群内 和 集群外 的 Consumer 展现了同样的日志信息。

More

在上面的 Isito 集群中,Consumer 访问外部的应用的时候,存在出的流量,并且经过了 envoy 劫持,在 Dubbo 场景下,需要将 global.outboundTrafficPolicy.mode 设置为 ALLOW_ANY,或者创建 ServiceEntry 策略。

但由于流出集群的 outbound 流量被 Envoy 劫持感觉“毫无意义”,可以考虑使用策略将出流量绕过 envoy 以提高效率,如下:

代码语言:txt复制
#...
  template:
    metadata:
      annotations:
        traffic.sidecar.istio.io/excludeOutboundIPRanges: "10.0.50.0/24,172.24.2.0/24,172.24.1.0/24,172.24.0.0/24"
 #...

程序代码可参考:

https://github.com/cloudbeer/dubbo-mesh-demo

其中的两个部署文件分别位于 deploy/d-dubbo.yaml, deploy/d-mesh.yaml。

总结

使用上述方法,我们可以在不修改代码的情况下,完美地将 Dubbo 应用部署到 Istio 集群,并且可以不影响业务,慢慢迁移,迁移一个应用,就在 services.properties 中加入 接口和服务映射。

但实际环境的 Dubbo 的迁移仍然是一件比较复杂的过程,需要经过大量测试验证才能确保最终成果。

同学们,加油!


参考:

dubbo 直连提供者: http://dubbo.apache.org/zh-cn/docs/user/demos/explicit-target.html

0 人点赞