因为涉及到开发环境与部署环境,首先我们确认一种高效率的开发联调方式是我们自己负责开发的工程可以在本地IDE进行修改启动,而我们依赖的其他服务可以使用部署环境里面已经完成部署的稳定服务,如下图:
在这种情况下主要需要解决两个问题,1. 本地网络环境与K8S环境的网络链路打通,2. k8s环境的微服务本地发现与调用打通。
服务网络链路打通方法
首先介绍一个工具:kubefwd。【链接】
kubefwd 是一个用于端口转发Kubernetes中指定namespace下的全部或者部分pod的命令行工具。 kubefwd 使用本地的环回IP地址转发需要访问的service,并且使用与service相同的端口。 kubefwd会临时将service的域条目添加到 /etc/hosts 文件中。
首先确认对应的微服务已经在k8s中配置了service,比如配置微服务1的service为app1,端口为8080
首先需要安装kubectl,kubectl安装参考【链接】
Mac安装
brew install txn2/tap/kubefwd
Windows安装
scoop install kubefwd
使用:以mac为例
# -c, --kubeconfig -n, --namespace
sudo kubefwd svc -c kubeConfig.yaml -n default
# 检查标准输出中的Forwarding条目中存在你定义的service,比如app1:8080
# 然后本地进行curl,检查服务是否正确返回
curl app1:8080
服务发现打通方法
Java微服务体系中,目前比较普遍的方式是使用SpringCloud微服务体系,使用注册中心的方法将微服务注册上去,消费者通过服务名到注册中心获取提供者的ip端口。
因为微服务注册在K8s中,这种情况下注册到注册中心的ip地址一般为该微服务的pod地址,而pod的网络与本地的开发网络是隔离的,所以这里需要将微服务之间调用的地址替换为service名字,使用上文介绍的kubefwd的方式打通的服务网络进行微服务调用。
以下以feignClient的调用为例子,此处为消费者部分代码
SpringBootApplication 的主入口,如application.java
注释掉@EnableFeignClients相关的注解
@EnableDiscoveryClient
//@EnableFeignClients(basePackages = {
// "com.aliyun.gts.work.flow.api.api"
//})
@MapperScan("com.aliyun.gts.delivery.capabilities.infrastructure.domain.repository")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
显示声明对api的引用,此处以FlowProcessApi为例子(一个feign接口)
FlowApi.java
import com.aliyun.gts.delivery.capabilities.boot.FeignConfiguration;
import com.aliyun.gts.work.flow.api.api.FlowProcessApi;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import lombok.Builder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FlowApi {
@Value("${flow-service.endpoint:}")
private String endpoint;
@Bean
FlowProcessApi flowProcessApi() {
return create(FlowProcessApi.class, endpoint);
}
@Autowired
Contract contract;
@Autowired
Decoder decoder;
@Autowired
Encoder encoder;
protected <T> T create(Class<T> t, String endpoint) {
return create(t, endpoint,
LogConfig.builder()
.logger(new Logger.JavaLogger())
.level(Logger.Level.NONE).build()
);
}
protected <T> T create(Class<T> t, String endpoint, LogConfig logConfig) {
String url = t.getAnnotation(FeignClient.class).value();
if (StringUtils.isNotBlank(endpoint)) {
url = buildUrl(endpoint);
}
T client = Feign.builder()
.logger(logConfig.logger).logLevel(logConfig.level)
.contract(contract)
.encoder(encoder)
.decoder(decoder)
.requestInterceptor(new FeignConfiguration())
.target(t, url);
return client;
}
public static String buildUrl(String url) {
if (StringUtils.isBlank(url)) {
return "";
}
if (url.startsWith("http://") || url.startsWith("https://")) {
return url;
}
return "http://" + url;
}
@Builder
static class LogConfig {
private Logger logger;
private Logger.Level level;
}
}
在application.yaml(相应环境的配置文件中添加微服务的endpoint)
# 在k8s中的服务名,当本地kubefwd完成之后可以本地进行curl测试是否正常
flow-service.endpoint: flow.service:8080