Implementar una app de Java de Spring Boot en Kubernetes en Google Kubernetes Engine

Kubernetes es un proyecto de código abierto que se puede ejecutar en muchos entornos distintos, desde laptops hasta clústeres de múltiples nodos de alta disponibilidad, desde nubes públicas hasta implementaciones locales y desde instancias de máquinas virtuales (VM) hasta equipos físicos.

En este codelab, implementarás una app web simple de Spring Boot Java en Kubernetes en GKE, con el objetivo de que ejecutes tu app web como una app replicada en Kubernetes. Tomará el código que desarrolla en su máquina, lo convierte en una imagen de contenedor de Docker y la ejecuta en GKE.

Usará GKE, un servicio de Kubernetes completamente administrado en Google Cloud que le permitirá concentrarse más en experimentar Kubernetes, en lugar de configurar la infraestructura subyacente.

Si le interesa ejecutar Kubernetes en su máquina local, como una laptop de desarrollo, consulte Minikube, que ofrece una configuración sencilla de un clúster de Kubernetes de un solo nodo para fines de desarrollo y pruebas. Si lo deseas, puedes usar Minikube para realizar el codelab.

En el codelab, se usará el código de muestra de la guía Cómo compilar una app con Spring Boot.

Requisitos previos

  • Estar familiarizado con el lenguaje y las herramientas de programación de Java
  • Conocimientos de editores de texto estándares de Linux, como Vim, Emacs y nano

Actividades

  • Empaqueta una app simple de Java como un contenedor de Docker.
  • Crea un clúster de Kubernetes en GKE.
  • Implementar tu app de Java en Kubernetes en GKE
  • Escala verticalmente tu servicio y lanza una actualización.
  • Acceder al Panel de control, una interfaz de usuario basada en la Web de Kubernetes

Requisitos

Configuración del entorno a su propio ritmo

  1. Accede a Cloud Console y crea un proyecto nuevo o reutiliza uno existente. (Si no tienes una cuenta de Gmail o G Suite, debes crear una).

Recuerde el ID de proyecto, un nombre único en todos los proyectos de Google Cloud (el nombre anterior ya se encuentra en uso y no lo podrá usar). Se mencionará más adelante en este codelab como PROJECT_ID.

  1. A continuación, debes habilitar la facturación en Cloud Console para usar los recursos de Google Cloud.

Ejecutar este codelab no debería costar más que unos pocos dólares, pero podría ser más si decides usar más recursos o si los dejas en ejecución.

Los usuarios nuevos de Google Cloud son aptos para obtener una prueba gratuita de USD 300.

Activar Cloud Shell

  1. En Cloud Console, haz clic en Activar Cloud Shell .

Si nunca ha iniciado Cloud Shell, aparecerá una pantalla intermedia (debajo de la mitad inferior de la página) que describe qué es. Si ese es el caso, haz clic en Continuar (y no volverás a verlo). Así es como se ve la pantalla única:

El aprovisionamiento y la conexión a Cloud Shell solo tomará unos minutos.

Esta máquina virtual está cargada con todas las herramientas de desarrollo que necesitarás. Ofrece un directorio principal persistente de 5 GB y se ejecuta en Google Cloud, lo que permite mejorar considerablemente el rendimiento de la red y la autenticación. Gran parte de tu trabajo en este codelab, si no todo, se puede hacer simplemente con un navegador o tu Chromebook.

Una vez conectado a Cloud Shell, debería ver que ya se autenticó y que el proyecto ya se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que está autenticado:
gcloud auth list

Resultado del comando

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
gcloud config list project

Resultado del comando

[core]
project = <PROJECT_ID>

De lo contrario, puede configurarlo con este comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

Después de que se inicie Cloud Shell, podrá usar la línea de comandos para clonar el código fuente de ejemplo en el directorio principal.

$ git clone https://github.com/spring-guides/gs-spring-boot.git
$ cd gs-spring-boot/complete
  1. Puedes iniciar la app de Spring Boot normalmente con el complemento de Spring Boot.
$ ./mvnw -DskipTests spring-boot:run
  1. Cuando se inicie la app, haga clic en Vista previa en la Web en la barra de herramientas de Cloud Shell y seleccione Vista previa en el puerto 8080.

En su navegador, se abrirá una pestaña y se conectará al servidor que acaba de iniciar.

A continuación, debes preparar tu app para que se ejecute en Kubernetes. El primer paso es definir el contenedor y su contenido.

  1. Crear el JAR que se puede implementar para la app
$ ./mvnw -DskipTests package
  1. Habilita Container Registry para almacenar la imagen de contenedor que crearás.
$ gcloud services enable containerregistry.googleapis.com
  1. Use Jib para crear la imagen de contenedor y enviarla a Container Registry.
$ ./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. Si todo sale bien, deberías poder ver la imagen de contenedor en la consola. Para ello, navega a Container Registry > Imágenes. Ahora tienes una imagen de Docker disponible para todo el proyecto, a la que Kubernetes puede acceder y organizar en unos minutos.
  1. Cuando se complete ese proceso (la descarga y extracción tardará un tiempo), puedes probar de forma local la imagen con el siguiente comando, que ejecutará un contenedor de Docker como un daemon en el puerto 8080 desde la imagen de contenedor recién creada:
$ docker run -ti --rm -p 8080:8080 \
  gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. Nuevamente, aproveche la función de vista previa web de Cloud Shell.

  1. Debería ver la página predeterminada en una pestaña nueva. Después de verificar que la app se ejecuta de forma local en un contenedor de Docker, puedes presionar Control+C para detener el contenedor.

Ya puedes crear un clúster de GKE. Un clúster consiste en un servidor de la API de Kubernetes administrado por Google y un conjunto de nodos trabajadores. Los nodos trabajadores son VM de Compute Engine.

  1. Primero, asegúrese de que estén habilitadas las funciones relacionadas de la API.
$ gcloud services enable compute.googleapis.com container.googleapis.com
Operation "operations/..." finished successfully
  1. Crea un clúster con dos nodos n1-standard-1 (el proceso tardará unos minutos en completarse).
$ gcloud container clusters create hello-java-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

Cuando el proceso se complete, debería ver que se creó el clúster.

Creating cluster hello-java-cluster...done.
Created [https://container.googleapis.com/v1/projects/...].
kubeconfig entry generated for hello-dotnet-cluster.
NAME                  ZONE            MASTER_VERSION  
hello-java-cluster  us-central1-c  ...

Ahora debería tener un clúster de Kubernetes completamente funcional con la tecnología de GKE.

Es momento de implementar tu app alojada en contenedores en el clúster de Kubernetes. A partir de ahora, usarás la línea de comandos de kubectl (que ya está configurada en tu entorno de Cloud Shell). El resto del codelab requiere que la versión del cliente y del servidor de Kubernetes sean 1.2 o superiores. kubectl version te mostrará la versión actual del comando.

  1. Una implementación de Kubernetes puede crear, administrar y escalar varias instancias de tu app mediante la imagen de contenedor que creaste. Implementa una instancia de tu app en Kubernetes con el comando kubectl run.
$ kubectl create deployment hello-java \
  --image=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. Para ver la implementación que creó, simplemente ejecute el siguiente comando:
$ kubectl get deployments
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   1         1         1            1           37s
  1. Para ver las instancias de la app creadas por la implementación, ejecuta el siguiente comando:
$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
hello-java-714049816-ztzrb   1/1       Running   0          57s

En este punto, ya debería tener su contenedor ejecutándose bajo el control de Kubernetes, pero debe hacer que sea accesible para todo el mundo.

De forma predeterminada, solo se puede acceder al Pod mediante su IP interna dentro del clúster. Para que el contenedor hello-java sea accesible desde fuera de la red virtual de Kubernetes, debe exponer el Pod como un servicio de Kubernetes.

  1. En Cloud Shell, puede exponer el Pod a la Internet pública con el comando kubectl expose combinado con la marca --type=LoadBalancer. La marca es necesaria para crear una IP accesible de forma externa.
$ kubectl create service loadbalancer hello-java --tcp=8080:8080

La marca utilizada en el comando especifica que usarás el balanceador de cargas que te proporciona la infraestructura subyacente. Tenga en cuenta que se expone directamente la implementación, no el Pod. Eso hará que el servicio resultante cargue el tráfico de carga en todos los Pods administrados por la implementación (en este caso, solo se agregará un Pod, pero luego agregará más réplicas).

La instancia principal de Kubernetes crea el balanceador de cargas y las reglas de reenvío de Compute Engine relacionadas, los grupos de destino y las reglas de firewall para que el servicio se vuelva completamente accesible desde el exterior de Google Cloud.

  1. Para encontrar la dirección IP de acceso público del servicio, simplemente solicite kubectl a fin de enumerar todos los servicios del clúster.
$ kubectl get services
NAME         CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
Hello-java   10.3.253.62    aaa.bbb.ccc.ddd  8080/TCP    1m
kubernetes   10.3.240.1     <none>           443/TCP    5m
  1. Tenga en cuenta que hay dos direcciones IP enumeradas para su servicio, y ambas entregan contenido al puerto 8080. Una es la dirección IP interna que solo es visible dentro de su nube privada virtual. La otra es la dirección IP externa con balanceo de cargas. En el ejemplo, la dirección IP externa es aaa.bbb.ccc.ddd. Ahora debería poder acceder al servicio apuntando su navegador a http://<EXTERNAL_IP>:8080.

Una de las características poderosas que ofrece Kubernetes es lo fácil que es escalar tu app. Supongamos que, de repente, necesitas más capacidad para la app. Puedes indicarle al controlador de replicación que administre una nueva cantidad de réplicas para las instancias de la app.

$ kubectl scale deployment hello-java --replicas=3
deployment "hello-java" scaled

$ kubectl get deployment
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   3         3         3            3           22m

Observa el enfoque declarativo. En vez de iniciar o detener nuevas instancias, usted declara cuántas instancias deberían estar en ejecución constantemente. Los bucles de conciliación de Kubernetes simplemente se aseguran de que la realidad coincida con lo que solicitó y, de ser necesario, realizan acciones.

En algún momento, la app que implementaste en producción requerirá correcciones de errores o funciones adicionales. Kubernetes puede ayudarlo a implementar una versión nueva en producción sin afectar a los usuarios.

  1. En el menú de Cloud Shell, haz clic en Abrir editor para abrir el editor de código.
  2. Navega a src/main/java/hello/HelloController.java y actualiza el valor de la respuesta.
package hello;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {    
    @RequestMapping("/")
    public String index() {
        return "Greetings from Google Kubernetes Engine!";
    }
}
  1. Usa Jib para compilar y enviar una versión nueva de la imagen de contenedor.
$ ./mvnw -DskipTests package \
  com.google.cloud.tools:jib-maven-plugin:build \
  -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2

Está todo listo para que Kubernetes actualice sin problemas su controlador de replicación a la nueva versión de la aplicación.

  1. A fin de cambiar la etiqueta de la imagen de tu contenedor en ejecución, debes editar la implementación hello-java existente y cambiar la imagen de gcr.io/PROJECT_ID/hello-java:v1 a gcr.io/PROJECT_ID/hello-java:v2.
  1. Puedes usar el comando kubectl set image para pedirle a Kubernetes que implemente la versión nueva de la app en todo el clúster, una instancia a la vez, con actualizaciones progresivas.
$ kubectl set image deployment/hello-java \
  hello-java=gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v2

deployment "hello-java" image updated
  1. Vuelve a consultar http://EXTERNAL_IP:8080 para ver que devuelve la nueva respuesta.

¡Uy! ¿Cometió un error con una nueva versión de la aplicación? Es posible que la versión nueva contenga un error y deba revertirla rápidamente. Con Kubernetes, puede revertir el estado anterior con facilidad. Revierte la app con el siguiente comando:

$ kubectl rollout undo deployment/hello-java

Aprendió a compilar e implementar una nueva aplicación web basada en Java en Kubernetes en GKE.

Más información