Migracja z aplikacji Google App Engine w Javie do Cloud Run przy użyciu Dockera

1. Omówienie

Ta seria ćwiczeń z programowania (samodzielne, praktyczne samouczki) ma na celu pomóc deweloperom w modernizowaniu aplikacji w Google App Engine (Standard) w języku Java, poprzez przeprowadzenie ich przez serię migracji. Wykonując te czynności, możesz zaktualizować aplikację, aby była bardziej przenośna, i zdecydować się na jej skonteneryzowanie na potrzeby Cloud Run, czyli usługi Google Cloud, która jest usługą siostrza App Engine do hostowania kontenerów, oraz innych usług hostowania kontenerów.

Z tego samouczka dowiesz się, jak skonteneryzować aplikację App Engine, aby wdrożyć ją w pełni zarządzanej usłudze Cloud Run za pomocą pliku Dockerfile. Pliki Dockerfiles to najbardziej praktyczna metoda wdrażania w przypadku tej migracji, ale oferują też najwięcej opcji dostosowywania procesu kompilacji.

Oprócz pokazania Ci wymaganych czynności, które należy wykonać, aby przenieść aplikację z App Engine do Cloud Run, pokażemy Ci też, jak uaktualnić aplikację App Engine w Javie 8 do wersji Java 17.

Jeśli aplikacja, którą chcesz przenieść, intensywnie korzysta ze starszych usług w pakiecie App Engine lub innych funkcji App Engine, jako punkt wyjścia możesz wybrać przewodnik Uzyskiwanie dostępu do usług w pakiecie App Engine w wersji Java 11/17, który może być lepszym punktem wyjścia niż ten samouczek.

Dowiesz się, jak:

  • Użyj Cloud Shell
  • Włącz interfejsy Cloud Run API, Artifact Registry API i Cloud Build API
  • Umieszczenie aplikacji w kontenerze za pomocą Dockera, Dockera i Cloud Build
  • Wdrażanie obrazów kontenera w Cloud Run

Czego potrzebujesz

Ankieta

Jak wykorzystasz ten samouczek?

Przeczytaj go tylko Przeczytaj go i wykonaj ćwiczenia

Jak oceniasz swoje wrażenia z korzystania z języka Java?

Początkujący Średnio zaawansowany Zaawansowany

Jak oceniasz korzystanie z usług Google Cloud?

Początkujący Średnio zaawansowany Zaawansowany

2. Tło

Systemy PaaS, takie jak App Engine i Cloud Functions, zapewniają wiele udogodnień dla Twojego zespołu i aplikacji, np. umożliwiają administratorom systemów i zespołom Devops skupienie się na tworzeniu rozwiązań. Dzięki platformom bezserwerowym Twoja aplikacja może automatycznie skalować się w miarę potrzeby, a także zmniejszać do zera dzięki płatnościom za użycie, co pomaga kontrolować koszty. Możesz też używać różnych popularnych języków programowania.

Jednak elastyczność kontenerów również jest kusząca. Kontenery umożliwiają wybór dowolnego języka, biblioteki i pliku binarnego, co łączy zalety obu rozwiązań: wygodę obsługi rozwiązań bezserwerowych i elastyczność kontenerów. Właśnie na tym polega Google Cloud Run.

Nauka korzystania z Cloud Run nie wchodzi w zakres tego ćwiczenia z programowania. Jest ono opisane w dokumentacji Cloud Run. Celem tego ćwiczenia jest zapoznanie się z konteneryzacją aplikacji App Engine na potrzeby Cloud Run (lub innych usług hostowanych w kontenerach). Jest kilka rzeczy, o których musisz wiedzieć, zanim przejdziesz dalej, przede wszystkim dlatego, że interfejs Twojej witryny będzie nieco inny.

Z tego ćwiczenia w Codelabs dowiesz się, jak tworzyć i wdrażać kontenery. Dowiedz się, jak skonteneryzować aplikację za pomocą pliku Dockerfile, zmienić konfigurację App Engine i (opcjonalnie) zdefiniować kroki kompilacji dla Cloud Build. Oznacza to rezygnację z niektórych funkcji App Engine. Jeśli nie chcesz podążać tą ścieżką, możesz uaktualnić środowisko wykonawcze Java do wersji 11/17, a jednocześnie pozostawić aplikacje w App Engine.

3. Konfiguracja/wstępne przygotowanie

1. Konfigurowanie projektu

W tym samouczku użyjesz przykładowej aplikacji z repozytorium appengine-java-migration-samples w zupełnie nowym projekcie. Upewnij się, że projekt ma aktywne konto rozliczeniowe.

Jeśli chcesz przenieść istniejącą aplikację App Engine do Cloud Run, możesz użyć tej aplikacji.

Uruchom to polecenie, aby włączyć interfejsy API niezbędne w projekcie:

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

2. Pobieranie przykładowej aplikacji podstawowej

Sklonuj przykładową aplikację na swoim komputerze lub w Cloud Shell, a następnie przejdź do folderu baseline.

Przykładowa aplikacja to Servlet w Javie 8, przeznaczona do wdrożenia w App Engine. Postępuj zgodnie z instrukcjami w pliku README, aby dowiedzieć się, jak przygotować tę aplikację do wdrożenia App Engine.

3. (Opcjonalnie) Wdróż aplikację podstawową

Poniższe czynności są konieczne tylko wtedy, gdy chcesz sprawdzić, czy aplikacja działa w App Engine, zanim przeprowadzimy ją do Cloud Run.

Zapoznaj się z instrukcjami w pliku README.md:

  1. Zainstaluj i ponownie zapoznaj się z interfejsem wiersza poleceń gcloud
  2. Zainicjuj gcloud CLI dla projektu za pomocą gcloud init
  3. Tworzenie projektu App Engine w narzędziu gcloud app create
  4. Wdrażanie przykładowej aplikacji w App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. Sprawdź, czy aplikacja działa w App Engine bez problemów

4. Tworzenie repozytorium Artifact Registry

Po skonteneryzowaniu aplikacji musisz mieć miejsce na przesyłanie i przechowywanie obrazów. Zalecany sposób wykonania tej operacji w Google Cloud to użycie Artifact Registry.

Utwórz repozytorium o nazwie migration za pomocą gcloud w ten sposób:

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

Pamiętaj, że ten repozytorium używa formatu docker, ale dostępnych jest kilka typów repozytoriów.

W tym momencie masz już podstawową aplikację App Engine, a Twój projekt Google Cloud jest gotowy do przeniesienia jej do Cloud Run.

4. Modyfikowanie plików aplikacji

Jeśli Twoja aplikacja intensywnie korzysta ze starszych pakietów usług, konfiguracji lub innych funkcji App Engine, zalecamy dalsze korzystanie z tych usług podczas uaktualniania do nowego środowiska wykonawczego. Ten projekt pokazuje ścieżkę migracji aplikacji, które już korzystają z samodzielnych usług lub mogą zostać przekształcone w takie.

1. Przechodzenie na Java 17

Jeśli Twoja aplikacja jest napisana w wersji Java 8, rozważ przejście na nowszą wersję LTS, np. 11 lub 17, aby otrzymywać aktualizacje zabezpieczeń i mieć dostęp do nowych funkcji językowych.

Najpierw zaktualizuj właściwości w swoim pliku pom.xml, aby uwzględnić te elementy:

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

Spowoduje to ustawienie wersji projektu na 17, poinformowanie wtyczki kompilatora, że chcesz uzyskać dostęp do funkcji języka Java 17, oraz żądanie zgodności skompilowanych klas z Java 17 JVM.

2. Serwer WWW

Istnieje kilka różnic między App Engine a Cloud Run, które warto wziąć pod uwagę podczas przenoszenia się między nimi. Jedna z różnic polega na tym, że chociaż środowisko wykonawcze Java 8 App Engine udostępniało serwer Jetty dla hostowanych aplikacji i zarządzał nim, Cloud Run tego nie robi. Użyjemy Spring Boot do utworzenia serwera WWW i kontenera servleta.

Dodaj te zależności:

<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 domyślnie osadza serwer Tomcat, ale w tym przykładzie wykluczymy ten element i użyjemy Jetty, aby zminimalizować różnice w domyślnym zachowaniu po migracji.

3. Konfiguracja Spring Boot

Spring Boot może używać serwerletów bez ich modyfikacji, ale aby były one możliwe do znalezienia, trzeba je skonfigurować.

Utwórz w pakiecie com.example.appengine klasę MigratedServletApplication.java:

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);
    }
}

Pamiętaj, że obejmuje to adnotację @ServletComponentScan, która (w domyślnym pakiecie) będzie wyglądać tak samo w przypadku dowolnego @WebServlets i będzie dostępna zgodnie z oczekiwaniami.

4. Pakowanie aplikacji jako pliku JAR

Chociaż można skonteneryzować aplikację po wojnie, będzie to łatwiejsze, jeśli spakujesz ją w postaci pliku wykonywalnego JAR. Nie wymaga to wielu ustawień, zwłaszcza w przypadku projektów, które używają Maven jako narzędzia do kompilacji, ponieważ pakowanie jar jest domyślnym zachowaniem.

Usuń tag packaging z pliku pom.xml:

<packaging>war</packaging>

Następnie dodaj 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. Migracja z konfiguracji, usług i zależności App Engine

Jak wspomnieliśmy na początku ćwiczeń z programowania, usługi Cloud Run i App Engine zostały zaprojektowane tak, aby oferować różne możliwości użytkownikom. Niektóre funkcje, które App Engine oferuje domyślnie, np. usługi Cron i kolejka zadań, trzeba ponownie utworzyć ręcznie. Więcej informacji na ten temat znajdziesz w kolejnych modułach.

Przykładowa aplikacja nie korzysta ze starszych pakietów usług, ale użytkownicy, których aplikacje już korzystają z pakietów, mogą skorzystać z tych przewodników:

Od teraz będziesz wdrażać aplikację w Cloud Run, więc możesz usunąć 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. Konteneryzacja aplikacji

W tym momencie możesz poinformować Cloud Build o tym, jak rzeczywiście utworzyć kontener aplikacji. W przypadku tej metody konteneryzacja nie wymaga osobnego pliku konfiguracji kompilacji (cloudbuild.yaml). Jako punkt wyjścia możemy po prostu zdefiniować minimalny plik Dockerfile:

ŹRÓDŁO: eclipse-temurin

ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG

KOPIUJ plik app.jar ${JAR_FILE}

ENTRYPOINT ["java", "-jar","/app.jar"]

Ten plik dockerfile zawiera w jednej warstwie wersję uber-jar usługi spring boot. Jest to najprostsze podejście do konteneryzacji Dockerfile, ale ma kilka wad, zwłaszcza w przypadku powtarzających się czasów, w których zależności są stosunkowo stabilne. Z tego powodu ta metoda konteneryzacji jest uważana za bardziej zaawansowaną. Z drugiej strony, napisanie własnego pliku Dockerfile daje pełną kontrolę nad obrazem podstawowym i możliwość korzystania z zalet związanych z skutecznością tworzenia obrazu z uwzględnieniem warstw.

2**. Uruchamianie procesu kompilacji**

Gdy już podasz Cloud Build odpowiednie kroki kompilacji, możesz wdrożyć usługę jednym kliknięciem.

Uruchom to polecenie:

gcloud builds submit --tag LOCATION-docker.pkg.dev/PROJECT_ID/REPOSITORY/IMAGE_NAME

Zastąp wartości obiektów zastępczych w powyższym poleceniu tymi:

  • LOCATION: regionalna lub wieloregionalna lokalizacja repozytorium.
  • PROJECT_ID: identyfikator Twojego projektu Cloud.
  • REPOSITORY: nazwa repozytorium Artifact Registry.
  • IMAGE_NAME: nazwa obrazu kontenera.

Po zakończeniu procesu obraz kontenera zostanie skompilowany, zapisany w Artifact Registry i wdrożony w Cloud Run.

Na koniec tego ćwiczenia Twoja aplikacja powinna wyglądać tak samo jak ta w folderze mod4-migrate-to-cloud-run.

I to wszystko! Udało Ci się przenieść aplikację App Engine w Javie 8 do Javi 17 i Cloud Run. Masz już większą świadomość tego, ile pracy wymaga przejście na nową wersję i wybór opcji hostingu.

6. Podsumowanie/czyszczenie

Gratulacje! Aplikacja została zaktualizowana, spakowana do kontenera i przeniesiona. To koniec tego samouczka.

Następnie dowiedz się więcej o funkcjach CI/CD i zabezpieczeniach łańcucha dostaw oprogramowania, które możesz wdrażać za pomocą Cloud Build:

Opcjonalnie: wyczyść lub wyłącz usługę

Jeśli w ramach tego samouczka wdrożysz przykładową aplikację w App Engine, pamiętaj o wyłączeniu tej aplikacji, aby uniknąć naliczania opłat. Gdy uznasz, że chcesz przejść do kolejnego ćwiczenia z programowania, możesz je ponownie włączyć. Gdy aplikacje App Engine są wyłączone, nie będą generować ruchu, który powoduje naliczanie opłat. Użycie bazy danych może jednak być obciążone opłatą, jeśli przekroczy bezpłatny limit. Usuń więc wystarczającą liczbę aplikacji, aby nie przekroczyć tego limitu.

Jeśli z kolei nie chcesz kontynuować migracji i chcesz całkowicie usunąć wszystko, możesz usunąć usługę lub zamknąć projekt.

7. Dodatkowe materiały

Problemy/opinie dotyczące modułu migracji App Engine

Jeśli zauważysz problemy z tym Codelab, najpierw je wyszukaj, a potem prześlij zgłoszenie. Linki do wyszukiwania i tworzenia nowych problemów:

Zasoby migracji

Zasoby online

Poniżej znajdziesz zasoby online, które mogą być przydatne w tym samouczku:

App Engine

Inne informacje dotyczące Cloud

Filmy

Licencja

To zadanie jest licencjonowane na podstawie ogólnej licencji Creative Commons Attribution 2.0.