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
- VirtualBox
- Docker Toolbox
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
- provide a list of all services in the cluster vie the DiscoveryClient.
- on application layer invoke the other service based on the URI provided by the DiscoveryClient.
Everything seems to work but when I invoke the other service with URI/serviceId
I get the 503 error...
Following Spring Cloud versions are used: spring-cloud-starter-kubernetes 1.0.1.RELEASE spring-cloud-starter-gateway 2.1.1.RELEASE
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:
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);
}
}
I got it some how running after I overwrote the url-expression field in the gateway-service/application.yaml to
url-expression: "uri+'/'"
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?
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.