מעבר מאפליקציית Google App Engine Java ל-Cloud Run באמצעות Docker

1. סקירה כללית

סדרת שיעורי ה-codelab (מדריכים מעשיים בקצב אישי) הזו נועדה לעזור למפתחי Java ב-Google App Engine (Standard) לחדש את האפליקציות שלהם באמצעות סדרה של העברות. אחרי שתבצעו את השלבים האלה, תוכלו לעדכן את האפליקציה כדי שהיא תהיה ניידת יותר, ולהחליט להשתמש בה ב-Cloud Run, שירות אירוח קונטיינרים של Google Cloud שדומה ל-App Engine, ובשירותי אירוח קונטיינרים אחרים.

במדריך הזה נלמד איך ליצור קונטיינר לאפליקציית App Engine כדי לפרוס אותה בשירות המנוהל במלואו Cloud Run באמצעות Dockerfile. קובצי Docker הם שיטת ה-Deployment הכי מעשית להעברה הזו, אבל הם גם מציעים הכי הרבה אפשרויות להתאמה אישית של תהליך build.

בנוסף להסבר על השלבים הנדרשים למעבר מ-App Engine ל-Cloud Run, נסביר גם איך לשדרג אפליקציית Java 8 App Engine ל-Java 17.

אם האפליקציה שרוצים להעביר משתמשת הרבה בשירותים מקובצים מדור קודם של App Engine או בתכונות ספציפיות אחרות של App Engine, יכול להיות שהמדריך גישה לשירותים מקובצים של App Engine ל-Java 11/17 יהיה נקודת התחלה טובה יותר מה-codelab הזה.

כאן אפשר להבין איך

  • שימוש ב-Cloud Shell
  • הפעלת Cloud Run,‏ Artifact Registry ו-Cloud Build APIs
  • יצירת קונטיינר לאפליקציה באמצעות Docker ו-Cloud Build
  • פריסת קובצי אימג' של קונטיינרים ב-Cloud Run

מה תצטרכו

סקר

איך תשתמשו במדריך הזה?

רק לקרוא לקרוא ולבצע את התרגילים

איך היית מדרג את החוויה שלך עם Java?

מתחילים ביניים מומחים

איזה דירוג מתאים לדעתך לחוויית השימוש שלך בשירותי Google Cloud?

מתחילים ביניים מומחים

2. רקע

מערכות PaaS כמו App Engine ו-Cloud Functions מספקות הרבה יתרונות לצוות ולאפליקציה, למשל מאפשרות לאדמינים של מערכות ולצוותי DevOps להתמקד בבניית פתרונות. פלטפורמות ללא שרתים מאפשרות לאפליקציה להגדיל את הקיבולת באופן אוטומטי לפי הצורך, לצמצם את הקיבולת לאפס באמצעות חיוב לפי שימוש כדי לעזור לכם לשלוט בעלויות, ולהשתמש במגוון שפות פיתוח נפוצות.

עם זאת, הגמישות של קונטיינרים היא גם יתרון משמעותי. האפשרות לבחור כל שפה, כל ספרייה וכל תוכנה בינארית מאפשרת לכם ליהנות מכל העולמות: הנוחות של שרתים וירטואליים יחד עם הגמישות של קונטיינרים. בדיוק בשביל זה נועד Google Cloud Run.

המדריך הזה לא כולל הסבר על השימוש ב-Cloud Run. אפשר לקרוא על כך במסמכי התיעוד של Cloud Run. המטרה כאן היא להכיר את האופן שבו יוצרים קונטיינר לאפליקציית App Engine עבור Cloud Run (או שירותים אחרים שמארחים קונטיינרים). לפני שממשיכים, חשוב לדעת כמה דברים, בעיקר שחוויית המשתמש תהיה שונה מעט.

ב-Codelab הזה תלמדו איך ליצור ולפרוס קונטיינרים. תלמדו איך ליצור קונטיינר לאפליקציה באמצעות Dockerfile, איך להפסיק להשתמש בהגדרות של App Engine ואיך להגדיר שלבי build ל-Cloud Build (אופציונלי). הפעולה הזו תכלול מעבר מתכונות מסוימות שספציפיות ל-App Engine. אם אתם לא רוצים לפעול לפי השלבים האלה, אתם יכולים לשדרג לסביבת ריצה של Java 11/17 תוך כדי השארת האפליקציות ב-App Engine.

3. הגדרה/עבודה מקדימה

1. הגדרת פרויקט

במדריך הזה נשתמש באפליקציה לדוגמה ממאגר appengine-java-migration-samples בפרויקט חדש לגמרי. מוודאים שיש בפרויקט חשבון פעיל לחיוב.

אם אתם מתכוונים להעביר אפליקציית App Engine קיימת אל Cloud Run, אתם יכולים להשתמש באפליקציה הזו כדי לפעול לפי ההוראות.

מריצים את הפקודה הבאה כדי להפעיל את ממשקי ה-API הנדרשים לפרויקט:

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

2. קבלת אפליקציה לדוגמה של בסיס

משכפלים את האפליקציה לדוגמה במחשב שלכם או ב-Cloud Shell, ואז עוברים לתיקייה baseline.

הדוגמה היא אפליקציית Datastore מבוססת-Servlet ב-Java 8, שמיועדת לפריסה ב-App Engine. פועלים לפי ההוראות בקובץ ה-README כדי להכין את האפליקציה לפריסה ב-App Engine.

3. (אופציונלי) פריסת אפליקציית בסיס

השלב הבא נדרש רק אם רוצים לוודא שהאפליקציה פועלת ב-App Engine לפני המעבר ל-Cloud Run.

פועלים לפי השלבים בקובץ README.md:

  1. התקנה או היכרות מחדש עם gcloud CLI
  2. מאתחלים את ה-CLI של gcloud עבור הפרויקט באמצעות gcloud init
  3. יוצרים את פרויקט App Engine באמצעות gcloud app create
  4. פריסת אפליקציית הדוגמה ב-App Engine
./mvnw package appengine:deploy -Dapp.projectId=$PROJECT_ID
  1. אישור שהאפליקציה פועלת ב-App Engine ללא בעיות

4. יצירת מאגר ב-Artifact Registry

אחרי שמכניסים את האפליקציה לקונטיינר, צריך מקום לשליחה ולאחסון של קובצי האימג' של הקונטיינרים. הדרך המומלצת לעשות זאת ב-Google Cloud היא באמצעות Artifact Registry.

יוצרים את המאגר בשם migration באמצעות gcloud באופן הבא:

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

שימו לב שהמאגר הזה משתמש בפורמט docker, אבל יש כמה סוגים של מאגרים.

בשלב הזה, יש לכם אפליקציית App Engine בסיסית, והפרויקט שלכם ב-Google Cloud מוכן להעברה אל Cloud Run.

4. שינוי קבצים של אפליקציות

במקרים שבהם האפליקציה שלכם עושה שימוש נרחב בשירותים, בהגדרות או בתכונות אחרות של App Engine מדור קודם, אנחנו ממליצים להמשיך לגשת לשירותים האלה בזמן השדרוג לסביבת זמן הריצה החדשה. Codelab זה מדגים נתיב העברה לאפליקציות שכבר משתמשות בשירותים עצמאיים, או שאפשר לבצע בהן ארגון הקוד מחדש (Refactoring) כדי שיוכלו להשתמש בשירותים כאלה.

1. שדרוג ל-Java 17

אם האפליקציה שלכם מבוססת על Java 8, כדאי לשדרג לגרסה מאוחרת יותר של LTS כמו 11 או 17 כדי להתעדכן בעדכוני אבטחה ולקבל גישה לתכונות חדשות של השפה.

כדי להתחיל, צריך לעדכן את המאפיינים ב-pom.xml כך שיכללו את המאפיינים הבאים:

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

הפעולה הזו תגדיר את גרסת הפרויקט ל-17, תודיע לתוסף של הקומפיילר שאתם רוצים גישה לתכונות השפה של Java 17, ותגרום לכך שהמחלקות המקומפלות יהיו תואמות ל-JVM של Java 17.

2. כולל שרת אינטרנט

יש כמה הבדלים בין App Engine לבין Cloud Run שכדאי לקחת בחשבון כשעוברים ביניהם. הבדל אחד הוא שבזמן הריצה של Java 8 ב-App Engine, שרת Jetty סופק ונוהל על ידי האפליקציות שהוא אירח, אבל ב-Cloud Run זה לא קורה. נשתמש ב-Spring Boot כדי לספק לנו שרת אינטרנט ומאגר סרוולטים.

מוסיפים את יחסי התלות הבאים:

<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 מטמיע שרת Tomcat כברירת מחדל, אבל בדוגמה הזו לא נכלל הארטיפקט הזה, והמערכת תשתמש ב-Jetty כדי לצמצם את ההבדלים בהתנהגות ברירת המחדל אחרי ההעברה.

3. הגדרה של Spring Boot

מערכת Spring Boot תוכל לעשות שימוש חוזר ב-servlets שלכם בלי לבצע בהם שינויים, אבל תצטרכו לבצע כמה הגדרות כדי לוודא שהמערכת תוכל לזהות אותם.

יוצרים את המחלקה MigratedServletApplication.java הבאה בחבילה 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);
    }
}

שימו לב: זה כולל את ההערה @ServletComponentScan, שתחפש (בחבילה הנוכחית כברירת מחדל) כל @WebServlets ותהפוך אותם לזמינים כצפוי.

4. אריזת האפליקציה כקובץ JAR

אפשר להכניס את האפליקציה לקונטיינר מתוך קובץ WAR, אבל יהיה קל יותר אם תארזו את האפליקציה כקובץ JAR הפעלה. הפעולה הזו לא דורשת הרבה הגדרות, במיוחד בפרויקטים שמשתמשים ב-Maven ככלי בנייה, כי אריזת jar היא התנהגות ברירת המחדל.

מסירים את התג packaging בקובץpom.xml:

<packaging>war</packaging>

לאחר מכן, מוסיפים את 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. מעבר מהגדרות, משירותים ומהתלויות של App Engine

כמו שציינו בתחילת ה-codelab, ‏ Cloud Run ו-App Engine נועדו לספק חוויות משתמש שונות. תכונות מסוימות ש-App Engine מציע מחוץ לקופסה – כמו השירותים Cron ו-Task Queue – צריך ליצור מחדש באופן ידני, והן יוסברו בפירוט רב יותר במודולים הבאים.

אפליקציית הדוגמה לא משתמשת בשירותים מדור קודם שצורפו לחבילה, אבל משתמשים שהאפליקציות שלהם כן משתמשות בשירותים כאלה יכולים לעיין במדריכים הבאים:

מעכשיו תבצעו פריסה ל-Cloud Run, ולכן אפשר להסיר את 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. העברה של אפליקציה לקונטיינר

בשלב הזה אתם מוכנים להגדיר ב-Cloud Build איך לבנות את הקונטיינר של האפליקציה. בשיטה הזו של יצירת קונטיינרים לא נדרש קובץ תצורה נפרד של build (cloudbuild.yaml). אנחנו יכולים פשוט להגדיר קובץ Dockerfile מינימלי כנקודת התחלה:

FROM eclipse-temurin

ARG JAR_FILE=JAR_FILE_MUST_BE_SPECIFIED_AS_BUILD_ARG

COPY ${JAR_FILE} app.jar

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

קובץ ה-Docker הזה כולל את גרסת ה-uber-jar של שירות Spring Boot בשכבה אחת. זו הגישה הכי פשוטה ליצירת קונטיינרים של Dockerfile, אבל יש לה כמה חסרונות, במיוחד כשמשווים בין מקרים חוזרים שבהם התלות יחסית יציבה. בעיות כמו זו הן הסיבה לכך ששיטת הקונטיינר הזו נחשבת למתקדמת יותר. מצד שני, כשכותבים קובץ Dockerfile משלכם, יש לכם שליטה מלאה על תמונת הבסיס וגישה ליתרונות הביצועים של כתיבת תמונה בשכבות מחושבות.

‫2**. מריצים את תהליך ה-build**

אחרי שעדכנתם את Cloud Build לגבי שלבי ה-build הרצויים, אתם מוכנים לפריסה בלחיצה אחת.

מריצים את הפקודה הבאה:

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

מחליפים את ערכי ה-placeholder בפקודה שלמעלה בערכים הבאים:

  • ‫LOCATION: המיקום האזורי או המיקום במספר אזורים של המאגר.
  • ‫PROJECT_ID: מזהה הפרויקט שלכם ב-Cloud.
  • REPOSITORY: השם של מאגר Artifact Registry.
  • ‫IMAGE_NAME: השם של קובץ האימג' בקונטיינר.

בסיום התהליך, קובץ אימג' של קונטיינר נבנה, אוחסן ב-Artifact Registry ונפרס ב-Cloud Run.

בסיום ה-codelab, האפליקציה שלכם צריכה להיראות כמו האפליקציה ב-mod4-migrate-to-cloud-run folder.

זהו, אתה מוכן! הצלחתם להעביר אפליקציית Java 8 App Engine ל-Java 17 ול-Cloud Run, ועכשיו יש לכם הבנה ברורה יותר של העבודה הנדרשת כשעוברים בין אפשרויות אירוח ובוחרים ביניהן.

6. סיכום/ניקוי

מזל טוב, שדרגת, יצרת קונטיינר, העברת את האפליקציה שלך, ובכך סיימת את המדריך הזה!

מכאן, השלב הבא הוא לקרוא מידע נוסף על תכונות האבטחה של CI/CD ושל שרשרת אספקת התוכנה, שזמינות לכם עכשיו כשאתם יכולים לבצע פריסה באמצעות Cloud Build:

אופציונלי: פינוי נפח אחסון או השבתה של שירות

אם פרסתם את האפליקציה לדוגמה ב-App Engine במהלך המדריך הזה, אל תשכחו להשבית את האפליקציה כדי להימנע מחיובים. כשרוצים לעבור ל-codelab הבא, אפשר להפעיל אותו מחדש. בזמן שאפליקציות App Engine מושבתות, הן לא מקבלות תנועה ולכן לא צוברות חיובים. עם זאת, יכול להיות שיהיו חיובים על השימוש ב-Datastore אם הוא חורג מהמכסה החינמית, לכן צריך למחוק מספיק נתונים כדי שלא לחרוג מהמגבלה הזו.

מצד שני, אם אתם לא מתכוונים להמשיך בהעברות ורוצים למחוק הכול לגמרי, אתם יכולים למחוק את השירות או להשבית את הפרויקט לגמרי.

7. מקורות מידע נוספים

App Engine migration module codelabs issues/feedback

אם נתקלתם בבעיות ב-codelab הזה, כדאי לחפש את הבעיה לפני ששולחים דיווח. קישורים לחיפוש וליצירה של בעיות חדשות:

מקורות מידע על העברת נתונים

משאבים באינטרנט

בהמשך מופיעים מקורות מידע באינטרנט שעשויים להיות רלוונטיים למדריך הזה:

App Engine

מידע אחר על Cloud

סרטונים

רישיון

עבודה זו מורשית תחת רישיון Creative Commons שמותנה בייחוס 2.0 כללי.