Como migrar do app Java do Google App Engine para o Cloud Run com Jib

1. Visão geral

Esta série de codelabs (tutoriais práticos e autoguiados) tem como objetivo ajudar os desenvolvedores Java do Google App Engine (Padrão) a modernizar os aplicativos por meio de uma série de migrações. Seguindo estas etapas, você pode atualizar seu app para que ele seja mais portátil e decidir colocá-lo em um contêiner para o Cloud Run, o serviço irmã de hospedagem de contêiner do Google Cloud no App Engine e outros serviços de hospedagem de contêiner.

Neste tutorial, você aprende a colocar um app do App Engine em contêiner para implantá-lo no serviço totalmente gerenciado do Cloud Run usando o Jib. Com o Jib, é possível criar imagens do Docker, uma plataforma conhecida no setor para desenvolver, enviar e executar aplicativos em contêineres.

Além de ensinar as etapas necessárias para migrar do App Engine para o Cloud Run, você também vai aprender a fazer upgrade de um app do Java 8 do App Engine para o Java 17.

Se o aplicativo usa muitos serviços agrupados legados do App Engine ou outros recursos do App Engine, recomendamos migrar esses serviços ou substituir esses recursos antes de migrar para o Cloud Run. Se você precisar de mais tempo para investigar as opções de migração ou quiser continuar usando os serviços em pacote legados por enquanto, continue a acessar os serviços incluídos no App Engine para Java 11/17 ao fazer upgrade para um ambiente de execução mais recente. Quando o app estiver mais portátil, volte a este codelab para aprender a aplicar as instruções.

Você vai aprender a

  • Usar o Cloud Shell
  • Ative as APIs Cloud Run, Artifact Registry e Cloud Build.
  • Conteinerizar seu app usando o Jib e o Cloud Build
  • Implantar imagens de contêiner no Cloud Run

O que é necessário

Pesquisa

Como você vai usar este tutorial?

Apenas leitura Leitura e exercícios

Como você classificaria sua experiência com Java?

Iniciante Intermediário Proficiente

Como você classificaria sua experiência de uso dos serviços do Google Cloud?

Iniciante Intermediário Proficiente

2. Contexto

Os sistemas PaaS (Plataforma como serviço), como o App Engine e o Cloud Functions, oferecem muitas conveniências para sua equipe e aplicativo, como permitir que SysAdmins e Devops se concentrem na criação de soluções. Com plataformas sem servidor, seu app pode ser escalonado automaticamente de acordo com a necessidade, reduzir o tamanho zero para pagar com pagamento por uso, ajudar a controlar custos e usar uma variedade de linguagens de desenvolvimento comuns.

No entanto, a flexibilidade dos contêineres também é atraente. Com a capacidade de escolher qualquer linguagem, qualquer biblioteca e qualquer binário, os contêineres oferecem o melhor dos dois mundos: a conveniência de usar um ambiente sem servidor e a flexibilidade dos contêineres. É disso que se trata o Cloud Run.

O aprendizado deste codelab não está no escopo deste codelab coberto pela documentação do Cloud Run. O objetivo é que você se familiarize com a conteinerização do seu aplicativo do App Engine para o Cloud Run ou de outros serviços hospedados em contêineres. Há algumas coisas que você deve saber antes de avançar, principalmente que a experiência do usuário será um pouco diferente.

Neste codelab, você vai aprender a criar e implantar contêineres. Você vai aprender a:

  • Conteinerizar seu app com o Jib
  • Migrar da configuração do App Engine
  • e, opcionalmente, definir as etapas de build para o Cloud Build.

Isso envolve a desativação de alguns recursos específicos do App Engine. Se preferir não seguir esse caminho, ainda é possível fazer upgrade para um ambiente de execução do Java 11/17 e manter seus apps no App Engine.

3. Configuração/Pré-trabalho

1. Configurar projeto

Neste tutorial, você vai usar um app de exemplo do repositório appengine-java-migration-samples em um projeto novo. Verifique se o projeto tem uma conta de faturamento ativa.

Se você pretende mover um app do App Engine para o Cloud Run, use esse app para acompanhar o tutorial.

Execute o seguinte comando para ativar as APIs necessárias para o projeto:

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

2. Instalar o app de exemplo de referência

Clone o app de exemplo na sua máquina ou no Cloud Shell e navegue até a pasta baseline.

O exemplo é um app do Datastore baseado em servlet Java 8 destinado à implantação no App Engine. Siga as instruções no README sobre como preparar este app para a implantação no App Engine.

3. (Opcional) Implantar o app de referência

As etapas a seguir são necessárias apenas se você quiser confirmar que o app funciona no App Engine antes da migração para o Cloud Run.

Consulte as etapas no README.md:

  1. Instalar/se familiarizar novamente com a CLI gcloud
  2. Inicialize a CLI gcloud para seu projeto com gcloud init
  3. Crie o projeto do App Engine com gcloud app create
  4. Implantar o app de exemplo no App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. Confirme se o aplicativo é executado no App Engine sem problemas

4. Criar um repositório do Artifact Registry

Depois de contêinerizar o app, você vai precisar de um lugar para enviar e armazenar as imagens. A maneira recomendada de fazer isso no Google Cloud é com o Artifact Registry.

Crie o repositório com o nome migration usando a gcloud da seguinte maneira:

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

Esse repositório usa o tipo de formato docker, mas há vários tipos de repositório disponíveis.

Neste ponto, você tem o aplicativo do App Engine de referência e seu projeto do Google Cloud está preparado para a migração para o Cloud Run.

4. Modificar arquivos do aplicativo

Nos casos em que o app usa muito os serviços agrupados legados, a configuração ou outros recursos exclusivos do App Engine, recomendamos continuar acessando esses serviços durante a atualização para o novo ambiente de execução. Este codelab demonstra um caminho de migração para aplicativos que já usam serviços independentes ou que podem ser refatorados para fazer isso.

1. Fazer upgrade para o Java 17

Se o app estiver no Java 8, faça upgrade para uma versão candidata de LTS mais recente, como 11 ou 17, para acompanhar as atualizações de segurança e ter acesso a novos recursos de linguagem.

Comece atualizando as propriedades no pom.xml para incluir o seguinte:

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

Isso vai definir a versão do projeto como 17, informar ao plug-in do compilador que você quer acessar os recursos da linguagem Java 17 e que quer que as classes compiladas sejam compatíveis com a JVM Java 17.

2. Incluir um servidor da Web

Há várias diferenças entre o App Engine e o Cloud Run que valem a pena considerar ao alternar entre eles. Uma diferença é que, embora o ambiente de execução do Java 8 do App Engine fornecesse e gerenciasse um servidor Jetty para os aplicativos hospedados, o Cloud Run não. Vamos usar o Spring Boot para fornecer um servidor da Web e um contêiner de servlet.

Adicione as seguintes dependências:

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

O Spring Boot incorpora um servidor Tomcat por padrão, mas este exemplo exclui esse artefato e fica com o Jetty para minimizar as diferenças no comportamento padrão após a migração. Também podemos configurar a versão do Jetty para corresponder àquela fornecida pelo App Engine.

<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. Configuração do Spring Boot

Embora o Spring Boot possa reutilizar seus servlets sem modificações, ele vai precisar de alguma configuração para a descoberta.

Crie a seguinte classe MigratedServletApplication.java no pacote 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);
    }
}

Isso inclui a anotação @ServletComponentScan, que vai procurar (no pacote atual por padrão) por qualquer @WebServlets e disponibilizá-los conforme o esperado.

4. Como empacotar o app como um JAR

Embora seja possível conteinerizar seu app com o Jib a partir de um war, fica mais fácil se você empacotar o app como um JAR executável. Isso não vai exigir muita configuração, principalmente para projetos que usam o Maven como uma ferramenta de build, já que a embalagem jar é o comportamento padrão.

Remova a tag packaging no arquivo pom.xml:

<packaging>war</packaging>

Em seguida, adicione 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. Como migrar da configuração, dos serviços e das dependências do App Engine

Como mencionado no início do codelab, o Cloud Run e o App Engine foram criados para oferecer experiências de usuário diferentes. Alguns recursos que o App Engine oferece de forma imediata, como os serviços Cron e Task Queue, precisam ser recriados manualmente e serão abordados com mais detalhes em módulos posteriores.

O app de exemplo não usa os serviços incluídos no pacote legados, mas os usuários cujos apps usam podem consultar os seguintes guias:

Como você vai implantar no Cloud Run, o appengine-maven-plugin pode ser removido:

<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. Conteinerizar o aplicativo

Nesse ponto, você pode implantar o app manualmente no Cloud Run diretamente do código-fonte. Essa é uma excelente opção que usa o Cloud Build em segundo plano para oferecer uma experiência de implantação prática. Vamos saber mais sobre implantações de origem nos próximos módulos.

Se você precisar de mais controle sobre a forma de implantação do app, defina um arquivo cloudbuild.yaml que defina explicitamente as etapas de build pretendidas:

1. Definir um arquivo cloudbuild.yaml

Crie o arquivo cloudbuild.yaml a seguir no mesmo nível do 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']

Quando informamos ao Cloud Build que ele deve seguir estas etapas, ele:

  1. Executar testes com ./mvnw test
  2. Crie, envie e marque sua imagem no Artifact Registry com o Jib.
  3. Implantar a imagem no Cloud Run com gcloud run deploy

Observe que ‘visitors' é fornecido ao Cloud Run como o nome de serviço desejado. A sinalização –allow-unauthenticated permite que os usuários acessem o app da Web sem exigir autenticação. Substitua PROJECT_ID pelo ID do seu projeto no cloudbuild.yaml arquivo.

Em seguida, adicione as seguintes vinculações de política do IAM para permitir que a conta de serviço do Cloud Build acesse o 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. Executar o processo de build

Agora que você informou ao Cloud Build as etapas de build desejadas, está tudo pronto para uma implantação com um clique.

Execute este comando:

gcloud builds submit

Quando o processo for concluído, a imagem do contêiner será criada, armazenada no Artifact Registry e implantada no Cloud Run.

Ao final deste codelab, seu app vai ficar igual ao do java17-and-cloud-run/finish.

Pronto! Você migrou um app do App Engine Java 8 para o Java 17 e o Cloud Run e agora tem um entendimento mais claro do trabalho envolvido na troca e na escolha entre as opções de hospedagem.

6. Resumo/limpeza

Parabéns! Você fez upgrade, criou um contêiner, migrou e seu app, o que conclui este tutorial.

A próxima etapa é conhecer os recursos de CI/CD e segurança da cadeia de suprimentos de software que você pode implantar com o Cloud Build:

Opcional: limpar e/ou desativar o serviço

Se você implantou o app de exemplo no App Engine durante este tutorial, desative o app para evitar cobranças. Quando estiver tudo pronto para passar para o próximo codelab, você poderá reativá-lo. Enquanto os aplicativos do App Engine estiverem desativados, eles não terão tráfego para gerar cobranças. No entanto, o uso do Datastore poderá ser faturado se exceder a cota sem custo financeiro. Por isso, exclua o suficiente para ficar abaixo desse limite.

Por outro lado, se você não quiser continuar com as migrações e quiser excluir tudo completamente, poderá excluir o serviço ou encerrar o projeto completamente.

7. Outros recursos

Problemas/comentários do módulo de migração do App Engine

Se você encontrar problemas com este codelab, pesquise seu problema antes de preenchê-lo. Links para pesquisar e criar novos problemas:

Recursos de migração

Recursos on-line

Confira abaixo alguns recursos on-line que podem ser relevantes para este tutorial:

App Engine

Outras informações do Cloud

Vídeos

Licença

Este conteúdo está sob a licença Atribuição 2.0 Genérica da Creative Commons.