如何设置 Spring Cloud Gateway 应用程序以便它可以使用 Spring Cloud Kubernetes 的服务发现? [英] How to set up Spring Cloud Gateway application so it can use the Service Discovery of Spring Cloud Kubernetes?

本文介绍了如何设置 Spring Cloud Gateway 应用程序以便它可以使用 Spring Cloud Kubernetes 的服务发现?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了两个 Spring Boot 应用程序,它们都将部署在 Kubernetes 集群中.其中一个应用程序将充当网关,因此使用 Spring Cloud Gateway 作为依赖项.另外我想将服务发现与 Spring Cloud Kubernetes 集成,网关使用服务发现来自动生成相应的路由.但是,当我公开在本地 Minikube 集群中运行的网关应用程序并调用第二个应用程序/服务时,我收到 503 错误并显示以下消息:Unable to find instance for ...-service

I created two Spring Boot applications which both will be deployed in a Kubernetes cluster. One of those apps will act as a gateway and therefore uses Spring Cloud Gateway as a dependency. Also I want to integrate service discovery with Spring Cloud Kubernetes and that the gateway uses the service discovery to automatically generate corresponding routes. But when I expose the gateway application, which is running in an local Minikube cluster, and invoke the second app/service I get a 503 error with following message: Unable to find instance for ...-service

目前我已经安装了以下内容:

Currently I have installed following:

  • Minikube
  • 虚拟盒子
  • Docker 工具箱

我创建了一个包含两个子项目(网关和另一个服务)的 Gradle 项目.所有项目都将在本地构建/部署.默认服务帐户具有读取 Kubernetes API 的权限.部署这些服务后,我向外部公开网关服务.在网关服务中,我实现了一些端点,

I have created a Gradle project with two subprojects (gateway and another service). All projects will be build/deployed locally. The default Service Account has permission to read the Kubernetes API. After deployment of those services I expose the gateway service externally. In the gateway service I have some endpoints implemented, which

  1. 通过 DiscoveryClient 提供集群中所有服务的列表.
  2. 在应用层根据 DiscoveryClient 提供的 URI 调用其他服务.

似乎一切正常,但是当我使用 URI/serviceId 调用其他服务时,我收到 503 错误...

Everything seems to work but when I invoke the other service with URI/serviceId I get the 503 error...

使用了以下 Spring Cloud 版本:spring-cloud-starter-kubernetes 1.0.1.RELEASEspring-cloud-starter-gateway 2.1.1.RELEASE

Following Spring Cloud versions are used: spring-cloud-starter-kubernetes 1.0.1.RELEASE spring-cloud-starter-gateway 2.1.1.RELEASE

我的演示应用程序可在 https://github.com/nmaoez/spring-cloud-gateway-kubernetes 和 README.md 提供了在本地 Minikube 集群中部署这两个服务的步骤.还显示了所有可用的端点.但有趣的部分是application.yaml和网关的应用类.

My demo app is available at https://github.com/nmaoez/spring-cloud-gateway-kubernetes and the README.md provides steps to get both services deployed in a local Minikube cluster. Also all available endpoints are shown. But the interessing part are the application.yaml and the application class of the gateway.

application.yaml:

application.yaml:

spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
management:
  endpoints:
    web:
      exposure:
        include: '*'

网关应用程序.java

GatewayApplication.java

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class GatewayApplication {

  @Autowired
  RestTemplate restTemplate;

  @Autowired
  private DiscoveryClient discoveryClient;

  @GetMapping("/")
  @ResponseBody
  public String hello() {
    return "GatewayApplication says hello!";
  }

  @GetMapping("/test")
  @ResponseBody
  public String invokeTestService() {
    List<ServiceInstance> testServiceInstances = this.discoveryClient.getInstances("test-service");
    return restTemplate.getForObject(testServiceInstances.get(0).getUri(), String.class);
  }

  @GetMapping("/services")
  public List<String> services() {
    return this.discoveryClient.getServices();
  }

  @GetMapping("/services/{serviceId}")
  public List<ServiceInstance> servicesById(@PathVariable("serviceId") String serviceId) {
    return this.discoveryClient.getInstances(serviceId);
  }

  @Bean
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }

  public static void main(String[] args) {
    SpringApplication.run(GatewayApplication.class, args);
  }
}

在将 gateway-service/application.yaml 中的 url-expression 字段覆盖为

I got it some how running after I overwrote the url-expression field in the gateway-service/application.yaml to

url-expression: "uri+'/'"

之后,我在调用 gateway-uri/another-service/ 后得到了正确的响应.但我的愿望是不明确替换 lb://serviceid 的默认值.我该怎么做?

After that I got a correct response after I invoked gateway-uri/another-service/. But my wish is to not explicitly replace the default of lb://serviceid. How can I do that?

我希望如果我通过网关调用集群中的另一个服务,我会得到 200 响应和基于应用程序的其余控制器的正确答案.

I expect that if I invoke another service in the cluster though the gateway, I get a 200 response and the correct answer based in the rest controller of the application.

推荐答案

我刚刚使用 Spring Cloud Gateway 和 Kubernetes 实现了一个示例应用程序,它在 Docker Desktop 中的作用就像一个魅力.并且不需要额外或有趣的配置.

I just implemented an example application using Spring Cloud Gateway and Kubernetes, that works like a charm in Docker Desktop. And no extra nor funny configurations were needed.

如果它可以帮助这是我的build.gradle:

If it may help this was my build.gradle:

plugins {
    id 'org.springframework.boot' version '2.4.2'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.example'
version = '0.1.0-SNAPSHOT'

repositories {
    mavenCentral()
    maven { url 'https://repo.spring.io/milestone' }
}

ext {
    set('springCloudVersion', "2020.0.0")
    set('springCloudKubernetesVersion', '1.1.7.RELEASE')
    set('springCloudVersion', '2020.0.0')
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
    implementation 'org.springframework.cloud:spring-cloud-starter-sleuth'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    implementation "org.springframework.cloud:spring-cloud-starter-kubernetes:$springCloudKubernetesVersion"
    implementation "org.springframework.cloud:spring-cloud-starter-kubernetes-config:$springCloudKubernetesVersion"
    implementation "org.springframework.cloud:spring-cloud-starter-kubernetes-ribbon:$springCloudKubernetesVersion"
    implementation "org.springframework.cloud:spring-cloud-starter-kubernetes-loadbalancer:$springCloudKubernetesVersion"
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:$springCloudVersion"
    }
}

test {
    useJUnitPlatform()
}

这是来自 application.yaml 的配置:

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true

最后,DiscoveryClient 在应用程序中启用:

And finally, the DiscoveryClient is enabled in the app:

@SpringBootApplication
@EnableDiscoveryClient // So services can be discovered
public class GatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }

}

请注意,正如 Jakub Kubrynski 所说,您必须包含 Ribbon 依赖项.

Note as Jakub Kubrynski said, you must include the Ribbon dependency.

还要注意路由仅在网关部署到 K8s 集群时才有效.在它之外,它可以看到 K8s 服务,但无法路由到它们,因为它们使用的是 K8s 网络中的 IP 地址.

Also beware routing only works when the gateway is deployed to the K8s cluster. Outside it, it can see the K8s services but cannot route to them since they are using IP addresses in the K8s network.

这篇关于如何设置 Spring Cloud Gateway 应用程序以便它可以使用 Spring Cloud Kubernetes 的服务发现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆