domingo, 24 de junio de 2018

EUREKA - RIBBON - Client Load Balancing (IV)

Esta entrada es la cuarta de la serie sobre EUREKA y RIBBON. La dedicamos a ver qué hacer con ambas soluciones del stack NETFLIX en un entorno Kubernetes.

En nuestro caso, en entorno local usamos Minikube, instalado sobre un Ubuntu virtualizado corriendo en VMWare player (mejor opción que Virtualbox).

Bien, veremos que Kubernetes ya nos provee de un servicio de descubrimiento y balanceo que hace innecesario usar el stack Netflix en lo que respecta a eureka y ribbon (para este último hay una forma, kubeflix, de poder usarlo dentro de kubernetes).

Por tanto, deberemos hacer una serie de cambios sobre el código que hemos ido compartiendo en gitlab. Directamente hemos obviado EUREKA y hemos modificado los dos microservicios para evitar el uso de RIBBON (sólo en el profile "prod", para el resto de profiles "des" y "dev" vale todo lo dicho en las entradas anteriores).

Explicamos aquí como proceder, entonces, en Minikube. Recordamos, minikube es un cluster kubernetes de un sólo nodo.

Lo arrancamos con "minikube start". Habitualmente se atuconfigura con la ip "192.168.99.100". Podemos verlo con "minikube ip". Cuando acabemos podemos parar con "minikube stop"

Todo lo que mostramos a continuación lo hacemos sobre nuestro ubuntu.


Ingress y Secret
En un entorno kubernetes, cada pod (equivalente a container en docker) responderá a una determinada ip, gestionada por el mismo kubernetes. Por tanto, para evitar el conocimiento detallado de la infraestructura, dejando que el mismo kubernetes haga de forma autónoma, lo mejor es crear un "dominio" de trabajo.

En nuestro caso hemos creado "gincol.blog.com". Esta entrada la introduciremos en el "/etc/host" del ubuntu virtualizado:

    192.168.99.100  gincol.blog.com

Además, como demo, proveeremos protocolo seguro para acceder a este dominio. Para ello generamos lo que en kubernetes se llama secret. Ejecutamos el siguiente comando en un directorio de trabajo

    openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout gincol.blog.com.key -out gincol.blog.com.cert -subj "/CN=gincol.blog.com/O=gincol.blog.com"

A continuación creamos el secret desde el mismo directorio desde el que tenemos los certificados creados:

    kubectl create secret tls gincol.blog.com-secret --key gincol.blog.com.key --cert gincol.blog.com.cert

Podemos verificarlo

    kubectl get secret

y obtener información con

    kubectl describe secret gincol.blog.com-secret

Crearemos un ingres para cada uno de los microservicios (lo veremos más adelante). El esquema simple nos lo muestra la propa api de kubernetes:

Ingress nos proporciona una forma de resolución de nombre interpuesto entre las peticiones de clientes externos (ya sean de internet, intranet...) y nuestros servicios desplegados en kubernetes.

Con secret, además, nos permite de una forma sencilla la adición de protección ssl.


Imagenes y Registro 
En nuestro caso, el laboratorio local que hemos configurado, para el despliegue en Kubernetes usamos un entorno CI. El código lo tenemos en nuestro eclipse windows. En ubuntu tenemos un jenkins y un gitlab (ambos gratuitos).

Por cada microservicio creamos:

  • repositorio gitlab con un webhook apuntando al job jenkins
  • un job jenkins de tipo pipeline

Cuando hacemos "git push ....." a nuestro repo, se dispara el webhook que informa a jenkins que tiene a su disposición nuevo código. Jenkins recoge el código, dentro del cual hay un Jenkinsfile que describe los pasos (compilación y creación del artefacto, push al registro privado de imágenes, deploy en Kubernetes de los diferentes ingress, deploys y services) a realizar.

En nuestro caso, con cada "git push..." se desencadena todo ese hilo de acciones, que tras unos minutos vemos operativo.

No es trivial hacerlo y menos aún explicarlo en esta entrada, sería kilométrica. Por lo que no nos detenemos en ello. Para simularlo deberéis copiar los artefactos generados en vuestro windows, llevadlos al ubuntu, junto con el docker-compose y Dockerfile que vimos en la anterior entrada,

Antes de lanzarlo haced que estos comando operen sobre Minikube, lanzando previamente

    eval $(minikube docker-env)

De esta forma, todos los comandos docker y docker-compose que lancéis lo haréis sobre Minikube.

Para subir la imagen generada al registro local debéis:

  • Crear el registro: docker run -d -p 5000:5000 --restart=always --name registry-srv -v /data/docker-registry:/var/lib/registry registry:2
  • subir la imagen al registro: docker push localhost:5000/MI_IMAGEN
  • ver las imágenes del registro: curl -X GET http://192.168.99.100:5000/v2/_catalog
  • eliminar una imagen del registro: docker image remove localhost:5000/MI_IMAGEN



Microservicio uno
De este levantaremos 3 réplicas. Proveemos en un mismo yaml (App.yaml) la configuración de deploy y servicio.

Nos detenemos sólo en lo esencial de dicho fichero:

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: client-one
      ...
    spec:
      replicas: 3
        spec:
          containers:
            - name: client-one
              image: localhost:5000/client-one-load-balancing
              ports:
                - containerPort: 8090
              env:
              - name: SPRING_PROFILES_ACTIVE
                value: prod
              readinessProbe:
                httpGet:
                  path: /client-one-load-balancing/readiness
                  port: 8090
                initialDelaySeconds: 30
                timeoutSeconds: 5  
              livenessProbe:
                httpGet:
                  path: /client-one-load-balancing/liveness
                  port: 8090
                initialDelaySeconds: 30
                timeoutSeconds: 5

    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: client-one
      ...
    spec:
      type: NodePort
      ports:
      - port: 8090
        protocol: TCP
      selector:
        app: client-one
        tier: backend  

Los "---" son necesarios para separar el deploy del service. Los "..." indican que no es completo (está completo en el gitlab)

Se han añadido "readinessProbe" y "livenessProbe" como peticiones de "health check" que permiten a kubernetes ver la salud de nuestros pods. Para ello hemos creado un "MonitorController.java" con ambos endpoints. En ellos sólo devolvemos un OK. Si kubernetes no obtiene un 200 como código de respuesta http, no pasará peticiones a nuestro pod.

En dichos endpoints podemos hacer aquellas validaciones que creamos oportunas para asegurar que nuestro microservicio está realmente disponible (conexión a bdd o a un recurso externo, etc...).

Con NodePort en el service declaramos el puerto por el que será visible nuestro microservicio.
El nombre del microservicio "client-one" es semejante al nombre que descubríamos en EUREKA en las versiones de profiles "des" y "dev".

Para ejecutar el fichero yaml hacemos
    kubectl apply -f App.yaml (o bien kubectl create -f App.yaml)

Si necesitamos modificar algo y volverlo lanzar
    kubectl apply -f App.yaml (o bien kubectl replace --force --cascade=true -f App.yaml)


El Ingress.yaml de este microservicio es el siguiente:

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: client-two-ing
      annotations:
        kubernetes.io/ingress.class: nginx
    spec:
      tls:
        - hosts:
          - gincol.blog.com
          secretName: gincol.blog.com-secret
      rules:
      - host: gincol.blog.com
        http:
          paths:
          - path: /client-two-load-balancing
            backend:
              serviceName: client-two
              servicePort: 9999

Se observa la referencia al secret anteriormente creado, la definición del dominio gincol.blog.com, el serviceName, que ha de corresponderse con el nombre del servicio. Se observa también el path asociado al context de nuestro microservicio (definido en el application-prod.yml) y el puerto que sigue el mismo patrón.

Se lanza como antes "kubectl apply -f Ingress.yaml"


Microservicio dos
Muy semejante al primero, con los cambios obvios siguiendo el mismo patrón.
No lo detallamos, se puede encontrar en el gitlab.

Unicamente indicamos como se enlaza el dos con el uno, ahora sin RIBBON. Se hace mediante la url

    http://client-one:8090/client-one-load-balancing/saludo

donde se ve que la referencia es al nombre del servicio uno, que como dijimos más arriba viene a ser el nombre "descubierto" en EUREKA en las versiones anteriores. Se podría haber configurado como nombre de dominio, el nombre "DNS entry", que sigue el patrón "service.namespace.svc.cluster.local", que en nuestro caso hubiese sido:

    http://client-one.default.svc.cluster.local:8090/client-one-load-balancing/saludo


Prueba
Abrimos un firefox en nuestro ubuntu y lazamos la url directa de nuestro microservicio uno: "https://gincol.blog.com/client-one-load-balancing/saludo". Si vamos refrescando veremos que cada vez responde un pod diferente (de los tres que levantamos). Hemos añadido código para verificar el host que reponde





Ahora invocamos al microservicio dos "https://gincol.blog.com/client-two-load-balancing/hola" (que acaba llamando al uno):




Ahora podemos jugar un poco con los pods, borramos uno de ellos
primero vemos los activos "kubectl get pods", luego eliminamos uno "kubectl delete pod ID_POD". Vemos que Kubernetes lo que hace es levantar un nuevo pod de forma que siempre haya tres activos

Seguimos lanzando peticiones. Obsrevamos que no se pasan peticiones al pod borrado y tampoco al nuevo hasta que esté totalmente activo, gracias al "readinessProbe". Aquí lo tenemos, con nueva ip:




Código y más info
El código lo podéis descargar de
https://gitlab.com/gincol-blog/client-one-load-balancing.git
https://gitlab.com/gincol-blog/client-two-load-balancing.git

Tenéis más info en
https://www.paradigmadigital.com/dev/microservicios-2-0-spring-cloud-netflix-vs-kubernetes-istio/
http://blog.christianposta.com/microservices/netflix-oss-or-kubernetes-how-about-both/
https://github.com/fabric8io/kubeflix

viernes, 22 de junio de 2018

EUREKA - RIBBON - Client Load Balancing (III)

Vamos añadiendo elementos a esta prueba de concepto.

Añadimos en esta entrada despliegue en Docker. Para ello hemos modificado y añadido diferentes elementos de configuración en gitlab.

Por tanto, si ya os habíais descargado el código de las anteriores entradas, deberéis actualizarlo. Recuerdo los enlaces de las anteriores entradas (I y II)


Recuerdo también el objetivo de este ciclo de entradas
  • Un microservicio con tres replicas en ejecución, mediante tres puertos diferentes.
  • Un segundo microservicio usará RIBBON para invocar al primero mediante balanceo desde cliente. Lo haremos de dos formas:
    • Mediante EUREKA (con conocimiento del nombre del primer microservicio)
    • Sin EUREKA (invocando en lugar del nombre a "localhost")
Por tanto, si eso ya nos funcionaba en un entorno local "habitual" ahora le añadimos docker. Se requiere tener instalado docker, docker-compose y docker-machine (este último no sería indispensable si trabajamos con la machine "default", si queremos crear otra si que hará falta).

Al final de esta entrada tendremos los siguientes containers en ejecución:

  1. Un contenedor con nuestro eureka-server
  2. Tres contenedores con el microservicio uno
  3. Un contenedor con el microservicio dos invocando vía RIBBON a los tres contenedores anteriores.
Comencemos.


Previo

Hemos de comentar un detalle importante. Para optimizar el lanzamiento de nuestras aplicaciones en docker nos hemos creado un sistema de despliegues propio que merece ser explicado. Lo hacemos en entrada aparte ya que os lo encontraréis en el código de todos los proyectos.

Por tanto, será necesario leerlo si se quiere adoptar ese sistema. En otro caso, se deberá lanzar de forma manual (docker-compose up -d......). Este es el procedimiento que si que documentamos en esta y sucesivas entradas que tengan que ver con docker.


docker-compose y Dockerfile
Necesitaremos un docker-compose.yml por cada elemento, uno para eureka, otro para el microservicio uno (con tres containers) y otro para el microservicio dos.


Eureka

El docker-compose-yml de eureka es el siguiente:

    version: '3.5'
    services:
      eureka-server:
        build: 
          context: .
          dockerfile: ./docker/Dockerfile
        image: eureka-server-img
        container_name: eureka-server-ct
        environment:
           - "SPRING_PROFILES_ACTIVE=dev" 
        ports:
          - "8761:8761"
        networks:
          - arq-net
  
    networks:
      arq-net:
        name: arq-net
        driver: bridge

Como datos a tener en cuenta:
  • Se lanza con "docker-compose up -d --build" desde el directorio raíz del proyecto, donde se encuentra el fichero.
  • Es el primero que se ha de lanzar.
  • crea una red, necesaria para que exista la comunicación entre containers lanzados desde diferentes docker-compose.
  • Los microservicios referenciarán (como veremos) esa red creada

En "dockerfile" aparece la ruta del fichero Dockerfile que creará la imagen en base a una imagen publicada en docker hub. Este es el contenido del Dockerfile:

    FROM java:openjdk-8-jdk-alpine

    # add el jar con el nombre del "finalName" del pom.xml
    ADD target/eureka-server.jar /app.jar

    # se modifica la fecha a la actual
    RUN sh -c 'touch /app.jar'

    # comando a ejecutar
    CMD ["java", "-jar", "/app.jar"]


Como se puede ver, la imagen base (FROM) es la "java:openjdk-8-jdk-alpine". Es decir, para hacer correr nuestro server eureka sólo necesitamos una imagen con java8 instalado. Suficiente.

Le introducimos el jar (con ADD) y lo ejecutamos (CMD) con "java -jar ....". por tanto, aunque es obvio, es imprescindible haber lanzado un "mv clean install" (por ejemplo) de nuestro proyecto, para que genere el artefacto a desplegar en nuestro container.



Microservicio uno

El docker-compose.yml del microservicio uno es un poco más largo, ya que contiene la descripción de los tres contenedores. Sólo copio aquí el de uno, indicando en negrita lo que se debe cambiar para los otros dos

    version: '3.5'
    services:
      client-one-load-balancing-1:
        build: 
          context: .
          dockerfile: ./docker/Dockerfile
        image: client-one-load-balancing-img
        container_name: client-one-load-balancing-ct-1
        environment:
           - "SPRING_PROFILES_ACTIVE=dev" 
           - "SERVER_PORT=8090"
        ports:
          - "8090:8090"
        networks:
          - arq-net

    client-one-load-balancing-2:
    .....
      environment:
        - "SERVER_PORT=8091"
      ports:
        - "8091:8091"

    client-one-load-balancing-3:
    ....
      environment:
        - "SERVER_PORT=8092"
      ports:

        - "8091:8091"

    networks:
      arq-net:
        external: true

La imagen (image) no cambia, será la misma para los tres. El puerto pondremos 8091 y 8092 siguiendo el mismo patrón.

La red (arq-net) ahora se referencia la creada por el docker-compose de eureka. Se especifica como "external: true" (ya creada).

El Dockerfile es exactamente igual al del eureka, cambiando el nombre al del jar del microservicio

    ADD target/client-one-load-balancing.jar /app.jar

Arrancamos como antes, lanzando el comando "docker-compose up -d --build" desde el directorio raíz del proyecto, al mismo nivel del docker-compose.yml


Microservicio dos

Su docker-compose.yml es muy parecido a los anteriores

    version: '3.5'
    services:
      client-two-load-balancing:
        build: 
          context: .
          dockerfile: ./docker/Dockerfile
        image: client-two-load-balancing-img
        container_name: client-two-load-balancing-ct
        environment:
           - "SPRING_PROFILES_ACTIVE=dev" 
        ports:
          - "9999:9999"
        networks:
          - arq-net
  
    networks:
      arq-net:
      external: true

Y su Dockerfile también, sólo se ha de cambiar la siguiente línea:

    ADD target/client-two-load-balancing.jar /app.jar

Arrancamos como antes, lanzando el comando "docker-compose up -d --build" desde el directorio raíz del proyecto, al mismo nivel del docker-compose.yml


Prueba

Accedemos a Eureka (http://192.168.99.100:8761/) y vemos el primer microservicio replicado tres veces. Vemos también el segundo microservicio:


Ahora invocamos nuestro primer microservicio a partir de la url "http://192.168.99.100:9999/hola?nombre=José". Si vamos refrescando obtenemos una respuesta por cada uno de las réplicas del microservicio uno:






Miscelánea 


La ip de acceso es la de la docker-machine activa y donde hemos desplegado los containers. La obtenemos mediante "docker-machine ip nombre_machine"

Para ver los containers activos "docker ps"
Para ver los containers activos y parados "docker ps -a"

Para ver los logs de uno de los microservicios ejecutamos "docker logs -f id_container" (con -f se nos queda la consola enlazada a la salida del container).

Para ver la red creada "docker network list"

Para parar todos los containers mejor hacerlo con "docker-compose down" desde los directorios desde los que hemos lanzado anteriormente los "... up...".
También se pueden parar directamente con "docker stop id_container" y eliminarlos con "docker rm id_container".

Paramos la docker-machine con "docker-machine stop nombre_machine"

En una entrada posterior añadiremos la configuración para extender la prueba de concepto a Minikube, un cluster Kubernetes de un sólo nodo, a modo de laboratorio.


martes, 19 de junio de 2018

EUREKA - RIBBON - Client Load Balancing (II)

Vamos con RIBBON.

Los que no lo hayan visto la primera entrada deberán inexcusablemente hacerlo, ya que para que lo que aquí compartimos funcione necesita de EUREKA, y es en dicha primera entrada donde se explica.

En la tercera desplegaremos todos los elementos en un entorno docker.

En la cuarta lo haremos sobre un entorno kubernetes.

El código de ambos micorservicios lo tenéis en microservicio1 y microservicio2.


Primer microservicio

Mostramos los detalles del primer microservicio, el que hará de "servidor" y recibirá peticiones del segundo.


pom.xml

Sólo mostramos la dependencia que nos permite registrarlo en EUREKA

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>



application.yml

Este es su contenido:

    spring:
      application:
        name: client-one-load-balancing
      profiles:
        active: des

    eureka:
      client:
        enabled: true
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance: 
        leaseRenewalIntervalInSeconds: 1
        leaseExpirationDurationInSeconds: 1

Lo importante para esta entrada es la configuración de acceso a eureka. 
Habilitamos la conexión, indicando la url del server.

Por defecto, cuando un microservicio se registra en eureka, cada 30 segundos lanza un ping para indicar que está activo. Eureka no se da por enterado del nuevo microservicio hasta tres pings, por tanto 90 segundos. 

Con "leaseRenewalIntervalInSeconds: 1" indicamos que nos basta con uno para darlo por activo.

Igualmente, hasta que no pasan 3 intervalos de 30 segundos sin recibir ping del cliente, eureka no lo hace desaparecer del registro. 

Con "leaseExpirationDurationInSeconds: 1" indicamos que con un intervalo basta para "des-registrarlo". 


java

En la clase main, añadimos la anotación "@EnableEurekaClient" a la cabecera, juntamente con la habitual "@SpringBootApplication".

Para dar servicio hemos declarado un endpoint "/saludo" y otro para la raíz "/", dentro de la clase MainController (anotade la clase con "@RestController")

    @Value("${server.port}")
    String puerto;

    @RequestMapping(value = "/saludo")
    public String greet() {
log.info("Acceso /saludo");

List<String> greetings = Arrays.asList("Hola", "Saludos", "Saludos cordiales");
Random rand = new Random();

int randomNum = rand.nextInt(greetings.size());
        String retorno = greetings.get(randomNum);
        return retorno + ", desde puerto " + puerto;
    }

    @RequestMapping(value = "/")
    public String home() {
log.info("Acceso /");
return "Hola!";
    }


Arranque

Arrancaremos tres réplicas del mismo microservicio. Para hacerlo de la misma forma con los tres arranques los lanzaremos desde línea de comandos. 

Abrimos cmd de windows y nos vamos al directorio raíz del proyecto, donde está ubicado el pom.xml. Nos aseguramos que el JAVA_HOME apunta al jdk 8 (echo %JAVA_HOME%). Si no es así deberemos setear dicha variable en cada una de las consolas (set JAVA_HOME=C:\XXXXXXXX). Por ejemplo en mi caso he de hacer 

    set JAVA_HOME=C:\Java\java8_131

Una vez hecho esto lanzamos los siguientes comandos, uno por cada consola

    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8090
    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8091
    mvn spring-boot:run -Dspring-boot.run.arguments=--server.port=8092

Ya tenemos nuestro primer microservicio levantado y respondiendo a los puertos 8090, 8091 y 8092. 



Podemos validarlo a partir de la url

    http://localhost:8090/saludo
    http://localhost:8091/saludo
    http://localhost:8092/saludo

Veremos que en cada una pone un literal al azar de cualquiera de estos 

    "Hola", "Saludos", "Saludos cordiales"

  añadiendo el puerto activo.

Vemos en el dashboard de eureka nuestros tres microservicios


Los tres registados bajo el nombre "client-one-load-balancing". Este nombre es importante!!!!

Vamos con el segundo microservicio


Segundo microservicio

Estos son los detalles del segundo microservicio, el que hace de cliente.

pom.xml

Necesitamos las siguientes dependencias

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

La específica en este caso es la dependencia de ribbon. La de eureka cliente es como en el primer microservicio.


application.yml

Esta es nuestra configuración usando Ribbon con nombres de servicio suminstrados por Eureka:

     server:
      port: 9999
  
    spring:
      application:
        name: client-two-load-balancing
      profiles:
        active: des

    client-one-load-balancing:
      ribbon:
        #eureka:
          #enabled: false
        listOfServers: client-one-load-balancing:8090,client-one-load-balancing:8091,client-one-load-balancing:8092
        #listOfServers: localhost:8090,localhost:8091,localhost:8092
        ServerListRefreshInterval: 15000
    
    eureka:
      client:
        enabled: true
        service-url:
          defaultZone: http://localhost:8761/eureka/
      instance: 
        leaseRenewalIntervalInSeconds: 1
        leaseExpirationDurationInSeconds: 1

Remarcamos en negrita lo específico de este segundo microservicio.
Vemos el nombre "client-one-load-balancing", que es el nombre de registro del microservicio uno. Vemos también la lista de servers "listOfServers" con los tres servicios levantados, cada uno con su puerto, y de nuevo, en lugar de dominio o ip, vemos el nombre de registro en eureka.

El atributo "ServerListRefreshInterval: 15000" indica, en milisegundos, el intervalo entre ping y ping lanzado desde el microservicio dos a los microservicios "unos".


NOTA:
Si quisiésemos trabajar sin EUREKA deberíamos quitar los comentarios de

       eureka:
          enabled: false
          listOfServers: localhost:8090,localhost:8091,localhost:8092

y comentar:

       #listOfServers: client-one-load-balancing:8090,client-one-load-balancing:8091,client-one-load-balancing:8092

ya que en ese caso no habría ningún servidor de registro que habilite el descubrimiento de nombres.

Deberíamos también eliminar la configuración de EUREKA y la anotación "@EnableEurekaClient" del Application.java de ambos microservicios.

Asimismo deberíamos eliminar la dependencia siguiente de ambos microservicios.

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>


java

En la parte java, usaremos la anotación "@EnableEurekaClient" de la misma forma que en el microservicio uno.

Añadimos una clase de configuración que nos exige ribbon para realizar el blanceo y los "pings". Podéis verla tras la descarga del código del gitlab.

El MainController tiene ciertas particularidades. Pego la clase completa


    @RestController
    @RibbonClient(name = "client-one-load-balancing", configuration = Configuration.class)
    public class MainController {

private static Logger log = LoggerFactory.getLogger(MainController.class);

@LoadBalanced
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}

@Autowired
RestTemplate restTemplate;

@RequestMapping("/hola")
public String hi(@RequestParam(value = "nombre", defaultValue = "Rigoberto") String nombre) {
log.info("parametro recibido: " + nombre);
String saludo = this.restTemplate.getForObject("http://client-one-load-balancing/saludo", String.class);
return String.format("%s, %s!", saludo, nombre);
}

    }

En negrita lo más importante. Se añade la anotación "@RibbonClient" apuntando al nombre del registro eureka del microservicio uno, indicando la clase de configuración comentada más arriba.

Se añade la antación "@LoadBalanced" al bean restTemplate para que haga balanceo a los microservicios declarados en la "listOfServers" del application.yml

Por último, se invoca al microservicio uno vía restTemplate, añadiendo a lo que devuelve aquel, el nombre recibido por parámteros.


Prueba

Arrancamos este segundo microservicio desde eclipse.

Lanzamos repetidamente la url "http://localhost:9999/hola?nombre=Antonio" (podéis cambiar el "nombre" a vuestro gusto.  Obtendremos diferentes resultados. Por ejemplo






Como se puede observar, estamos invocando al microservicio uno, el cual mediante ribbon balancea las peticiones llamando a cualquiera de los microservicios uno. En las capturas se ve graficamente por el puerto de respuesta.

A nivel de logs veremos las diferentes peticiones como van llegando a cualquier consola 

    Acceso /saludo

Cada 15 segundos se verá en cada una de las consolas un log del ping, que se realiza a la raíz, dejando esta traza

    Acceso /

Ahora podemos jugar.... paremos con "CTRL + C" cualquiera de los microservicios uno. Si lanzamos peticiones antes de los 15 segundos de intervalo entre ping's, es posible que alguna petición se dirija al mcroservicio parado dando un error de acceso. Si esperamos dichos 15 segundos veremos que ninguna petición llega al microservicio parado.

Paremos un segundo y hagamos lo mismo, ahora todas las peticiones se encamian al único microservicio uno activo.

Ahora hagamos al revés, id levantando uno a uno los microservicios uno parados, y pasado 15 segundos veremos que vuelve a estar activos, pudiendo recibir peticiones de forma correcta.

Y todo desde cliente.



Nuestro código