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

1. Antes de comenzar

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 durante 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
  • Accede al panel, una interfaz de usuario de Kubernetes basada en la Web.

Requisitos

2. Configuración y requisitos

Configuración del entorno de autoaprendizaje

  1. Accede a Google Cloud Console y crea un proyecto nuevo o reutiliza uno existente. Si aún no tienes una cuenta de Gmail o de Google Workspace, debes crear una.

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • El Nombre del proyecto es el nombre visible de los participantes de este proyecto. Es una cadena de caracteres que no se utiliza en las APIs de Google. Puedes actualizarla cuando quieras.
  • El ID del proyecto es único en todos los proyectos de Google Cloud y es inmutable (no se puede cambiar después de configurarlo). La consola de Cloud genera automáticamente una cadena única. Por lo general, no importa cuál sea. En la mayoría de los codelabs, deberás hacer referencia al ID de tu proyecto (suele identificarse como PROJECT_ID). Si no te gusta el ID que se generó, podrías generar otro aleatorio. También puedes probar uno propio y ver si está disponible. No se puede cambiar después de este paso y se usa el mismo durante todo el proyecto.
  • Recuerda que hay un tercer valor, un número de proyecto, que usan algunas APIs. Obtén más información sobre estos tres valores en la documentación.
  1. A continuación, deberás habilitar la facturación en la consola de Cloud para usar las APIs o los recursos de Cloud. Ejecutar este codelab no costará mucho, tal vez nada. Para cerrar recursos y evitar que se generen cobros más allá de este instructivo, puedes borrar los recursos que creaste o borrar el proyecto. Los usuarios nuevos de Google Cloud son aptos para participar en el programa Prueba gratuita de $300.

Activar Cloud Shell

  1. En la consola de Cloud, haz clic en Activar Cloud Shell853e55310c205094.png.

55efc1aaa7a4d3ad.png

Si es la primera vez que inicias Cloud Shell, aparecerá una pantalla intermedia en la que se describirá qué es. Si apareció una pantalla intermedia, haz clic en Continuar.

9c92662c6a846a5c.png

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

9f0e51b578fecce5.png

Esta máquina virtual está cargada con todas las herramientas de desarrollo necesarias. 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 con un navegador.

Una vez que te conectes a Cloud Shell, deberías ver que te autenticaste y que el proyecto se configuró con tu ID del proyecto.

  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que tienes la autenticación:
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`
  1. En Cloud Shell, ejecuta el siguiente comando para confirmar que el comando gcloud conoce tu proyecto:
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].

3. Obtener código fuente

Después de que se inicie Cloud Shell, puedes 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

4. Ejecuta la app de forma local

  1. Asegúrate de que JAVA_HOME esté configurado en la versión correcta:
$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64
  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 1a94d5bd10bfc072.pngen la barra de herramientas de Cloud Shell y selecciona Vista previa en el puerto 8080.

6252b94905f3f7bd.png

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

9b6c29059957bd0.jpeg

5. Empaqueta la app de Java como un contenedor de Docker

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 la API de Artifact Registry para almacenar la imagen de contenedor que crearás.
$ gcloud services enable artifactregistry.googleapis.com
  1. Crea un nuevo repositorio de Docker si no existe uno. Debes crear un repositorio para poder enviarle imágenes:
$ gcloud artifacts repositories create codelabrepo     --repository-format=docker --location=us-central1 
  1. Tu imagen tendrá el siguiente formato:

{LOCATION}-docker.pkg.dev/{PROJECT-ID}/{REPOSITORY}/{IMAGE-NAME}

Por ejemplo, si creaste el repositorio en la ubicación us-central1 con el nombre codelabrepo y quieres llamar a tu imagen hello-java:v1, la imagen será la siguiente:

us-central1-docker.pkg.dev/{PROJECT-ID}/codelabrepo/hello-java:v1

  1. Usa Jib para crear la imagen del contenedor y enviarla a Artifact Registry.
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format="value(core.project)"`

$ ./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build -Dimage=us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/codelabrepo/hello-java:v1
  1. Para ver la imagen del contenedor en la consola, navega a la página Imágenes de Artifact Registry en Cloud Console. 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.
  2. (Opcional) Después de que se complete el proceso (tardará un tiempo en descargar y extraer todo), prueba la imagen con el siguiente comando, que ejecutará un contenedor de Docker como daemon en el puerto 8080 desde la imagen de contenedor que creaste recientemente. Si tienes problemas con los permisos, primero ejecuta gcloud auth configure-docker us-central1-docker.pkg.dev:
$ docker run -ti --rm -p 8080:8080 \
  us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1
  1. Nuevamente, aprovecha la función de vista previa en la Web de Cloud Shell.

6252b94905f3f7bd.png

  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.

6. Cree su clúster

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
  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.

758c7fca14f70623.png

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.

7. Implementa tu app en Kubernetes

  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=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/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.

8. Permite el tráfico externo

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 Internet pública creando un servicio LoadBalancer de Kubernetes.
$ kubectl create service loadbalancer hello-java --tcp=8080:8080

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 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 del servicio a la que se puede acceder de forma pública, 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. Ahora deberías poder acceder al servicio dirigiendo tu navegador a http://<EXTERNAL_IP>:8080.

9. Escale tu servicio

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 se aseguran de que la realidad coincida con lo que solicitaste y, de ser necesario, ejecutan acciones.

10. Implementa una actualización para tu servicio

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 Abrir editor 2109d75686c889a.pngen el menú de Cloud Shell para abrir el editor de código.
  2. Navega a src/main/java/com/example/springboot/HelloController.java y actualiza el valor de la respuesta.
package com.example.springboot;

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. Compilar y enviar la imagen actualizada debería ser mucho más rápido, ya que se aprovecha al máximo el almacenamiento en caché.
$ ./mvnw -DskipTests package com.google.cloud.tools:jib-maven-plugin:build -Dimage=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/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, debes editar la implementación de hello-java existente y cambiar la imagen de us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/hello-java:v1

hacia us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/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=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v2

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

11. Revertir

¡Uy! ¿Cometiste un error con una versión nueva de la app? Tal vez la nueva versión contenía un error y debas 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

Deberías ver la respuesta anterior cuando vuelvas a consultar http://EXTERNAL_IP:8080.

12. Felicitaciones

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

Realiza una limpieza

$ gcloud container clusters delete hello-java-cluster --zone us-central1-c

$ gcloud container images delete us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1 us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v2

Más información