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?
If you use Ribbon for load balancing I see it in your error org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient
You need say Ribbon about real address all your microservices and use for this action discovery Client.
Above your main class, add a few annotation
@EnableDiscoveryClient
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = RibbonConfiguration.class)
public class MyApp
Add implementations yours dynamic Server List
public class MyServerList extends AbstractServerList<Server> {
private final DiscoveryClient discoveryClient;
private IClientConfig clientConfig;
public MyServerList(DiscoveryClient discoveryClient) {
this.discoveryClient = discoveryClient;
}
@Override
public List<Server> getInitialListOfServers() {
return getUpdatedListOfServers();
}
@Override
public List<Server> getUpdatedListOfServers() {
Server[] servers = discoveryClient.getInstances(clientConfig.getClientName()).stream()
.map(i -> new Server(i.getHost(), i.getPort()))
.toArray(Server[]::new);
return Arrays.asList(servers);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
this.clientConfig = clientConfig;
}
}
Add RibbonConfiguration.class
public class RibbonConfiguration {
@Autowired
private DiscoveryClient discoveryClient;
@Bean
@ConditionalOnMissingBean
public ServerList<?> ribbonServerList(IClientConfig config) {
MyServerList myserverLis = new MyServerList(discoveryClient);
myserverLis.initWithNiwsConfig(config);
return myserverLis;
}
}
and you can config in your app property refresh time I mean period of time call getUpdatedListOfServers