Migra de la app de Java de Google App Engine a Cloud Run con Jib

1. Descripción general

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

En este instructivo, aprenderás a crear contenedores para una app de App Engine para implementarla en el servicio completamente administrado de Cloud Run con Jib. Con Jib, puedes crear imágenes de Docker, una plataforma conocida en la industria para desarrollar, enviar y ejecutar aplicaciones en contenedores.

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 tu aplicación hace un uso intensivo de los servicios en paquetes heredados de App Engine o de otras funciones de esta plataforma, recomendamos migrar desde esos servicios en paquetes o reemplazar esas funciones antes de migrar a Cloud Run. Si necesitas más tiempo para investigar tus opciones de migración o deseas seguir usando los servicios en paquetes heredados por el momento, puedes acceder a los servicios en paquetes de App Engine para Java 11/17 cuando actualices a un entorno de ejecución más reciente. Cuando tu app sea más portátil, vuelve a este codelab para aprender a aplicar las instrucciones a tu app.

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 Jib y 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. Información general

Los sistemas de plataforma como servicio (PaaS), como App Engine y Cloud Functions, brindan muchas comodidades a tu equipo y aplicación, como permitir que los administradores de sistemas y DevOps se enfoquen en compilar soluciones. Con las plataformas sin servidores, tu app puede aumentar la escala automáticamente según sea necesario, reducir la escala verticalmente a cero con la facturación de pago por uso para controlar los costos y usar una variedad de lenguajes de desarrollo comunes.

Sin embargo, la flexibilidad de los contenedores también es convincente. 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 esto se trata Cloud Run.

Aprender a usar Cloud Run no está dentro del alcance de este codelab. que se describe en la documentación de Cloud Run. El objetivo es que te familiarices con la creación de contenedores para tu app de App Engine para Cloud Run (o para 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 hacer lo siguiente:

  • Organiza tu app en contenedores con Jib
  • Migra de la configuración de App Engine
  • y, de manera opcional, definir los pasos de compilación para Cloud Build.

Esto implicará alejarse de 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 del modelo de referencia.

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 sobre cómo preparar esta app para la implementación en App Engine.

3. Implementa la app de referencia (opcional)

Lo siguiente solo es necesario si deseas 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 gcloud CLI 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 ejecute en App Engine sin problemas.

4. Crea un repositorio de Artifact Registry

Después de crear contenedores para tu app, necesitarás un lugar para enviar y almacenar las 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. Modificar archivos de la aplicación

En los casos en que tu app use en gran medida los paquetes heredados de servicios en paquete, la configuración o cualquier otra función exclusiva 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. Actualiza a Java 17

Si tu app está en Java 8, considera actualizarla a un candidato de LTS posterior, como el 11 o el 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>

De este modo, se configurará la versión del proyecto en 17, se 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. Incluye un servidor web.

Existen varias diferencias entre App Engine y Cloud Run que vale la pena tener en cuenta a la hora de pasar de una a otra. Una diferencia es que, si bien 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. Usaremos Spring Boot para proporcionarnos un servidor web y un contenedor de servlet.

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 quedará con Jetty para minimizar las diferencias en el comportamiento predeterminado después de la migración. También podemos configurar la versión de Jetty para que coincida con la que proporciona App Engine desde el primer momento.

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

3. Configuración de Spring Boot

Si bien Spring Boot podrá volver a usar tus servlets sin modificaciones, requerirá cierta configuración para la visibilidad.

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 hará que estén disponibles según lo previsto.

4. Empaqueta la app como un archivo JAR

Si bien es posible crear contenedores para tu app con Jib a partir de una guerra, resulta más fácil si empaquetas la app como un JAR ejecutable. Esto no requerirá mucha configuración, en especial para proyectos que usan Maven como herramienta de compilación, ya que el empaquetado en JAR es el comportamiento predeterminado.

Quita la etiqueta packaging del archivo pom.xml:

<packaging>war</packaging>

A continuación, agrega 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. Migración 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. Ciertas funciones que App Engine ofrece de inmediato, como los servicios Cron y Lista de tareas en cola, se deben volver a crear de forma manual y se tratarán con más detalle en módulos posteriores.

La app de ejemplo no utiliza los paquetes heredados de servicios, pero los usuarios cuyas apps sí 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. Alojar la aplicación en contenedores

En este punto, puedes implementar de forma manual 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. Abordaremos las implementaciones de origen con mayor detalle en próximos módulos.

Como alternativa, si necesitas más control sobre la forma en que se implementa tu app, puedes lograrlo definiendo un archivo cloudbuild.yaml que establezca de manera explícita los pasos de compilación deseados:

1. Define un archivo cloudbuild.yaml

Crea el siguiente archivo cloudbuild.yaml en el mismo nivel que pom.xml:

steps:
  # Test your build
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: ["test"]
  # Build with Jib
  - name: maven:eclipse-temurin
    entrypoint: mvn
    args: [ "compile", "com.google.cloud.tools:jib-maven-plugin:3.2.1:build", "-Dimage=northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib"]
  # Deploy to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: gcloud
    args: [ 'run', 'deploy', 'visitors', '--image', 'northamerica-northeast1-docker.pkg.dev/PROJECT_ID/migration/visitors:jib', '--region', 'northamerica-northeast1', '--allow-unauthenticated']

Una vez que le indicamos a Cloud Build que siga estos pasos, sucederá lo siguiente:

  1. Ejecuta las pruebas con ./mvnw test
  2. Compila, envía y etiqueta tu imagen en Artifact Registry con Jib
  3. Implementa tu imagen en Cloud Run con gcloud run deploy

Ten en cuenta que ‘visitors' se proporciona a Cloud Run como el nombre de servicio deseado. La marca –allow-unauthenticated permite a los usuarios visitar la aplicación web sin requerir autenticación. Asegúrate de reemplazar PROJECT_ID por el ID de tu proyecto en el archivo cloudbuild.yaml.

A continuación, agrega las siguientes vinculaciones de políticas de IAM para permitir que la cuenta de servicio de Cloud Build acceda a Artifact Registry:

export PROJECT_ID=$(gcloud config list --format 'value(core.project)')
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)" )

gcloud projects add-iam-policy-binding $PROJECT_ID \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role=roles/run.admin \
--project=$PROJECT_ID
gcloud iam service-accounts add-iam-policy-binding $PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
--role roles/iam.serviceAccountUser --project=$PROJECT_ID

2. Ejecuta el proceso de compilación

Ahora que informaste a Cloud Build sobre los pasos de compilación deseados, estás listo para una implementación con un clic.

Ejecuta el siguiente comando:

gcloud builds submit

Una vez que el proceso finalice, tu imagen de contenedor se compiló, se almacenó en Artifact Registry y se implementó en Cloud Run.

Al final de este codelab, tu app debería verse igual a la de java17-and-cloud-run/finish.

Lo logró. Migraste correctamente una aplicación de App Engine para Java 8 a Java 17 y Cloud Run, y ahora comprendes mejor el trabajo que implica el cambio y la elección entre opciones de hosting.

6. Resumen/limpieza

¡Felicitaciones! Actualizaste, almacenaste en contenedores, migraste tu app y concluye este instructivo.

A partir de aquí, el siguiente paso es aprender más sobre las funciones de seguridad de CI/CD y de la cadena de suministro de software que están a tu alcance ahora que puedes implementar 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é todo listo para pasar al siguiente codelab, puedes volver a habilitarlo. Si bien las apps de App Engine están inhabilitadas, no recibirán tráfico que genere cargos. Sin embargo, el uso de Datastore puede ser facturable si supera su cuota gratuita, así que borra lo suficiente para no exceder 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 Cloud

Videos

Licencia

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