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

11
我创建了两个Spring Boot应用程序,它们都将部署在Kubernetes集群中。其中一个应用程序将作为网关,因此使用Spring Cloud Gateway作为依赖项。我还希望使用Spring Cloud Kubernetes集成服务发现,让网关使用服务发现自动生成相应的路由。但是,当我公开运行在本地Minikube集群中的网关应用程序并调用第二个应用/服务时,会收到503错误,并显示以下消息:Unable to find instance for ...-service 目前我已安装以下内容:
  • Minikube
  • VirtualBox
  • Docker Toolbox
我创建了一个Gradle项目,其中包含两个子项目(网关和另一个服务)。所有项目都将在本地构建/部署。默认的服务帐户具有读取Kubernetes API的权限。在部署这些服务之后,我外部公开了网关服务。在网关服务中,我实现了一些端点,它们:
  1. 通过DiscoveryClient提供集群中所有服务的列表。
  2. 在应用程序层面根据DiscoveryClient提供的URI调用其他服务。
一切似乎都正常工作,但是当我使用URI/serviceId 调用其他服务时,我收到了503错误...。
使用以下Spring Cloud版本: 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和application类。
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);
  }
}

我设法使其运行,之后在网关服务/application.yaml中覆盖了url-expression字段

url-expression: "uri+'/'"

之后我在调用gateway-uri/another-service/后得到了正确的响应。但是我的愿望是不要显式地替换lb://serviceid的默认值。我该怎么做呢?
我期望如果我通过网关调用集群中的另一个服务,我会得到一个200响应和基于应用程序REST控制器的正确答案。

我在GKE上遇到了类似的问题,你找到解决方案了吗?请参见此处:https://dev59.com/XbXna4cB1Zd3GeqPRtlh#57594399 - akuma8
我卡住了,你已经找到解决方案了吗? - Patrick
3个回答

3
您需要在项目中添加依赖项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。"Original Answer"翻译成"最初的回答"。

1
我有类似的问题,这个答案没有帮助。 - akuma8

2

我刚使用Spring Cloud Gateway和Kubernetes实现了一个示例应用程序,在Docker Desktop上运行非常顺利,而且不需要任何额外或有趣的配置。

如果有所帮助,这是我的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地址。


2
我能够使用Spring Cloud Kubernetes依赖版本1.1.10.RELEASE和Spring Boot 2.5.7以及Spring Cloud Gateway 3.0.4来设置Spring Cloud网关的发现。下面是pom文件的样例:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>


    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.7</version>
        <relativePath/>
    </parent>

    <groupId>com.csg.cro.rccs</groupId>
    <artifactId>api-gateway</artifactId>
    <version>${revision}</version>
    <name>RCC-APIGateway</name>
    <description>Enable Proxy and verify user token project for Risk 360</description>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
        <spring-cloud.version>2020.0.3</spring-cloud.version>
        <revision>21.7.0-SNAPSHOT</revision>
    </properties>


    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes</artifactId>
            <version>1.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-config</artifactId>
            <version>1.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
            <version>1.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-loadbalancer</artifactId>
            <version>1.1.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
             <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>flatten-maven-plugin</artifactId>
            <version>1.1.0</version>
            <configuration>
                <updatePomFile>true</updatePomFile>
                <flattenMode>resolveCiFriendliesOnly</flattenMode>
            </configuration>
            <executions>
                <execution>
                    <id>flatten</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>flatten</goal>
                    </goals>
                </execution>
                <execution>
                    <id>flatten.clean</id>
                    <phase>clean</phase>
                    <goals>
                        <goal>clean</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        </plugins>
    </build>
    
</project>

我的发现配置看起来像这样:

spring:
  application.name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          url-expression: "'http://'+serviceId+':'+getPort()"
          lower-case-service-id: true


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接