Implementa 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 multinodo 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. Convertirás el código que desarrolles en tu máquina en una imagen de contenedor de Docker y la ejecutarás en GKE.

Usarás GKE, un servicio de Kubernetes completamente administrado en Google Cloud, para que puedas enfocarte más en experimentar con Kubernetes, en lugar de configurar la infraestructura subyacente.

Si te interesa ejecutar Kubernetes en tu máquina local, como una laptop de desarrollo, consulta 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 este codelab, se usará el código de ejemplo de la guía sobre cómo compilar una app con Spring Boot.

Requisitos previos

  • Tener conocimientos del lenguaje de programación y las herramientas de Java
  • Conocimiento de editores de texto estándares de Linux, como Vim, Emacs y nano

Actividades

  • Empaquetarás una app simple de Java como un contenedor de Docker.
  • Crea tu clúster de Kubernetes en GKE.
  • Implementa tu app de Java en Kubernetes en GKE.
  • Cómo escalar tu servicio verticalmente e implementar una actualización
  • Panel de acceso, una interfaz de usuario de Kubernetes basada en la Web

Requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Cloud Console y crea un proyecto nuevo o reutiliza uno existente. (Si todavía no tienes una cuenta de Gmail o de 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, deberás habilitar la facturación en la consola de Cloud para usar los recursos de Google Cloud.

Ejecutar este codelab debería costar solo unos pocos dólares, pero su costo podría aumentar 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 la consola de Cloud, 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, puedes configurarlo con el siguiente comando:

gcloud config set project <PROJECT_ID>

Resultado del comando

Updated property [core/project].

Después de que se inicie Cloud Shell, podrás 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. Después de que se inicie la app, haz clic en Vista previa en la Web en la barra de herramientas de Cloud Shell y selecciona Vista previa en el puerto 8080.

En tu navegador, se abrirá una pestaña y se conectará al servidor que acabas 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. Crea el archivo JAR implementable 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. Usa Jib para crear la imagen del 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 que puede organizar, como verás en unos minutos.
  1. Una vez que se complete este proceso (llevará un tiempo descargar y extraer todo), puedes probar la imagen de forma local con el siguiente comando, que ejecutará un contenedor de Docker como daemon en el puerto 8080 desde la imagen de contenedor que creaste recientemente:
$ docker run -ti --rm -p 8080:8080 \
  gcr.io/$GOOGLE_CLOUD_PROJECT/hello-java:v1
  1. Nuevamente, aprovecha la función de vista previa en la Web de Cloud Shell.

  1. Deberías 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 detener el contenedor en ejecución presionando Control+C.

Ya puedes crear tu clúster de GKE. Un clúster consiste en un servidor de API de Kubernetes que administra Google y un conjunto de nodos trabajadores. Los nodos trabajadores son VMs de Compute Engine.

  1. Primero, asegúrate de que estén habilitadas las funciones de la API relacionadas.
$ gcloud services enable compute.googleapis.com container.googleapis.com
Operation "operations/..." finished successfully
  1. Crea un clúster con dos nodos n1-standard-1 (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ías tener un clúster de Kubernetes completamente funcional con la tecnología de GKE.

Llegó la hora de implementar tu app en contenedores en el clúster de Kubernetes. A partir de ahora, usarás la línea de comandos kubectl (que ya está configurada en tu entorno de Cloud Shell). Para el resto del codelab, se requiere que la versión del cliente y del servidor de Kubernetes sea la 1.2 o una posterior. 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 con 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 creaste, simplemente ejecuta 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, deberías tener tu contenedor ejecutándose bajo el control de Kubernetes, pero aún tienes que hacerlo accesible para otras personas.

Según la configuración predeterminada, el Pod solo es accesible a través de su IP interna dentro del clúster. Para hacer accesible el contenedor hello-java desde fuera de la red virtual de Kubernetes, tienes que exponer el Pod como un servicio de Kubernetes.

  1. En Cloud Shell, puedes exponer el Pod a la Internet pública con el comando kubectl expose combinado con la marca --type=LoadBalancer. Esta 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 proporcionado por la infraestructura subyacente. Ten en cuenta que expones directamente la implementación, no el Pod. Esto hará que el servicio resultante balancee la carga de tráfico en todos los Pods administrados por la implementación (en este caso, solo un Pod, pero luego podrás agregar más réplicas).

La instancia principal de Kubernetes crea el balanceador de cargas y las reglas de reenvío, los grupos de destino y las reglas de firewall de Compute Engine relacionados para que se pueda acceder al servicio completamente desde fuera de Google Cloud.

  1. Para encontrar la dirección IP accesible de forma pública del servicio, solo debes solicitar que kubectl muestre 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. Observa que se muestran dos direcciones IP para tu servicio, y ambas entregan contenido al puerto 8080. Una es la dirección IP interna que solo es visible dentro de tu 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ías poder acceder al servicio dirigiendo tu navegador a http://<EXTERNAL_IP>:8080.

Una de las características avanzadas que ofrece Kubernetes es la gran facilidad para escalar tu app. Supongamos que, de repente, necesitas más capacidad para tu app. Simplemente puedes indicarle al controlador de replicación que administre una nueva cantidad de réplicas para las instancias de tu 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, debes declarar cuántas instancias deberían estar en ejecución constantemente. Los bucles de conciliación de Kubernetes simplemente garantizan que la realidad coincida con lo que solicitaste y, de ser necesario, ejecutan acciones.

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

  1. Haz clic en Iniciar editor en el menú de Cloud Shell 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 nueva versión 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

Ya está todo listo para que Kubernetes actualice sin problemas tu controlador de replicación a la nueva versión de la app.

  1. Para cambiar la etiqueta de la imagen de tu contenedor en ejecución, deberás editar la implementación de 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 solicitarle a Kubernetes que implemente la versión nueva de tu 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 respuesta nueva.

¡Uy! ¿Cometiste un error con una versión nueva de la app? Quizás la nueva versión contenía un error y necesitas revertirla rápidamente. Con Kubernetes, puedes revertir fácilmente al estado anterior. Ejecuta el siguiente comando para revertir la app:

$ kubectl rollout undo deployment/hello-java

Aprendiste a compilar e implementar una nueva app web basada en Java en Kubernetes en GKE.

Más información