Table of Contents |
---|
EN | ES
As a local balancer, Ribbon allows you to invoke services in the CaaS infrastructure transparently regardless of the number of Pods behind the service. In infrastructures with Kubernetes, you can also do without a discovery service (such as Eureka, Consul ...) since Ribbon uses the Kubernetes API to discover the Pods.
To integrate Ribbon, you must add the Ribbon dependence to your Maven project:
Code Block |
---|
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
|
Add the @LoadBalanced annotation to the RestTemplate:
Code Block |
---|
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(factory());
} |
Each Ribbon client is associated with a service name, so in your application, you must declare as many Ribbon customers (No RestTemplate, these only need to be @LoadBalanced) as balanced destinations you have. This can be done in the SpringBootApplication class itself to which you also need to add the @EnableDiscoveryClient annotation.
Code Block |
---|
@RibbonClients(value = {
@RibbonClient(name = "${connection-protocol-redsys.protocolredsys.service}", configuration = RibbonConfiguration.class),
@RibbonClient(name = "${connection-protocol-sat.protocolsat.service}", configuration = RibbonConfiguration.class),
})
@EnableDiscoveryClient
public class BackendBusinessAuthorizationApplication {
public static void main(String[] args) {
SpringApplication.run(BackendBusinessAuthorizationApplication.class, args);
}
} |
As you can see, you have the @RibbonClient name parameterized and you indicate a Configuration class for each client: RibbonConfiguration.class
In this class, a basic configuration would be:
The declaration of a Bean that declares the rule to follow to choose a destination (specific Pod) behind a service. In this case it is based on response time, although there are many others, and they can even be programmed ad-hoc, such as RoundRobin, Geographical affinity...
The declaration of a Bean that will periodically ping the Pods behind the service to identify which ones are "alive".
Code Block |
---|
public class RibbonConfiguration {
@Autowired
IClientConfig ribbonClientConfig;
@Bean
public IPing ribbonPing(IClientConfig config) {
return new PingUrl(false, "/balancer/ping");
}
@Bean
public IRule ribbonRule(IClientConfig config) {
return new WeightedResponseTimeRule();
}
} |
The Ping's previous configuration forces each destination to implement a controller that responds to the Ping url:
Code Block |
---|
@RestController
@RequestMapping(value ="/balancer")
public class PingController {
@GetMapping(path = "/ping")
public void ping() {
}
} |
Once you have all this programmatic configuration, the application is ready to use Ribbon locally balancing for the services indicated in the declared RibbonClients. The following is to configure the services:
Local Development. You do not need to have any discovery service, you can declare the service in the application.yml:
Code Block |
---|
connection-protocol-redsys:
protocolredsys.service: protocolredsys
endpoint: http://${connection-protocol-redsys.protocolredsys.service}/protocol/redsys/v1
connection-protocol-sat:
protocolsat.service: protocolsat
endpoint: http://${connection-protocol-sat.protocolsat.service}/protocolsat/protocol/v1
protocolredsys:
ribbon:
eureka:
enabled: false
listOfServers: localhost:9866
ServerListRefreshInterval: 30000
protocolsat:
ribbon:
eureka:
enabled: false
listOfServers: localhost:9890
ServerListRefreshInterval: 30000
|
As you can see, this is done to declare two services with Ribbon: protocolredsys and protocolsat, which are those indicated in the url as a service name and those that were included parameterized for the name attribute in the @RibbonClient in the SpringBootApplication class. Thus, protocolredsys points to localhost:9866 and protocolsat to localhost:9890
Deployment in Kubernetes. In this case, the application-docker.yml is configured so that the name of the services can be passed as an environment variable:
Code Block |
---|
connection-protocol-redsys:
protocolredsys.service: ${protocol-redsys-service}
connection-protocol-sat:
protocolsat.service: ${protocol-sat-service} |
To use Ribbon in Kubernetes, add the dependency through a specific profile, so that it is added only if the destination of the compile is a CaaS kubernetes:
Code Block |
---|
<profiles>
<profile>
<id>kubernetes</id>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
<!-- version>${latest.version}</version-->
</dependency>
</dependencies>
</profile>
</profiles> |
In the latest versions of Spring Cloud, this dependency is already included in the starter itself, so you don’t need to indicate version. If you are using an old version of Spring cloud, please check consult the version of this library to use, since not all of them are valid.
The next thing is to enable the service in Kubernetes. By default, a service is created for each workload, but this service points to port 42. Therefore, you need to create a service that points to the correct port exposed by your pods:
...
Once the service is created, you can configure the environment variables indicated in your application’s application-docker.yml:
...
And the integration of Spring Cloud and Kubernetes will be in charge of balancing between the different Pods behind each service.
Important note:
It is very likely that, when starting the application for the first time, you will have a permission error like this one:
Code Block |
---|
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://10.43.0.1/api/v1/namespaces/testloadbalancing/endpoints. Message: Forbidden!Configured service account doesn't have access. Service account may have been revoked. endpoints is forbidden: User "system:serviceaccount:testloadbalancing:default" cannot list resource "endpoints" in API group "" in the namespace "testloadbalancing". |
This is because the Ribbon library for Kubernetes invokes the Kubernetes API and does not have permission. To give it permission, you need to enter the kubernetes console and create a role that allows the user account that runs your workload to consult the Kubernetes API with:
Code Block |
---|
kubectl create clusterrolebinding testloadbalancing:default --clusterrole=cluster-admin --serviceaccount=testloadbalancing:default |
...
Where:
testloadbalancing:default --> Is the role’s name.
-clusterrole=cluster-admin --> Are the role’s permissions.
-serviceaccount=testloadbalancing:default --> Is the user’s account.
The three parameters can be identified in the error message itself.