如何设置Spring Cloud Gateway应用程序使其可以使用Spring Cloud Kubernetes的服务发现?

时间:2019-05-16 14:07:21

标签: spring-boot spring-cloud service-discovery spring-cloud-gateway spring-cloud-kubernetes

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

当前我已安装以下内容:

  • Minikube
  • VirtualBox
  • Docker工具箱

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

  1. 提供集群中所有服务的列表,以查找DiscoveryClient。
  2. 在应用程序层上,基于DiscoveryClient提供的URI调用其他服务。

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

使用以下Spring Cloud版本: spring-cloud-starter-kubernetes 1.0.1。发布 spring-cloud-starter-gateway 2.1.1。发布

我的演示应用程序可以在https://github.com/nmaoez/spring-cloud-gateway-kubernetes上使用,README.md提供了将两个服务都部署在本地Minikube群集中的步骤。还显示了所有可用的端点。但是有趣的是网关的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: '*'

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字段改写为

后,我得到了一些运行方式的信息
url-expression: "uri+'/'"

此后,我调用gateway-uri/another-service/后得到了正确的响应。但我希望不明确替换默认的lb://serviceid。我该怎么办?

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

2 个答案:

答案 0 :(得分:1)

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

如果有帮助,这就是我的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 在应用中启用:

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

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

}

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

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

答案 1 :(得分:0)

您还必须将依赖项添加到spring-cloud-starter-kubernetes-ribbon

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
            <version>1.0.1.RELEASE</version>
        </dependency>

然后它就可以工作,而无需进行任何重写,只需使用spring.cloud.gateway.discovery.locator.enabled: true