spring cloud kubernetes 使用 feign 的正确方法是什么?
What is the correct way to use feign with spring cloud kubernetes?
我正在使用 Spring Cloud Kubernetes 并且我试图让 feign 能够根据 kubernetes 中存在的服务名称发送请求,但是当我尝试发出请求时我不能发生以下错误:
"timestamp": "2019-12-06T15:37:50.285+0000",
"status": 500,
"error": "Internal Server Error",
"message": "com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo",
"trace": "java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo\n\tat org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute....
我尝试调用集群中的其他服务,但所有服务的问题都是一样的,我通过进入 poc-deposit pod 并执行 poc-balance curl 进行了测试,它工作正常,所以问题不在于 poc-deposit 服务。平衡或显然与 kubernetes 的服务发现。
该项目有一个 public 配置文件:
https://gitlab.com/viniciusxyz/spring-kubernetes-feign
对于那些想要更直接信息的人:
我的主要class如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceDiscoveryApplication.class, args);
}
}
我的feign界面如下:
@FeignClient("poc-saldo")
public interface ProxyGenerico {
@RequestMapping(method = RequestMethod.GET)
String getHttpResponse();
}
我可以在应用程序中列出 kubernetes 中可用的服务,如下所示:
@RestController
public class RestTest {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private ProxyGenerico proxyGenerico;
@GetMapping("/services")
public ResponseEntity<?> services() {
return new ResponseEntity<Object>(discoveryClient.getServices(), HttpStatus.OK);
}
@GetMapping("/pocsaldo")
public ResponseEntity<?> gitlab() {
return new ResponseEntity<Object>(proxyGenerico.getHttpResponse(), HttpStatus.OK);
}
}
在这个列表中我有几个服务,其中我想要访问的服务称为 poc-balance,return json 如下所示:
[
"poc-deposito",
"poc-saldo",
"sonarqube",
"sql-server-sonar",
"zookeeper",
"gitlab"
]
要补充列表,请遵循我的依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
discoveryClient.getInstances ("poc-saldo") 命令 returns:
[
{
"instanceId": "32a4db0d-0549-11ea-8850-e0d55ef66cf8",
"serviceId": "poc-saldo",
"secure": false,
"metadata": {
"helm.sh/chart": "spring-boot-app-0.1.23",
"port.http": "8080",
"app.kubernetes.io/managed-by": "Tiller",
"app.kubernetes.io/name": "poc-saldo",
"app.kubernetes.io/instance": "banco-digital-poc-saldo",
"app.kubernetes.io/version": "1.0"
},
"port": 8080,
"host": "10.42.0.60",
"scheme": "http://",
"uri": "http://10.42.0.60:8080"
}
]
你能想到问题出在哪里吗?
如果您使用 Ribbon 进行负载平衡,我会在您的错误中看到它 org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient
你需要说功能区关于你所有微服务的真实地址和
用于此操作发现客户端。
在你的主要 class 之上,添加一些注释
@EnableDiscoveryClient
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class MyApp
添加实现你的动态服务器列表
public class MyServerList extends AbstractServerList<Server> {
private final DiscoveryClient discoveryClient;
private IClientConfig clientConfig;
public MyServerList(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
@Override
public List<Server> getInitialListOfServers() {
return getUpdatedListOfServers();
}
@Override
public List<Server> getUpdatedListOfServers() {
Server[] servers = discoveryClient.getInstances(clientConfig.getClientName()).stream()
.map(i -> new Server(i.getHost(), i.getPort()))
.toArray(Server[]::new);
return Arrays.asList(servers);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}
}
添加RibbonConfiguration.class
public class RibbonConfiguration {
@Autowired
private DiscoveryClient discoveryClient;
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config) {
MyServerList myserverLis = new MyServerList(discoveryClient);
myserverLis.initWithNiwsConfig(config);
return myserverLis;
}
}
你可以在你的应用程序中配置 属性 刷新时间我的意思是调用 getUpdatedListOfServers 的时间段
长话短说,截至 2021 年 7 月,Spring Cloud Feign 与 Spring Cloud Kubernetes 完美配合。我已经移动了 Spring Cloud Feign 项目从使用 Spring Cloud Netflix 到 Spring Cloud Kubernetes 并且不需要更改 Feign 接口。我刚刚从我的 build.gradle
文件中删除了之前的 Service Registry (Eureka) 依赖项并添加了:
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
对 Spring Cloud LoadBalancer 的支持已添加到 Spring Cloud Feign Spring Cloud Kubernetes 和 Ribbon 已从 Spring Cloud 2020.0 开始删除。 (又名 Ilford),因此没有必要再排除它了。
除此之外,整个代码库中唯一需要的更改是使用 @EnableDiscoveryClient
注释 Spring 引导应用程序 class 以启用 K8s 原生服务发现:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class BookApplication {
Spring Cloud Feign 使用 Spring Cloud LoadBalancer,当 运行 在 Kubernetes 上利用Discovery Client for Kubernetes 检查服务实例。因此,它只会从已启动且 运行 的实例中进行选择。 唯一的要求是将Kubernetes服务名称与spring.application.name
属性对齐。就这样:
application.properties(yaml):
spring.application.name=library-book-service
结合以下Kubernetes配置
kubectl 获取 svc:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
library-book-service ClusterIP 10.100.200.235 <none> 8080/TCP 5d21h
我正在使用 Spring Cloud Kubernetes 并且我试图让 feign 能够根据 kubernetes 中存在的服务名称发送请求,但是当我尝试发出请求时我不能发生以下错误:
"timestamp": "2019-12-06T15:37:50.285+0000",
"status": 500,
"error": "Internal Server Error",
"message": "com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo",
"trace": "java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo\n\tat org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute....
我尝试调用集群中的其他服务,但所有服务的问题都是一样的,我通过进入 poc-deposit pod 并执行 poc-balance curl 进行了测试,它工作正常,所以问题不在于 poc-deposit 服务。平衡或显然与 kubernetes 的服务发现。
该项目有一个 public 配置文件:
https://gitlab.com/viniciusxyz/spring-kubernetes-feign
对于那些想要更直接信息的人:
我的主要class如下:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceDiscoveryApplication.class, args);
}
}
我的feign界面如下:
@FeignClient("poc-saldo")
public interface ProxyGenerico {
@RequestMapping(method = RequestMethod.GET)
String getHttpResponse();
}
我可以在应用程序中列出 kubernetes 中可用的服务,如下所示:
@RestController
public class RestTest {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private ProxyGenerico proxyGenerico;
@GetMapping("/services")
public ResponseEntity<?> services() {
return new ResponseEntity<Object>(discoveryClient.getServices(), HttpStatus.OK);
}
@GetMapping("/pocsaldo")
public ResponseEntity<?> gitlab() {
return new ResponseEntity<Object>(proxyGenerico.getHttpResponse(), HttpStatus.OK);
}
}
在这个列表中我有几个服务,其中我想要访问的服务称为 poc-balance,return json 如下所示:
[
"poc-deposito",
"poc-saldo",
"sonarqube",
"sql-server-sonar",
"zookeeper",
"gitlab"
]
要补充列表,请遵循我的依赖项:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
discoveryClient.getInstances ("poc-saldo") 命令 returns:
[
{
"instanceId": "32a4db0d-0549-11ea-8850-e0d55ef66cf8",
"serviceId": "poc-saldo",
"secure": false,
"metadata": {
"helm.sh/chart": "spring-boot-app-0.1.23",
"port.http": "8080",
"app.kubernetes.io/managed-by": "Tiller",
"app.kubernetes.io/name": "poc-saldo",
"app.kubernetes.io/instance": "banco-digital-poc-saldo",
"app.kubernetes.io/version": "1.0"
},
"port": 8080,
"host": "10.42.0.60",
"scheme": "http://",
"uri": "http://10.42.0.60:8080"
}
]
你能想到问题出在哪里吗?
如果您使用 Ribbon 进行负载平衡,我会在您的错误中看到它 org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient
你需要说功能区关于你所有微服务的真实地址和 用于此操作发现客户端。
在你的主要 class 之上,添加一些注释
@EnableDiscoveryClient @AutoConfigureAfter(RibbonAutoConfiguration.class) @RibbonClients(defaultConfiguration = RibbonConfiguration.class) public class MyApp
添加实现你的动态服务器列表
public class MyServerList extends AbstractServerList<Server> { private final DiscoveryClient discoveryClient; private IClientConfig clientConfig; public MyServerList(DiscoveryClient discoveryClient) { this.discoveryClient = discoveryClient; } @Override public List<Server> getInitialListOfServers() { return getUpdatedListOfServers(); } @Override public List<Server> getUpdatedListOfServers() { Server[] servers = discoveryClient.getInstances(clientConfig.getClientName()).stream() .map(i -> new Server(i.getHost(), i.getPort())) .toArray(Server[]::new); return Arrays.asList(servers); } @Override public void initWithNiwsConfig(IClientConfig clientConfig) { this.clientConfig = clientConfig; } }
添加RibbonConfiguration.class
public class RibbonConfiguration { @Autowired private DiscoveryClient discoveryClient; @Bean @ConditionalOnMissingBean public ServerList<?> ribbonServerList(IClientConfig config) { MyServerList myserverLis = new MyServerList(discoveryClient); myserverLis.initWithNiwsConfig(config); return myserverLis; } }
你可以在你的应用程序中配置 属性 刷新时间我的意思是调用 getUpdatedListOfServers 的时间段
长话短说,截至 2021 年 7 月,Spring Cloud Feign 与 Spring Cloud Kubernetes 完美配合。我已经移动了 Spring Cloud Feign 项目从使用 Spring Cloud Netflix 到 Spring Cloud Kubernetes 并且不需要更改 Feign 接口。我刚刚从我的 build.gradle
文件中删除了之前的 Service Registry (Eureka) 依赖项并添加了:
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
对 Spring Cloud LoadBalancer 的支持已添加到 Spring Cloud Feign Spring Cloud Kubernetes 和 Ribbon 已从 Spring Cloud 2020.0 开始删除。 (又名 Ilford),因此没有必要再排除它了。
除此之外,整个代码库中唯一需要的更改是使用 @EnableDiscoveryClient
注释 Spring 引导应用程序 class 以启用 K8s 原生服务发现:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class BookApplication {
Spring Cloud Feign 使用 Spring Cloud LoadBalancer,当 运行 在 Kubernetes 上利用Discovery Client for Kubernetes 检查服务实例。因此,它只会从已启动且 运行 的实例中进行选择。 唯一的要求是将Kubernetes服务名称与spring.application.name
属性对齐。就这样:
application.properties(yaml):
spring.application.name=library-book-service
结合以下Kubernetes配置
kubectl 获取 svc:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
library-book-service ClusterIP 10.100.200.235 <none> 8080/TCP 5d21h