Migra de una app de Java de Google App Engine a Cloud Run con paquetes de compilación

1. Descripción general

Esta serie de codelabs (instructivos prácticos y de autoaprendizaje) tiene como objetivo ayudar a los desarrolladores de Java de Google App Engine (estándar) a modernizar sus apps con una serie de migraciones. Si sigues estos pasos, puedes actualizar tu app para que sea más portátil y decidir alojarla en contenedores para Cloud Run, el servicio de alojamiento de contenedores de Google Cloud en App Engine y otros servicios de alojamiento de contenedores.

En este instructivo, aprenderás a organizar una app de App Engine en contenedores para implementarla en el servicio completamente administrado de Cloud Run con Buildpacks. Los paquetes de compilación son un proyecto de CNCF que te permiten llevar tu app directamente del código fuente a imágenes altamente portátiles que se pueden ejecutar en cualquier nube.

Además de enseñarte los pasos necesarios para pasar de App Engine a Cloud Run, también aprenderás a actualizar una app de App Engine de Java 8 a Java 17.

Si la aplicación que deseas migrar hace un uso intensivo de los servicios en paquetes heredados de App Engine o de otras funciones específicas de App Engine, la guía Cómo acceder a los servicios empaquetados de App Engine para Java 11/17 puede ser más adecuada que este codelab.

En un próximo lab,

  • Usa Cloud Shell
  • Habilita las APIs de Cloud Run, Artifact Registry y Cloud Build
  • Aloja tu app en contenedores con Buildpacks en Cloud Build
  • Implementa tus imágenes de contenedor en Cloud Run

Requisitos

Encuesta

¿Cómo usarás este instructivo?

Ler Leer y completar los ejercicios

¿Cómo calificarías tu experiencia con Java?

Principiante Intermedio Avanzado

¿Cómo calificarías tu experiencia en el uso de los servicios de Google Cloud?

Principiante Intermedio Avanzado

2. Segundo plano

Los sistemas PaaS, como App Engine y Cloud Functions, ofrecen muchos beneficios para tu equipo y aplicación, como permitir que los administradores de sistemas y los desarrolladores se enfoquen en la compilación de soluciones. Con las plataformas sin servidores, tu app puede realizar un ajuste de escala automático según sea necesario, reducir la escala verticalmente a cero con la facturación de pago por uso que ayuda a controlar los costos, y usar una variedad de lenguajes de desarrollo comunes.

Sin embargo, la flexibilidad de los contenedores también es atractiva. Con la capacidad de elegir cualquier lenguaje, objeto binario o biblioteca, los contenedores te ofrecen lo mejor de ambos mundos: la conveniencia de la computación sin servidores y la flexibilidad de los contenedores. De eso se trata Google Cloud Run.

Aprender a usar Cloud Run no está dentro del alcance de este codelab. Consulta la documentación de Cloud Run. El objetivo aquí es que aprendas a alojar en contenedores tu app de App Engine para Cloud Run (u otros servicios alojados en contenedores). Antes de seguir adelante, debes tener en cuenta algunos aspectos, principalmente, que la experiencia del usuario será un poco diferente.

En este codelab, aprenderás a compilar e implementar contenedores. Aprenderás a crear contenedores para tu app con Buildpacks, migrar desde la configuración de App Engine y definir pasos de compilación para Cloud Build. Esto implicará dejar de usar ciertas funciones específicas de App Engine. Si prefieres no seguir esta ruta, puedes actualizar a un entorno de ejecución de Java 11/17 mientras mantienes tus apps en App Engine.

3. Configurar/trabajo previo

1. Configura el proyecto

En este instructivo, usarás una app de ejemplo del repositorio appengine-java-migration-samples en un proyecto nuevo. Asegúrate de que el proyecto tenga una cuenta de facturación activa.

Si piensas trasladar una app existente de App Engine a Cloud Run, puedes usarla para continuar.

Ejecuta el siguiente comando para habilitar las APIs necesarias para tu proyecto:

gcloud services enable artifactregistry.googleapis.com cloudbuild.googleapis.com run.googleapis.com

2. Obtén la app de ejemplo del modelo de referencia

Clona la app de ejemplo en tu propia máquina o en Cloud Shell y, luego, navega a la carpeta baseline.

La muestra es una aplicación de Datastore basada en servlet de Java 8 diseñada para implementarse en App Engine. Sigue las instrucciones del archivo README para preparar esta app para la implementación de App Engine.

3. Implementa la app de modelo de referencia (opcional)

La siguiente información solo es necesaria si quieres confirmar que la app funciona en App Engine antes de migrar a Cloud Run.

Consulta los pasos en README.md:

  1. Instala la CLI de gcloud o vuelve a familiarizarte con ella
  2. Inicializa la CLI de gcloud para tu proyecto con gcloud init
  3. Crea el proyecto de App Engine con gcloud app create
  4. Implementa la app de ejemplo en App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. Confirma que la app se ejecuta en App Engine sin problemas

4. Crea un repositorio de Artifact Registry

Después de crear un contenedor para tu app, necesitarás un lugar para enviar y almacenar tus imágenes. La forma recomendada de hacerlo en Google Cloud es con Artifact Registry.

Crea el repositorio llamado migration con gcloud de la siguiente manera:

gcloud artifacts repositories create migration --repository-format=docker \
--description="Docker repository for the migrated app" \
--location="northamerica-northeast1"

Ten en cuenta que este repositorio usa el tipo de formato docker, pero hay varios tipos de repositorios disponibles.

En este punto, tienes tu app de referencia de App Engine y tu proyecto de Google Cloud está preparado para migrarla a Cloud Run.

4. Modifica los archivos de la aplicación

En los casos en que tu app haga un uso intensivo de los paquetes heredados de servicios en paquete, la configuración o de otras funciones exclusivas de App Engine, te recomendamos que continúes accediendo a esos servicios mientras actualizas al nuevo entorno de ejecución. En este codelab, se muestra una ruta de migración para aplicaciones que ya usan servicios independientes o que se pueden refactorizar para hacerlo.

1. Actualización a Java 17

Si tu app está en Java 8, considera actualizar a una versión candidata de LTS posterior, como 11 o 17, para mantenerte al día con las actualizaciones de seguridad y obtener acceso a nuevas funciones del lenguaje.

Primero, actualiza las propiedades de tu pom.xml para incluir lo siguiente:

<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

Esto establecerá la versión del proyecto en 17, le informará al complemento del compilador que deseas acceder a las funciones del lenguaje Java 17 y que deseas que las clases compiladas sean compatibles con la JVM de Java 17.

2. Cómo incluir un servidor web

Existen varias diferencias entre App Engine y Cloud Run que vale la pena tener en cuenta cuando se cambia entre ellos. Una diferencia es que, mientras que el entorno de ejecución de Java 8 de App Engine proporcionaba y administraba un servidor Jetty para las apps que alojaba, Cloud Run no lo hace. Usaremos Spring Boot para proporcionarnos un servidor web y un contenedor de servlets.

Agrega las siguientes dependencias:

<dependencies>
<!-- ... -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
       <version>2.6.6</version>
       <exclusions>
           <!-- Exclude the Tomcat dependency -->
           <exclusion>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-tomcat</artifactId>
           </exclusion>
       </exclusions>
   </dependency>
   <!-- Use Jetty instead -->
   <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-jetty</artifactId>
       <version>2.6.6</version>
   </dependency>
<!-- ... -->
</dependencies>

Spring Boot incorpora un servidor Tomcat de forma predeterminada, pero este ejemplo excluirá ese artefacto y se mantendrá con Jetty para minimizar las diferencias en el comportamiento predeterminado después de la migración.

3. Configuración de Spring Boot

Si bien Spring Boot podrá volver a usar tus servlets sin modificaciones, requerirá cierta configuración para asegurarse de que sean detectables.

Crea la siguiente clase MigratedServletApplication.java en el paquete com.example.appengine:

package com.example.appengine;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@ServletComponentScan
@SpringBootApplication
@EnableAutoConfiguration
public class MigratedServletApplication {
    public static void main(String[] args) {
        SpringApplication.run(MigratedServletApplication.class, args);
    }
}

Ten en cuenta que esto incluye la anotación @ServletComponentScan, que buscará (en el paquete actual de forma predeterminada) cualquier @WebServlets y los pondrá a disposición como se espera.

4. Configuración de compilación

A continuación, quita la configuración para empaquetar nuestra aplicación como un WAR. Esto no requerirá mucha configuración, en particular para los proyectos que usan Maven como herramienta de compilación, ya que el empaquetado de jar es el comportamiento predeterminado.

Quita la etiqueta packaging del archivo pom.xml:

<packaging>war</packaging>

A continuación, agrega el spring-boot-maven-plugin:

<plugins>
<!-- ... -->
  <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.6.6</version>
  </plugin>
<!-- ... -->
</plugins>

5. Cómo migrar de la configuración, los servicios y las dependencias de App Engine

Como se mencionó al comienzo del codelab, Cloud Run y App Engine están diseñados para ofrecer diferentes experiencias del usuario. Algunas funciones que App Engine ofrece de forma predeterminada, como los servicios de Cron y Task Queue, deben volver a crearse de forma manual y se analizarán con más detalle en módulos posteriores.

La app de ejemplo no usa servicios agrupados en paquetes heredados, pero los usuarios cuyas apps sí lo hacen pueden consultar las siguientes guías:

Como implementarás en Cloud Run a partir de ahora, puedes quitar appengine-maven-plugin:

<plugin>
 <groupId>com.google.cloud.tools</groupId>
 <artifactId>appengine-maven-plugin</artifactId>
 <version>2.4.1</version>
 <configuration>
   <!-- can be set w/ -DprojectId=myProjectId on command line -->
   <projectId>${app.projectId}</projectId>
   <!-- set the GAE version or use "GCLOUD_CONFIG" for an autogenerated GAE version -->
   <version>GCLOUD_CONFIG</version>
 </configuration>
</plugin>

5. Cómo organizar en contenedores y, luego, implementar la aplicación

En este punto, ya puedes implementar tu app en Cloud Run directamente desde tu código fuente. Esta es una excelente opción que usa Cloud Build en segundo plano para proporcionar una experiencia de implementación sin intervención. Ten en cuenta que, para usar esta función, necesitarás una cuenta con al menos uno de los siguientes permisos y que hayas seguido estos pasos de configuración del entorno, o bien usa Cloud Shell:

Con esos requisitos previos, simplemente ejecuta lo siguiente desde tu directorio de origen:

gcloud run deploy SERVICE --source .

Se le solicitarán algunas tareas durante el comando run deploy, como en el siguiente ejemplo:

  • Proporciona la ubicación del código fuente
  • Proporciona el nombre del servicio
  • Habilita la API de Cloud Run
  • Cómo seleccionar tu región

Después de responder a esas solicitudes, comienza el proceso de compilación e implementación, durante el cual Cloud Build hará lo siguiente:

  • se comprime y guarda la fuente en un bucket de Cloud Storage.
  • usa los paquetes de compilación de la Cloud Native Computing Foundation en segundo plano para compilar tu imagen.
  • Crea un registro para almacenar la imagen de contenedor resultante (si aún no está presente).
  • Además, crea un servicio de Cloud Run para alojar tu app (si aún no está presente).

Cuando se complete la compilación y la implementación, deberías recibir un mensaje en el que se explique que hay una revisión nueva activa y entregando el 100% del tráfico.

6. Resumen/limpieza

¡Felicitaciones! Actualizaste, alojaste en contenedores, migraste y actualizaste tu app, lo que concluye con este instructivo.

A partir de este punto, el siguiente paso es obtener más información sobre las funciones de seguridad de CI/CD y de la cadena de suministro de software que están al alcance ahora que puedes implementarlas con Cloud Build:

Opcional: Limpia o inhabilita el servicio

Si implementaste la app de ejemplo en App Engine durante este instructivo, recuerda inhabilitar la app para evitar incurrir en cargos. Cuando estés listo para pasar al siguiente codelab, puedes volver a habilitarla. Aunque las apps de App Engine estén inhabilitadas, no recibirán tráfico que genere cargos. Sin embargo, el uso de Datastore puede facturarse si supera su cuota gratuita, así que borra lo suficiente para que quede dentro de ese límite.

Por otro lado, si no vas a continuar con las migraciones y deseas borrar todo por completo, puedes borrar tu servicio o cerrar tu proyecto por completo.

7. Recursos adicionales

Problemas o comentarios de los Codelabs del módulo de migración de App Engine

Si encuentras algún problema con este Codelab, primero busca el problema antes de enviarlo. Vínculos para buscar y crear problemas nuevos:

Recursos de migración

Recursos en línea

A continuación, hay recursos en línea que pueden ser relevantes para este tutorial:

App Engine

Otra información de la nube

Videos

Licencia

Este trabajo cuenta con una licencia Atribución 2.0 Genérica de Creative Commons.