Issue
I am using Spring Cloud Kubernetes and I am trying to make feign able to send requests based on the name of the services present in kubernetes, but I can't, when I try to make a request the following error occurs:
"timestamp": "2019-12-06T15:37:50.285+0000",
"status": 500,
"error": "Internal Server Error",
"message": "com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo",
"trace": "java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: poc-saldo\n\tat org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient.execute....
I tried to call other services within the cluster and the problem is the same for all of them, I did a test by going into the poc-deposit pod and doing a poc-balance curl and it works normally, so the problem is not with the poc-deposit service. balance or with kubernetes's service discovery apparently.
The project has a public profile at:
https://gitlab.com/viniciusxyz/spring-kubernetes-feign
For those who want more direct information:
My main class is as follows:
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceDiscoveryApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceDiscoveryApplication.class, args);
}
}
My interface with feign is as follows:
@FeignClient("poc-saldo")
public interface ProxyGenerico {
@RequestMapping(method = RequestMethod.GET)
String getHttpResponse();
}
I can list the services available in kubernetes within the application as follows:
@RestController
public class RestTest {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private ProxyGenerico proxyGenerico;
@GetMapping("/services")
public ResponseEntity<?> services() {
return new ResponseEntity<Object>(discoveryClient.getServices(), HttpStatus.OK);
}
@GetMapping("/pocsaldo")
public ResponseEntity<?> gitlab() {
return new ResponseEntity<Object>(proxyGenerico.getHttpResponse(), HttpStatus.OK);
}
}
And in this list I have several services among them the service I want to access called poc-balance, the return json looks like the following:
[
"poc-deposito",
"poc-saldo",
"sonarqube",
"sql-server-sonar",
"zookeeper",
"gitlab"
]
To complement the list follow my dependencies:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
The discoveryClient.getInstances ("poc-saldo") command returns:
[
{
"instanceId": "32a4db0d-0549-11ea-8850-e0d55ef66cf8",
"serviceId": "poc-saldo",
"secure": false,
"metadata": {
"helm.sh/chart": "spring-boot-app-0.1.23",
"port.http": "8080",
"app.kubernetes.io/managed-by": "Tiller",
"app.kubernetes.io/name": "poc-saldo",
"app.kubernetes.io/instance": "banco-digital-poc-saldo",
"app.kubernetes.io/version": "1.0"
},
"port": 8080,
"host": "10.42.0.60",
"scheme": "http://",
"uri": "http://10.42.0.60:8080"
}
]
Can you think of where the problem might be?
Solution
Long story short, Spring Cloud Feign works perfectly fine with Spring Cloud Kubernetes as of July 2021. I've moved a Spring Cloud Feign project from using Spring Cloud Netflix to Spring Cloud Kubernetes and no change in the Feign interfaces was required. I just removed the previous Service Registry (Eureka) dependency from my build.gradle
file and added:
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-all'
The support for Spring Cloud LoadBalancer which is now used by Spring Cloud Feign was added to Spring Cloud Kubernetes and Ribbon was removed as of Spring Cloud 2020.0. (aka Ilford), therefore there is no need to exclude it anymore.
Beyond that, the only change required in the whole codebase was annotating the Spring Boot application class with @EnableDiscoveryClient
to enable K8s-native Service Discovery:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class BookApplication {
Spring Cloud Feign uses Spring Cloud LoadBalancer which when running on Kubernetes leverages Discovery Client for Kubernetes to check for service instances. As a result, it only chooses from instances that are up and running. The only requirement is to align the Kubernetes service name with spring.application.name
property. Just like that:
application.properties(yaml):
spring.application.name=library-book-service
combined with the following Kubernetes configuration
kubectl get svc:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
library-book-service ClusterIP 10.100.200.235 <none> 8080/TCP 5d21h
Answered By - dbaltor
Answer Checked By - Katrina (JavaFixing Volunteer)