אפשרויות פריסה של Java
יש שתי אפשרויות לפריסת פונקציית Java:
- ממקור. לדיון כללי בנושא הזה, אפשר לעיין במאמר פריסת פונקציה ב-Cloud Functions.
- מקובץ JAR ארוז מראש.
פריסה מקוד המקור
קוד המקור של הפונקציה צריך להיות במיקום הרגיל של פרויקטים ב-Maven (src/main/java). הפונקציות לדוגמה במסמך הזה נמצאות ישירות ב-src/main/java, בלי הצהרת חבילה בקובץ המקור .java. במקרה של קוד לא טריוויאלי, סביר להניח שתצטרכו ליצור חבילה. אם החבילה היא com.example, ההיררכיה תיראה כך:
myfunction/
├─ pom.xml
├─ src
├─main
├─ java
├─ com
├─ example
├─ MyFunction.java
כדי לפרוס פונקציית HTTP, משתמשים בפקודה הבאה:
gcloud functions deploy $name --trigger-http --no-gen2 \
--entry-point $function_class --runtime java17
כאשר:
-
$nameהוא שם תיאורי שרירותי שיהיה השם של הפונקציה אחרי הפריסה.$nameיכול להכיל רק אותיות, מספרים, קווים תחתונים ומקפים. -
$function_classהוא השם המלא של המחלקה (לדוגמה,com.example.MyFunctionאו רקMyFunctionאם לא משתמשים בחבילה).
כדי לפרוס פונקציה מבוססת-אירועים, משתמשים בפקודה הבאה:
gcloud functions deploy $name --no-gen2 --entry-point $function_class \
--trigger-resource $resource_name \
--trigger-event $event_name \
--runtime java17
כאשר:
-
$nameהוא שם תיאורי שרירותי שיהיה השם של הפונקציה אחרי הפריסה. -
$function_classהוא השם המלא של המחלקה (לדוגמה,com.example.MyFunctionאו רקMyFunctionאם לא משתמשים בחבילה). -
$resource_nameו-$event_nameספציפיים לאירועים שמפעילים את הפונקציה. דוגמאות למשאבים ולאירועים נתמכים הם Google Cloud Pub/Sub ו-Google Cloud Storage.
כשפורסים פונקציה ממקור, Google Cloud CLI מעלה את ספריית המקור (ואת כל מה שיש בה) אל Google Cloud כדי לבנות. כדי להימנע משליחת קבצים מיותרים, אפשר להשתמש ב.gcloudignore
קובץ. עורכים את הקובץ .gcloudignore כדי להתעלם מספריות נפוצות כמו .git ו-target/. לדוגמה, קובץ .gcloudignore יכול להכיל את הפרטים הבאים:
.git
target
build
.idea
פריסה מקובץ JAR
אפשר לפרוס קובץ JAR מוכן מראש שמכיל את הפונקציה. זה שימושי במיוחד אם אתם צריכים לפרוס פונקציה שמשתמשת בתלות ממאגר פרטי של ארטיפקטים, שלא ניתן לגשת אליו מצינור העיבוד של Google Cloud כשיוצרים את הפונקציה ממקור. קובץ ה-JAR יכול להיות קובץ uber JAR שמכיל את מחלקת הפונקציה ואת כל מחלקות התלות שלה, או קובץ thin JAR שמכיל Class-Path רשומות של קובצי JAR של תלות בקובץ META-INF/MANIFEST.MF.
פיתוח ופריסה של קובץ Uber JAR
קובץ uber JAR הוא קובץ JAR שמכיל את מחלקות הפונקציות וגם את כל התלויות שלו. אפשר ליצור קובץ JAR גדול גם באמצעות Maven וגם באמצעות Gradle. כדי לפרוס קובץ Uber JAR, הוא צריך להיות קובץ ה-JAR היחיד בספרייה משלו, למשל:
my-function-deployment/ ├─ my-function-with-all-dependencies.jar
אפשר להעתיק את הקובץ למבנה התיקיות הזה, או להשתמש בתוספים של Maven ו-Gradle כדי ליצור את תיקיית הפריסה הנכונה.
Maven
משתמשים בפלאגין Maven Shade כדי ליצור קובץ JAR גדול. הגדרת pom.xml באמצעות הפלאגין Shade:
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<outputFile>${project.build.directory}/deployment/${build.finalName}.jar</outputFile>
<transformers>
<!-- This may be needed if you need to shade a signed JAR -->
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>.SF</resource>
<resource>.DSA</resource>
<resource>.RSA</resource>
</transformer>
<!-- This is needed if you have dependencies that use Service Loader. Most Google Cloud client libraries does. -->
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
יוצרים את קובץ ה-JAR הגדול:
mvn package
לאחר מכן מבצעים פריסה באמצעות הפקודה הבאה:
gcloud functions deploy jar-example \
--entry-point=Example \
--no-gen2 \
--runtime=java17 \
--trigger-http \
--source=target/deployment
Gradle
משתמשים בפלאגין Shadow ל-Gradle. מגדירים את הפלאגין בקובץ build.gradle:
buildscript {
repositories {
jcenter()
}
dependencies {
...
classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0"
}
}
plugins {
id 'java'
...
}
sourceCompatibility = '17.0'
targetCompatibility = '17.0'
apply plugin: 'com.github.johnrengelman.shadow'
shadowJar {
mergeServiceFiles()
}
...
עכשיו אפשר להריץ את Gradle באמצעות הפקודה shadowJar:
gradle shadowJar
לאחר מכן מבצעים פריסה באמצעות הפקודה הבאה:
gcloud functions deploy jar-example \
--entry-point=Example \
--no-gen2 \
--runtime=java17 \
--trigger-http \
--source=build/libs
פיתוח ופריסה של קובץ JAR דק עם תלות חיצונית
אפשר ליצור ולפרוס קובץ JAR דק במקום קובץ uber JAR. קובץ JAR דק הוא קובץ JAR שמכיל רק את מחלקות הפונקציות, ללא התלויות שמוטמעות באותו קובץ JAR. מכיוון שהתלות עדיין נדרשת לפריסה, צריך להגדיר את הדברים באופן הבא:
- יחסי התלות צריכים להיות בספריית משנה ביחס לקובץ ה-JAR שרוצים לפרוס.
- קובץ ה-JAR חייב לכלול קובץ
META-INF/MANIFEST.MFעם מאפייןClass-Pathשהערך שלו הוא רשימה של נתיבי התלות הנדרשים.
לדוגמה, קובץ ה-JAR my-function.jar מכיל קובץ META-INF/MANIFEST.MF עם 2 תלויות בספרייה libs/ (רשימה של נתיבים יחסיים שמופרדים באמצעות רווח):
Manifest-Version: 1.0
Class-Path: libs/dep1.jar libs/dep2.jar
ספריית הפריסה צריכה להכיל את קובץ ה-JAR של הפונקציה הראשית, וגם ספריית משנה עם שתי התלויות שהפונקציה תלויה בהן:
function-deployment/
├─ my-function.jar
├─ libs
├─ dep1.jar
├─ dep2.jar
אפשר ליצור קובץ JAR דק גם באמצעות Maven וגם באמצעות Gradle:
Maven
משתמשים בפלאגין Maven JAR כדי להגדיר אוטומטית את MANIFEST.MF עם הנתיבים לתלות, ואז משתמשים בפלאגין Maven Dependency כדי להעתיק את התלות.
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteReleases>false</overWriteReleases>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>${project.build.directory}/deployment</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>${build.finalName}.jar</include>
<include>libs/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
יוצרים את קובץ ה-JAR הדק:
mvn package
לאחר מכן מבצעים פריסה באמצעות הפקודה הבאה:
gcloud functions deploy jar-example \
--entry-point=Example \
--no-gen2 \
--runtime=java17 \
--trigger-http \
--source=target/deployment
Gradle
מעדכנים את קובץ הפרויקט build.gradle כדי להוסיף משימה חדשה לאחזור התלויות:
dependencies {
// API available at compilation only, but provided at runtime
compileOnly 'com.google.cloud.functions:functions-framework-api:1.0.1'
// dependencies needed by the function
// ...
}
jar {
manifest {
attributes(
"Class-Path": provider {
configurations.runtimeClasspath
.collect { "libs/${it.name}" }.join(' ')
}
)
}
}
task prepareDeployment(type: Copy) {
into("${buildDir}/deployment")
into('.') {
from jar
}
into('libs') {
from configurations.runtimeClasspath
}
}