Dubbo 与 Istio 共生

2020-06-13 13:48:24 浏览数 (1)

当下,越来越多的应用迁入了容器集群。“享受着”云原生带来的便利。mesh 也越来越被广大程序员所接受。

目前,将原有应用迁入容器集群应该不是难事儿,通过 ip 直连访问,几乎毫无影响。但传统微服务应用如何和 mesh 应用共生呢?

本文探讨了一中方法,让 dubbo 和 Istio 可以共生。设想如下:

设想的架构图设想的架构图

前提条件

  • 传统的 dubbo 应用:包含一个 provider 和一个 consumer。
  • 一个 k8s istio 集群。

部署过程

部署命名空间

创建一个命名空间 dubbo,这个命名空间没有 sidecar 注入,用于放置 dubbo 传统应用。

代码语言:txt复制
apiVersion: v1
kind: Namespace
metadata:
  name: dubbo
spec:
  finalizers:
    - kubernetes

部署 registry

使用 consul 作为注册发现服务器。本示例使用了单节点,开发模式/生产环境请自行查看官网。

需要注意的是:consul agent 默认监听的是 127.0.0.1,实际使用 Service 访问的时候,使用的是 pod 的 IP,所以需要将监听 IP 修改为 0.0.0.0。

代码语言:txt复制
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: consul
  namespace: dubbo
  labels:
    app: consul
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: consul
    spec:
      containers:
        - name: consul
          image: consul:1.7.3
          args:
            - "agent"
            - "-dev"
            - "-client=0.0.0.0"
          ports:
            - containerPort: 8500
              name: ui-port
            - containerPort: 8400
              name: alt-port
            - containerPort: 53
              name: udp-port
            - containerPort: 8443
              name: https-port
            - containerPort: 8080
              name: http-port
            - containerPort: 8301
              name: serflan
            - containerPort: 8302
              name: serfwan
            - containerPort: 8600
              name: consuldns
            - containerPort: 8300
              name: server

---
apiVersion: v1
kind: Service
metadata:
  name: consul
  namespace: dubbo
  labels:
    name: consul
spec:
  ports:
  - name: http
    port: 8500
    targetPort: 8500
  - name: https
    port: 8443
    targetPort: 8443
  - name: rpc
    port: 8400
    targetPort: 8400
  - name: serflan-tcp
    protocol: "TCP"
    port: 8301
    targetPort: 8301
  - name: serflan-udp
    protocol: "UDP"
    port: 8301
    targetPort: 8301
  - name: serfwan-tcp
    protocol: "TCP"
    port: 8302
    targetPort: 8302
  - name: serfwan-udp
    protocol: "UDP"
    port: 8302
    targetPort: 8302
  - name: server
    port: 8300
    targetPort: 8300
  - name: consuldns
    port: 8600
    targetPort: 8600
  selector:
    app: consul

consul 使用了 Service 暴露服务,在 dubbo 应用中,注册中心的地址应该是:

代码语言:txt复制
<dubbo:registry address="consul://consul.dubbo:8500"/>

部署 provider

这一步比较简单,没有sidecar。

代码语言:txt复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-provider
  namespace: dubbo
  labels:
    app: hello-dubbo-provider
    version: v1
spec:
  replicas: 1
  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:1.0.1
          command: ["java","-jar","hello-dubbo-provider-fat.jar"]
          ports:
            - containerPort: 20880
              protocol: TCP

查看 log,发现直接连通。

部署 consumer

首先将 consumer 部署在 dubbo 命名空间测试。

代码语言:txt复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-consumer
  namespace: dubbo
  labels:
    app: hello-dubbo-consumer
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-dubbo-consumer
      version: v1
  template:
    metadata:
      labels:
        app: hello-dubbo-consumer
        version: v1
    spec:
      containers:
        - name: hello-dubbo-consumer
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-consumer:1.0.0
          command: ["java","-jar","hello-dubbo-consumer-fat.jar"]

测试:直接成功。

为了让dubbo可以访问 isito 的应用,我们需要给 consumer 增加一个 sidecar。

命名空间 xyz 已经开启了 sidecar 自动注入,直接换一个命名空间部署:

代码语言:txt复制
...
namespace: xyz
...

启动后,有错误,日志如下:

代码语言:txt复制
Caused by: org.apache.dubbo.remoting.RemotingException: message can not send, because channel is closed . url:dubbo://10.4.0.211:20880/tencent.demo.DemoService?anyhost=true&application=demo-consumer&check=false&codec=dubbo&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&heartbeat=60000&init=false&interface=tencent.demo.DemoService&methods=sayHello&pid=1&register.ip=10.4.0.213&release=2.7.6&remote.application=hello-dubbo-provider&revision=1.0-SNAPSHOT&side=consumer&sticky=false&timestamp=1591279149752

目标地址通道被关闭,看来是被 envoy 劫持了。

Dubbo provider 在特定的端口提供服务,寻找到不被劫持的方法:excludeOutboundPorts,excludeInboundPorts。妥了。完整的yaml文件如下:

代码语言:txt复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-dubbo-consumer
  namespace: xyz
  labels:
    app: hello-dubbo-consumer
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-dubbo-consumer
      version: v1
  template:
    metadata:
      annotations:
        traffic.sidecar.istio.io/excludeOutboundPorts: "20880"
        traffic.sidecar.istio.io/excludeInboundPorts: "20880"
      labels:
        app: hello-dubbo-consumer
        version: v1
    spec:
      containers:
        - name: hello-dubbo-consumer
          image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-consumer:1.0.0
          command: ["java","-jar","hello-dubbo-consumer-fat.jar"]

好了,现在全通了。

最终的架构图最终的架构图

总结

在 Istio 中,可以将 Dubbo 应用随着 sidecar 一起部署,当需要访问 dubbo 服务的时候,需要将 Envoy 劫持服务端口排除掉;当访问 mesh 的 http 服务时,只需要启动 http client 访问服务名 端口就可以了。

如此,你的 Dubbo 应用便与 istio 应用可以互通访问了。美中不足的是:服务治理并未统一。

好在咱们还有时间。骚年,抓紧把 dubbo 服务改造到 istio 中吧。

改造方法:如何将一个 Dubbo 项目改造成一个 Service Mesh 项目?

附:dubbo 应用的 fatjar 打包

在 pom.xml 中增加如下配置:

代码语言:txt复制
    <build>
        <plugins>
            <plugin>
                <groupId>com.jolira</groupId>
                <artifactId>onejar-maven-plugin</artifactId>
                <version>1.4.4</version>
                <configuration>
                    <mainClass>tencent.demo.provider.Provider</mainClass>
                    <filename>${project.name}-fat.jar</filename>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>one-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

0 人点赞