本篇介绍如何将一个 Dubbo 项目改造成一个 SpringBoot + K8S + Istio 项目的全过程,实现了在不改变 Dubbo 项目整体代码结构的基础上,向 Service Mesh 云原生项目的蜕变。
现有 Dubbo 项目 xyz-dubbo,包括以下三个模块:
改造前的 Dubbo 项目根 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>xyz-dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>xyz-dubbo</name>
<modules>
<module>dubbo-consumer</module>
<module>dubbo-provider</module>
<module>dubbo-facade</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>dubbo-facade</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.6</version>
</dependency>
<dependency>
<groupId>com.ecwid.consul</groupId>
<artifactId>consul-api</artifactId>
<version>1.4.5</version>
</dependency>
<dependency>
<groupId>com.orbitz.consul</groupId>
<artifactId>consul-client</artifactId>
<version>1.4.2</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
改造后的 SpringBoot 项目根 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>xyz-dubbo</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>xyz-dubbo</name>
<modules>
<module>dubbo-consumer</module>
<module>dubbo-provider</module>
<module>dubbo-facade</module>
</modules>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>dubbo-facade</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
改造前的 Dubbo facade 接口示例:
public interface HelloService {
String sayHello(String name);
}
改造后的 Feign Restful 接口示例:
@FeignClient(name = "dubbo-provider", url = "http://dubbo-provider:8001")
public interface HelloService {
@GetMapping(value = "/apis/hello/{name}")
String sayHello(@PathVariable String name);
}
改造前的 dubbo-provider 模块 pom.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>xyz-dubbo</artifactId>
<groupId>io.xyzdemo.dubbo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>dubbo-provider</artifactId>
<packaging>war</packaging>
<name>dubbo-provider</name>
<dependencies>
<dependency>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>dubbo-facade</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>com.ecwid.consul</groupId>
<artifactId>consul-api</artifactId>
</dependency>
<dependency>
<groupId>com.orbitz.consul</groupId>
<artifactId>consul-client</artifactId>
</dependency>
</dependencies>
</project>
改造后的 dubbo-provider 模块 pom.xml 配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>xyz-dubbo</artifactId>
<groupId>io.xyzdemo.dubbo</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>dubbo-provider</artifactId>
<name>dubbo-provider</name>
<dependencies>
<dependency>
<groupId>io.xyzdemo.dubbo</groupId>
<artifactId>dubbo-facade</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>io.xyzdemo.dubbo.provider.ProviderApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
改造后的 HelloServiceImpl.java 代码示例(改造前只是缺少 @RestController 注解,其他代码完全一致):
@RestController
public class HelloServiceImpl implements HelloService {
public String sayHello(String name) {
return String.format("hello %s! podIP is %s!", name, CommonUtils.getLocalIP());
}
}
由于dubbo-consumer 项目改造与dubbo-provider 改造极其相似,这里不再贴出代码示例。
将下面三个配置文件通过 kubectl 在 K8S+Istio 的集群中执行,即可完成改造后的项目在 K8S+Istio 集群中的部署。
dubbo-provider-service.yml 配置文件示例:
apiVersion: v1
kind: Service
metadata:
name: dubbo-provider
spec:
type: ClusterIP
ports:
- name: http
port: 8001
selector:
k8s-app: dubbo-provider
qcloud-app: dubbo-provider
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: dubbo-provider-deployment
labels:
k8s-app: dubbo-provider
qcloud-app: dubbo-provider
spec:
replicas: 2 # 副本数量
selector:
matchLabels:
k8s-app: dubbo-provider
qcloud-app: dubbo-provider
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: dubbo-provider
qcloud-app: dubbo-provider
spec:
containers:
- name: dubbo-provider
image: ccr.ccs.tencentyun.com/axlyzhang-images/dubbo-provider:v1.1 # 镜像地址
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: LANG
value: C.UTF-8
- name: JAVA_HOME
value: /usr/lib/jvm/java-8-openjdk-amd64
- name: JAVA_VERSION
value: 8u111
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
securityContext:
privileged: false
procMount: Default
imagePullSecrets:
- name: qcloudregistrykey
- name: tencenthubkey
dubbo-consumer-service.yml 配置文件示例:
apiVersion: v1
kind: Service
metadata:
name: dubbo-consumer
spec:
type: ClusterIP
ports:
- name: http
port: 8002
selector:
k8s-app: dubbo-consumer
qcloud-app: dubbo-consumer
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: dubbo-consumer-deployment
labels:
k8s-app: dubbo-consumer
qcloud-app: dubbo-consumer
spec:
replicas: 2 # 副本数量
selector:
matchLabels:
k8s-app: dubbo-consumer
qcloud-app: dubbo-consumer
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: dubbo-consumer
qcloud-app: dubbo-consumer
spec:
containers:
- name: dubbo-consumer
image: ccr.ccs.tencentyun.com/axlyzhang-images/dubbo-consumer:v1.0 # 镜像地址
env:
- name: PATH
value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
- name: LANG
value: C.UTF-8
- name: JAVA_HOME
value: /usr/lib/jvm/java-8-openjdk-amd64
- name: JAVA_VERSION
value: 8u111
resources:
limits:
cpu: 500m
memory: 1Gi
requests:
cpu: 250m
memory: 256Mi
securityContext:
privileged: false
procMount: Default
imagePullSecrets:
- name: qcloudregistrykey
- name: tencenthubkey
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: dubbo-consumer-gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: consumer-vs
spec:
hosts:
- "*"
gateways:
- dubbo-consumer-gateway
http:
- match:
- uri:
prefix: /hello/error
route:
- destination:
host: dubbo-consumer
port:
number: 8003 -- 错误的服务端口
- route:
- destination:
host: dubbo-consumer
port:
number: 8002 -- 正确的服务端口
经过上面几步操作,我们成功的将一个 Dubbo 项目改造成了一个 Service Mesh 项目,并在 K8S + Istio 集群中部署成功、测试通过。
当然,真实业务系统中的架构复杂度是远高于这个 Demo 的,实际改造的难度要比改造这个 Demo 大得多。这篇文章只是抱砖引玉,希望可以跟大家继续探讨 Dubbo 向 Service Mesh 改造的更好方式。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。