使用 feign 和 spring cloud kubernetes 的正确方法是啥?

Posted

技术标签:

【中文标题】使用 feign 和 spring cloud kubernetes 的正确方法是啥?【英文标题】:What is the correct way to use feign with spring cloud kubernetes?使用 feign 和 spring cloud kubernetes 的正确方法是什么? 【发布时间】:2020-03-31 16:29:29 【问题描述】:

我正在使用 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 的服务发现。

该项目的公开资料位于:

https://gitlab.com/viniciusxyz/spring-kubernetes-feign

对于那些想要更直接信息的人:

我的主要课程如下:

@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,返回的 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") 命令返回:

[
    
        "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"
    
]

你能想到问题可能出在哪里吗?

【问题讨论】:

您是否使用eureka 作为您的服务发现?如果不是,它怎么知道这些服务在哪里。在这种情况下,您应该将它们的 url 配置为 &lt;app&gt;.ribbon.listOfServers=http://&lt;app-host&gt;/... 我使用的是使用 Kubernetes 服务发现的 Spring Cloud Kubernetes,eureka 只是支持的服务发现提供者之一。 在你的情况下,你能看到 kubernetes 中列出的那些服务吗? 总而言之,我使用 feign 作为 kubernetes 服务的 url 的参数,例如:@FeignClient("http://kubernetes-service"),我只是举这个例子如果您有同样的问题并需要快速解决方案,晚上发布完整的答案。 @ViniciusVieira 好的,所以无法像在 Eureka 中那样使用 FeignClient。我发现,您可以使用 @FeignClient(url="service-name") 而不是 @FeignClient("service-name") 并且它可以在不传递完整地址 http://service-name:port 的情况下工作 【参考方案1】:

长话短说,截至 2021 年 7 月,Spring Cloud Feign 与 Spring Cloud Kubernetes 完美配合。我已将 Spring Cloud Feign 项目从使用 Spring Cloud NetflixSpring Cloud Kubernetes,无需更改 Feign 接口。我刚刚从我的 build.gradle 文件中删除了以前的 Service Registry (Eureka) 依赖项并添加了:

implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'

Spring Cloud Feign 现在使用的 Spring Cloud LoadBalancer 支持已添加到 Spring Cloud KubernetesRibbon 自 Spring Cloud 2020.0 起已删除。 (又名 Ilford),因此无需再排除它。

除此之外,整个代码库中唯一需要的更改是使用 @EnableDiscoveryClient 注释 Spring Boot 应用程序类以启用 K8s-native 服务发现:

@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

【讨论】:

【参考方案2】:

如果您使用 Ribbon 进行负载平衡,我会在您的错误 org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient 中看到它

您需要使用 Ribbon 来了解您所有微服务的真实地址和 用于此操作发现客户端。

    在你的主类之上,添加一些注释

    @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 的时间段

【讨论】:

以上是关于使用 feign 和 spring cloud kubernetes 的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 spring-cloud-netflix 和 feign 编写集成测试

08 在Spring Cloud中使用Feign

使用 feign 和 spring cloud kubernetes 的正确方法是啥?

Spring Cloud之Feign客户端

spring-cloud-feign负载均衡组件

spring-cloud Feign