本文试验了一种方法,不修改 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