סביבת זמן ריצה של Java

סביבת זמן הריצה של Java היא מחסנית התוכנה שאחראית להתקנת הקוד של שירות האינטרנט וקשרי התלות שלו, ולהפעלת השירות.

מצהירים על זמן הריצה של Java בסביבה הרגילה של App Engine בקובץ app.yaml. לדוגמה:

runtime: javaVERSION

VERSION הוא מספר הגרסה של Java.MAJOR לדוגמה, כדי להשתמש בגרסה האחרונה של Java, ‏ Java 25, מציינים 25.

למידע על גרסאות נתמכות אחרות של Java וגרסת Ubuntu התואמת לגרסת Java שלכם, אפשר לעיין בלוח הזמנים של תמיכה בזמן ריצה.

לפני שמתחילים

  1. מורידים את הגרסה העדכנית של Google Cloud CLI או מעדכנים את ה-CLI של gcloud לגרסה הנוכחית:

    gcloud components update
    
  2. כדי לפרוס באמצעות Maven, צריך להוסיף את App Engine Maven Plugin לקובץ pom.xml:

    <plugin>
       <groupId>com.google.cloud.tools</groupId>
       <artifactId>appengine-maven-plugin</artifactId>
       <version>2.8.1</version>
    </plugin>

    אפשרויות נוספות לפריסה כוללות שימוש בפקודה gcloud app deploy או בתוסף App Engine Gradle.

  3. פועלים לפי ההוראות של מסגרת האפליקציה כדי להגדיר את הבנייה של קובץ הפעלה JAR.

תאימות למסגרת

בזמן הריצה של Java ב-App Engine, אפשר לפרוס קובצי JAR שניתנים להפעלה. זמני הריצה לא כוללים מסגרת להצגת אינטרנט, כלומר אתם לא מוגבלים לשימוש במסגרות או בספריות מבוססות-servlet. אתם יכולים להשתמש בתלות המקורית שלכם או במערכות רשת כמו ספריית Netty.

אתם לא מוגבלים למסגרות האלה, ואנחנו ממליצים לכם לנסות את המסגרת המועדפת עליכם, כמו Grails,‏ Blade,‏ Play!, ‫Vaadin או jHipster.

פריסת פרויקטים של קוד מקור ב-Maven בסביבת זמן הריצה של Java

אתם יכולים לפרוס את פרויקט Maven כקוד מקור, ולבנות ולפרוס אותו באמצעות Buildpacks של Google Cloud.

כדי לפרוס פרויקט Maven כקוד מקור, עוברים לספרייה ברמה העליונה של הפרויקט ומקלידים:

gcloud app deploy pom.xml

יומני הבנייה והפריסה יועברו בסטרימינג, ואפשר לראות את היומנים המפורטים בקטע Cloud Build history בGoogle Cloud מסוף.

שימוש בקובצי הפעלה של GraalVM

זמן הריצה של Java בסביבה הרגילה של App Engine תומך בקובצי הפעלה של תמונות מקוריות של GraalVM. אחרי שמהדרים את אפליקציית Java לתמונה מקורית של GraalVM, אפשר להשתמש בהגדרה entrypoint בקובץ app.yaml כדי להפנות לקובץ ההפעלה.

לדוגמה, לקובץ הפעלה עם שם הקובץ myexecutable יכול להיות קובץ התצורה app.yaml הבא:

runtime: 25 # or another supported runtime version.
entrypoint: ./myexecutable

Google Cloud אפשר להשתמש בספריות לקוח כדי לקמפל אפליקציות כתמונת Native של GraalVM. מידע נוסף מופיע במאמר בנושא קומפילציה של תמונות מקוריות.

גרסת Java

הגרסה האחרונה של Java שנתמכת היא 25. סביבת זמן הריצה של Java משתמשת בגרסה היציבה האחרונה של הגרסה שצוינה בקובץ app.yaml. App Engine מעדכן אוטומטית לגרסאות חדשות של תיקוני אבטחה, אבל הוא לא מעדכן אוטומטית את הגרסה המשנית.

לדוגמה, יכול להיות שהאפליקציה שלכם תופעל ב-Java 21.0.4 ותעודכן אוטומטית לגרסה Java 21.0.5 בהפעלה מאוחרת יותר של הפלטפורמה המנוהלת, אבל היא לא תעודכן אוטומטית ל-Java 22.

כדי ללמוד איך לשדרג את גרסת Java, אפשר לעיין במאמר בנושא שדרוג של אפליקציה קיימת.

סביבת Open JDK של זמן הריצה

‫App Engine מריץ אפליקציות Java במאגר מאובטח באמצעות gVisor בהפצת Ubuntu Linux עדכנית ובזמן הריצה הנתמך שלה openjdk-17-jdk ל-Java 17 או openjdk-21-jdk ל-Java 21.

במאמר לוח הזמנים של תמיכה בזמן ריצה מפורטות גרסאות Ubuntu הנתמכות עבור גרסת Java שלכם.

‫App Engine מתחזק את תמונת הבסיס ומעדכן את חבילת OpenJDK 17 ו-OpenJDK 21, בלי שתצטרכו לפרוס מחדש את האפליקציה.

האפליקציה שפרסתם נמצאת בספרייה /workspace של סביבת זמן הריצה. אפשר לגשת אליו גם דרך קישור סמלי בכתובת /srv.

גרסאות של App Engine Java

כל הארטיפקטים שפורסמו ומתחילים בגרסה 2.x.x משתמשים במנגנון הפרסום בקוד פתוח. פרטים נוספים זמינים במאגר GitHub.

תלויות

מידע נוסף על הצהרה על יחסי תלות וניהול שלהם זמין במאמר Specifying dependencies.

הפעלת האפליקציה

במסגרות כמו Spring Boot,‏ Micronaut ו-Ktor נוצרת כברירת מחדל הפעלה של uber JAR. אם קובץ ה-build של Maven או Gradle יוצר קובץ JAR של uber שניתן להפעלה, סביבת זמן הריצה מפעילה את האפליקציה על ידי הרצת אפליקציית JAR של uber.

לחלופין, App Engine ישתמש בתוכן של השדה האופציונלי entrypoint בקובץ app.yaml. לדוגמה:

runtime: java25 # or another supported runtime
entrypoint: java -Xmx64m -jar YOUR-ARTIFACT.jar

כאשר קובץ ה-JAR של האפליקציה YOUR-ARTIFACT.jar לדוגמה חייב:

  • להיות בתיקיית השורש עם קובץ app.yaml.
  • כוללים רשומה של Main-Class בקובץ המטא-נתונים META-INF/MANIFEST.MF.
  • אופציונלית, יכול להכיל רשומה Class-Path עם רשימה של נתיבים יחסיים לקובצי JAR אחרים שתלויים בו. הקבצים האלה יועלו עם האפליקציה באופן אוטומטי.

כדי שהאפליקציה תקבל בקשות HTTP, נקודת הכניסה צריכה להפעיל שרת אינטרנט שמקשיב ליציאה שצוינה במשתנה הסביבה PORT. הערך של משתנה הסביבה PORT מוגדר באופן דינמי על ידי סביבת ההגשה של App Engine. אי אפשר להגדיר את הערך הזה בקטע env_variables של הקובץ app.yaml.

בעזרת נקודת כניסה מותאמת אישית, אפשר ליצור את האפליקציה ולדחוס אותה כקובץ JAR דק שמכיל רק את קוד האפליקציה ותלות ישירה. כשפורסים את האפליקציה, התוסף App Engine מעלה רק את הקבצים שהשתנו, ולא את כל חבילת ה-JAR.

חשוב להשתמש במשתנה הסביבה PORT

אם אתם רואים את האזהרות לגבי יציאה 8080 ו-NGINX בקובצי היומן של האפליקציה, שרת האינטרנט של האפליקציה מאזין ליציאה 8080 שמוגדרת כברירת מחדל. כך נמנע מ-App Engine להשתמש בשכבת NGINX שלו כדי לדחוס תגובות HTTP. מומלץ להגדיר את שרת האינטרנט כך שיגיב לבקשות HTTP ביציאה שצוינה במשתנה הסביבה PORT, בדרך כלל 8081. לדוגמה:

/*
 * Copyright 2019 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.appengine;

import com.sun.net.httpserver.HttpServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;

public class Main {

  public static void main(String[] args) throws IOException {
    // Create an instance of HttpServer bound to port defined by the 
    // PORT environment variable when present, otherwise on 8080.
    int port = Integer.parseInt(System.getenv().getOrDefault("PORT", "8080"));
    HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);

    // Set root URI path.
    server.createContext("/", (var t) -> {
      byte[] response = "Hello World!".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    // Create a second URI path.
    server.createContext("/foo", (var t) -> {
      byte[] response = "Foo!".getBytes();
      t.sendResponseHeaders(200, response.length);
      try (OutputStream os = t.getResponseBody()) {
        os.write(response);
      }
    });

    server.start();
  }
}

תאימות לגרסאות קודמות של Java

למידע על ההבדלים בין Java 8 לבין הגרסה העדכנית ביותר של Java שנתמכת, אפשר לעיין במאמר מעבר מ-Java 8 לזמן הריצה העדכני ביותר של Java.

משתני סביבה

משתני הסביבה הבאים מוגדרים על ידי זמן הריצה:

משתנה הסביבה תיאור
GAE_APPLICATION המזהה של אפליקציית App Engine. המזהה הזה מתחיל בקידומת region code~, למשל e~ לאפליקציות שמוצבות באירופה.
GAE_DEPLOYMENT_ID המזהה של הפריסה הנוכחית.
GAE_ENV סביבת App Engine. ההגדרה היא standard.
GAE_INSTANCE המזהה של המופע שבו השירות שלכם פועל כרגע.
GAE_MEMORY_MB נפח הזיכרון שזמין לתהליך האפליקציה, ב-MB.
GAE_RUNTIME סביבת זמן הריצה שצוינה בקובץ app.yaml.
GAE_SERVICE שם השירות שצוין בקובץ app.yaml. אם לא מציינים שם שירות, ברירת המחדל היא default.
GAE_VERSION תווית הגרסה הנוכחית של השירות.
GOOGLE_CLOUD_PROJECT מזהה הפרויקט ב- Google Cloud שמשויך לאפליקציה.
PORT היציאה שמקבלת בקשות HTTP.
NODE_ENV (זמין רק בסביבת זמן ריצה של Node.js) מגדירים את הערך production כשהשירות נפרס.

אפשר להגדיר משתני סביבה נוספים בקובץ app.yaml, אבל אי אפשר לשנות את הערכים שלמעלה, למעט NODE_ENV.

פרוטוקול HTTPS ושרתי proxy להעברה

‫App Engine מסיימת חיבורי HTTPS במאזן העומסים ומעבירה בקשות לאפליקציה. יש אפליקציות שצריכות לקבוע את כתובת ה-IP והפרוטוקול של הבקשה המקורית. כתובת ה-IP של המשתמש זמינה בכותרת הרגילה X-Forwarded-For. אפליקציות שזקוקות למידע הזה צריכות להגדיר את תוכנת ה-framework שלהן כך שתיתן אמון בשרת ה-proxy.

גישה למערכת הקבצים

סביבת זמן הריצה כוללת ספרייה /tmp עם הרשאת כתיבה, ולכל שאר הספריות יש הרשאת קריאה בלבד. כתיבה ל-/tmp תופסת זיכרון מערכת.

שרת מטא-נתונים

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

אפשר לגשת לשרת המטא-נתונים דרך נקודות הקצה הבאות:

  • http://metadata
  • http://metadata.google.internal

בקשות שנשלחות לשרת המטא-נתונים צריכות לכלול את כותרת הבקשה Metadata-Flavor: Google. הכותרת הזו מציינת שהבקשה נשלחה בכוונה מפורשת לאחזר ערכי מטא-נתונים.

בטבלה הבאה מפורטות נקודות הקצה שאליהן אפשר לשלוח בקשות HTTP למטא-נתונים ספציפיים:

נקודת קצה של מטא-נתונים תיאור
/computeMetadata/v1/project/numeric-project-id מספר הפרויקט שהוקצה לפרויקט שלכם.
/computeMetadata/v1/project/project-id מזהה הפרויקט שהוקצה לפרויקט שלכם.
/computeMetadata/v1/instance/region האזור שבו המופע פועל.
/computeMetadata/v1/instance/service-accounts/default/aliases
/computeMetadata/v1/instance/service-accounts/default/email כתובת האימייל בחשבון השירות שמוגדר כברירת מחדל ומוקצה לפרויקט.
/computeMetadata/v1/instance/service-accounts/default/ מציגה את כל חשבונות השירות שמוגדרים כברירת מחדל בפרויקט.
/computeMetadata/v1/instance/service-accounts/default/scopes רשימה של כל ההיקפים הנתמכים בחשבונות שירות שמוגדרים כברירת מחדל.
/computeMetadata/v1/instance/service-accounts/default/token מחזירה את אסימון האימות שאפשר להשתמש בו כדי לאמת את האפליקציה שלכם ב-Google Cloud APIs אחרים.

לדוגמה, כדי לאחזר את מזהה הפרויקט, שולחים בקשה אל http://metadata.google.internal/computeMetadata/v1/project/project-id.