Как настроить приложение Spring Cloud Gateway, чтобы оно могло использовать Service Discovery в Spring Cloud Kubernetes?
Я создал два приложения Spring Boot, которые будут развернуты в кластере Kubernetes. Одно из этих приложений будет действовать как шлюз и, следовательно, использует Spring Cloud Gateway в качестве зависимости. Также я хочу интегрировать обнаружение служб с Spring Cloud Kubernetes и чтобы шлюз использовал обнаружение служб для автоматической генерации соответствующих маршрутов. Но когда я открываю приложение шлюза, работающее в локальном кластере Minikube, и вызываю второе приложение / службу, я получаю ошибку 503 со следующим сообщением: Unable to find instance for ...-service
В настоящее время я установил следующее:
- Minikube
- VirtualBox
- Панель инструментов Docker
Я создал проект Gradle с двумя подпроектами (шлюз и другой сервис). Все проекты будут построены / развернуты локально. Учетная запись службы по умолчанию имеет разрешение на чтение API Kubernetes. После развертывания этих сервисов я выставляю службу шлюза извне. В службе шлюза у меня реализованы некоторые конечные точки, которые
- предоставить список всех служб в кластере с помощью DiscoveryClient.
- на прикладном уровне вызовите другую службу на основе URI, предоставленного DiscoveryClient.
Кажется, все работает, но когда я вызываю другой сервис с 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.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);
}
}
Я понял, как работает после того, как я переписал поле url-expression в gateway-service / application.yaml, чтобы
url-expression: "uri+'/'"
После этого я получил правильный ответ после того, как вызвал gateway-uri/another-service/
, Но я хочу, чтобы не заменить явно lb://serviceid
, Как я могу это сделать?
Я ожидаю, что если я вызову другую службу в кластере через шлюз, я получу ответ 200 и правильный ответ, основанный на контроллере остальной части приложения.
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
Я только что реализовал пример приложения с использованием 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);
}
}
Обратите внимание, как сказал Якуб Кубрински, вы должны включить зависимость ленты.
Также будьте осторожны, маршрутизация работает только тогда, когда шлюз развернут в кластере K8s. За его пределами он может видеть службы K8s, но не может маршрутизировать к ним, поскольку они используют IP-адреса в сети K8s.
Я могу настроить весенний облачный шлюз с обнаружением зависимости spring-cloud-kubernetes версии 1.1.10.RELASE и Spring-boot: 2.5.7 Spring облачный шлюз: 3.0.4
Файл 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