1. بررسی اجمالی
در اولین آزمایشگاه کد، تصاویر را در یک سطل ذخیره خواهید کرد. این یک رویداد ایجاد فایل ایجاد می کند که توسط یک سرویس مستقر در Cloud Run مدیریت می شود. این سرویس با Vision API تماس می گیرد تا تجزیه و تحلیل تصویر را انجام دهد و نتایج را در یک دیتا استور ذخیره کند.
چیزی که یاد خواهید گرفت
- فضای ذخیره سازی ابری
- Cloud Run
- Cloud Vision API
- Cloud Firestore
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به Google Cloud Console وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .
- نام پروژه نام نمایشی برای شرکت کنندگان این پروژه است. این یک رشته کاراکتری است که توسط API های Google استفاده نمی شود. همیشه می توانید آن را به روز کنید.
- شناسه پروژه در تمام پروژههای Google Cloud منحصربهفرد است و تغییرناپذیر است (پس از تنظیم نمیتوان آن را تغییر داد). Cloud Console به طور خودکار یک رشته منحصر به فرد تولید می کند. معمولاً برای شما مهم نیست که چیست. در اکثر کدها، باید شناسه پروژه خود را ارجاع دهید (معمولاً با نام
PROJECT_ID
شناخته می شود). اگر شناسه تولید شده را دوست ندارید، ممکن است یک شناسه تصادفی دیگر ایجاد کنید. از طرف دیگر، میتوانید خودتان را امتحان کنید، و ببینید آیا در دسترس است یا خیر. پس از این مرحله نمی توان آن را تغییر داد و در طول مدت پروژه باقی می ماند. - برای اطلاع شما، یک مقدار سوم وجود دارد، یک شماره پروژه ، که برخی از API ها از آن استفاده می کنند. در مورد هر سه این مقادیر در مستندات بیشتر بیاموزید.
- در مرحله بعد، برای استفاده از منابع Cloud/APIها باید صورتحساب را در کنسول Cloud فعال کنید . اجرا کردن از طریق این کد لبه هزینه زیادی نخواهد داشت. برای خاموش کردن منابع برای جلوگیری از تحمیل صورتحساب فراتر از این آموزش، میتوانید منابعی را که ایجاد کردهاید حذف کنید یا پروژه را حذف کنید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
Cloud Shell را راه اندازی کنید
در حالی که Google Cloud را می توان از راه دور از لپ تاپ شما کار کرد، در این کد لبه از Google Cloud Shell استفاده خواهید کرد، یک محیط خط فرمان که در Cloud اجرا می شود.
از Google Cloud Console ، روی نماد Cloud Shell در نوار ابزار بالا سمت راست کلیک کنید:
تهیه و اتصال به محیط فقط چند لحظه طول می کشد. وقتی تمام شد، باید چیزی شبیه به این را ببینید:
این ماشین مجازی با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این یک فهرست اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد و احراز هویت شبکه را تا حد زیادی افزایش می دهد. تمام کارهای شما در این کد لبه را می توان در یک مرورگر انجام داد. شما نیازی به نصب چیزی ندارید.
3. API ها را فعال کنید
برای این آزمایشگاه، از Cloud Functions و Vision API استفاده خواهید کرد، اما ابتدا باید آنها را یا در Cloud Console یا با gcloud
فعال کنید.
برای فعال کردن Vision API در Cloud Console، Cloud Vision API
را در نوار جستجو جستجو کنید:
شما در صفحه Cloud Vision API قرار خواهید گرفت:
روی دکمه ENABLE
کلیک کنید.
همچنین میتوانید با استفاده از ابزار خط فرمان gcloud آن را فعال کنید.
در داخل Cloud Shell، دستور زیر را اجرا کنید:
gcloud services enable vision.googleapis.com
برای اتمام موفقیت آمیز باید عملیات را مشاهده کنید:
Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.
Cloud Run و Cloud Build را نیز فعال کنید:
gcloud services enable cloudbuild.googleapis.com \ run.googleapis.com
4. ایجاد سطل (کنسول)
یک سطل ذخیره سازی برای تصاویر ایجاد کنید. می توانید این کار را از کنسول Google Cloud Platform ( consol.cloud.google.com ) یا با ابزار خط فرمان gsutil از Cloud Shell یا محیط توسعه محلی خود انجام دهید.
به Storage بروید
از منوی "همبرگر" (☰)، به صفحه Storage
بروید.
سطل خود را نام ببرید
روی دکمه CREATE BUCKET
کلیک کنید.
CONTINUE
کلیک کنید.
مکان را انتخاب کنید
یک سطل چند منطقه ای در منطقه مورد نظر خود ایجاد کنید (اینجا Europe
).
CONTINUE
کلیک کنید.
کلاس ذخیره سازی پیش فرض را انتخاب کنید
کلاس ذخیره سازی Standard
را برای داده های خود انتخاب کنید.
CONTINUE
کلیک کنید.
کنترل دسترسی را تنظیم کنید
از آنجایی که با تصاویر در دسترس عموم کار می کنید، می خواهید همه تصاویر ذخیره شده ما در این سطل کنترل دسترسی یکسانی داشته باشند.
گزینه Uniform
Access Control را انتخاب کنید.
CONTINUE
کلیک کنید.
حفاظت/رمزگذاری را تنظیم کنید
پیش فرض ( Google-managed key)
را حفظ کنید، زیرا از کلیدهای رمزگذاری خود استفاده نخواهید کرد.
روی CREATE
کلیک کنید تا در نهایت ایجاد سطل ما نهایی شود.
allUsers را به عنوان نمایشگر ذخیره سازی اضافه کنید
به برگه Permissions
بروید:
یک عضو allUsers
را با نقش Storage > Storage Object Viewer
به سطل اضافه کنید:
روی SAVE
کلیک کنید.
5. سطل (gsutil) را ایجاد کنید
همچنین می توانید از ابزار خط فرمان gsutil
در Cloud Shell برای ایجاد سطل استفاده کنید.
در Cloud Shell، یک متغیر برای نام سطل یکتا تنظیم کنید. Cloud Shell قبلاً GOOGLE_CLOUD_PROJECT
را روی شناسه پروژه منحصر به فرد شما تنظیم کرده است. می توانید آن را به نام سطل اضافه کنید.
به عنوان مثال:
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
ایجاد یک منطقه استاندارد چند منطقه ای در اروپا:
gsutil mb -l EU gs://${BUCKET_PICTURES}
از دسترسی یکنواخت به سطح سطل اطمینان حاصل کنید:
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
سطل را عمومی کنید:
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}
اگر به بخش Cloud Storage
کنسول بروید، باید یک سطل uploaded-pictures
عمومی داشته باشید:
تست کنید که می توانید تصاویر را در سطل آپلود کنید و تصاویر آپلود شده برای عموم در دسترس هستند، همانطور که در مرحله قبل توضیح داده شد.
6. دسترسی عمومی به سطل را آزمایش کنید
با بازگشت به مرورگر ذخیره سازی، سطل خود را با دسترسی «عمومی» (شامل یک علامت هشدار که به شما یادآوری می کند که هر کسی به محتوای آن سطل دسترسی دارد) را در لیست می بینید.
اکنون سطل شما برای دریافت تصاویر آماده است.
اگر روی نام سطل کلیک کنید، جزئیات سطل را مشاهده خواهید کرد.
در آنجا، میتوانید دکمه Upload files
را امتحان کنید تا آزمایش کنید که میتوانید تصویری را به سطل اضافه کنید. یک پنجره انتخابگر فایل از شما می خواهد که یک فایل را انتخاب کنید. پس از انتخاب، در سطل شما آپلود می شود و دوباره دسترسی public
را که به طور خودکار به این فایل جدید نسبت داده شده است، خواهید دید.
در کنار برچسب دسترسی Public
، نماد پیوند کوچکی را نیز مشاهده خواهید کرد. وقتی روی آن کلیک می کنید، مرورگر شما به آدرس عمومی آن تصویر می رود که به شکل زیر خواهد بود:
https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png
با BUCKET_NAME
نام منحصربهفرد جهانی است که برای سطل خود انتخاب کردهاید، و سپس نام فایل تصویرتان.
با کلیک بر روی کادر کنار نام تصویر، دکمه DELETE
فعال می شود و می توانید این تصویر اول را حذف کنید.
7. پایگاه داده را آماده کنید
شما اطلاعات مربوط به تصویر ارائه شده توسط Vision API را در پایگاه داده Cloud Firestore ، یک پایگاه داده اسناد NoSQL سریع، کاملا مدیریت شده، بدون سرور و بومی ابری ذخیره خواهید کرد. با رفتن به بخش Firestore
در Cloud Console پایگاه داده خود را آماده کنید:
دو گزینه ارائه می شود: Native mode
یا Datastore mode
. از حالت بومی استفاده کنید، که ویژگیهای اضافی مانند پشتیبانی آفلاین و همگامسازی بلادرنگ را ارائه میدهد.
روی SELECT NATIVE MODE
کلیک کنید.
یک منطقه چندگانه (اینجا در اروپا، اما در حالت ایده آل حداقل همان منطقه ای که عملکرد و سطل ذخیره سازی شما هستند) انتخاب کنید.
روی دکمه CREATE DATABASE
کلیک کنید.
پس از ایجاد پایگاه داده، باید موارد زیر را مشاهده کنید:
با کلیک بر روی دکمه + START COLLECTION
یک مجموعه جدید ایجاد کنید.
pictures
مجموعه نام .
شما نیازی به ایجاد سند ندارید. وقتی تصاویر جدید در Cloud Storage ذخیره می شوند و توسط Vision API تجزیه و تحلیل می شوند، آنها را به صورت برنامه نویسی اضافه خواهید کرد.
روی Save
کلیک کنید.
Firestore اولین سند پیش فرض را در مجموعه جدید ایجاد می کند، می توانید با خیال راحت آن سند را حذف کنید زیرا حاوی اطلاعات مفیدی نیست:
اسنادی که به صورت برنامه نویسی در مجموعه ما ایجاد می شوند دارای 4 فیلد خواهند بود:
- نام (رشته): نام فایل تصویر آپلود شده که کلید سند نیز می باشد
- برچسب ها (آرایه رشته ها): برچسب های موارد شناسایی شده توسط Vision API
- رنگ (رشته): کد رنگ هگزادسیمال رنگ غالب (یعنی #ab12ef)
- ایجاد (تاریخ): مُهر زمانی ذخیره شدن فراداده این تصویر
- تصویر بندانگشتی (بولی): یک فیلد اختیاری که در صورت ایجاد یک تصویر کوچک برای این تصویر وجود دارد و درست است.
از آنجایی که در Firestore برای یافتن تصاویری که دارای ریز عکسها هستند جستجو میکنیم و بر اساس تاریخ ایجاد مرتب میکنیم، باید یک فهرست جستجو ایجاد کنیم.
می توانید با دستور زیر در Cloud Shell ایندکس را ایجاد کنید:
gcloud firestore indexes composite create \
--collection-group=pictures \
--field-config field-path=thumbnail,order=descending \
--field-config field-path=created,order=descending
یا میتوانید این کار را از کنسول Cloud انجام دهید، با کلیک بر روی Indexes
، در ستون پیمایش در سمت چپ، و سپس ایجاد یک نمایه ترکیبی مانند شکل زیر:
روی Create
کلیک کنید. ایجاد فهرست ممکن است چند دقیقه طول بکشد.
8. کد را شبیه سازی کنید
اگر قبلاً در آزمایشگاه کد قبلی نبوده اید، کد را شبیه سازی کنید:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
سپس می توانید برای شروع ساخت آزمایشگاه به دایرکتوری حاوی سرویس بروید:
cd serverless-photosharing-workshop/services/image-analysis/java
شما طرح بندی فایل زیر را برای سرویس خواهید داشت:
9. کد سرویس را کاوش کنید
شما با نگاهی به نحوه فعال شدن کتابخانه های کلاینت جاوا در pom.xml
با استفاده از یک BOM شروع می کنید:
ابتدا فایل pom.xml
را باز کنید که وابستگی های برنامه جاوا ما را فهرست می کند. تمرکز بر روی استفاده از Vision، Cloud Storage و Firestore API است
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0-M3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>services</groupId>
<artifactId>image-analysis</artifactId>
<version>0.0.1</version>
<name>image-analysis</name>
<description>Spring App for Image Analysis</description>
<properties>
<java.version>17</java.version>
<maven.compiler.target>17</maven.compiler.target>
<maven.compiler.source>17</maven.compiler.source>
<spring-cloud.version>2023.0.0-M2</spring-cloud.version>
<testcontainers.version>1.19.1</testcontainers.version>
</properties>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.24.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
—
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud.functions</groupId>
<artifactId>functions-framework-api</artifactId>
<version>1.1.0</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-firestore</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-vision</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-storage</artifactId>
</dependency>
این عملکرد در کلاس EventController
پیاده سازی شده است. هر بار که یک تصویر جدید در سطل آپلود می شود، سرویس اعلانی برای پردازش دریافت می کند:
@RestController
public class EventController {
private static final Logger logger = Logger.getLogger(EventController.class.getName());
private static final List<String> requiredFields = Arrays.asList("ce-id", "ce-source", "ce-type", "ce-specversion");
@RequestMapping(value = "/", method = RequestMethod.POST)
public ResponseEntity<String> receiveMessage(
@RequestBody Map<String, Object> body, @RequestHeader Map<String, String> headers) throws IOException, InterruptedException, ExecutionException {
...
}
کد به اعتبار سنجی سرصفحه های Cloud Events
ادامه می دهد:
System.out.println("Header elements");
for (String field : requiredFields) {
if (headers.get(field) == null) {
String msg = String.format("Missing expected header: %s.", field);
System.out.println(msg);
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
} else {
System.out.println(field + " : " + headers.get(field));
}
}
System.out.println("Body elements");
for (String bodyField : body.keySet()) {
System.out.println(bodyField + " : " + body.get(bodyField));
}
if (headers.get("ce-subject") == null) {
String msg = "Missing expected header: ce-subject.";
System.out.println(msg);
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
اکنون می توان یک درخواست ایجاد کرد و کد یکی از این درخواست ها را برای ارسال به Vision API
آماده می کند:
try (ImageAnnotatorClient vision = ImageAnnotatorClient.create()) {
List<AnnotateImageRequest> requests = new ArrayList<>();
ImageSource imageSource = ImageSource.newBuilder()
.setGcsImageUri("gs://" + bucketName + "/" + fileName)
.build();
Image image = Image.newBuilder()
.setSource(imageSource)
.build();
Feature featureLabel = Feature.newBuilder()
.setType(Type.LABEL_DETECTION)
.build();
Feature featureImageProps = Feature.newBuilder()
.setType(Type.IMAGE_PROPERTIES)
.build();
Feature featureSafeSearch = Feature.newBuilder()
.setType(Type.SAFE_SEARCH_DETECTION)
.build();
AnnotateImageRequest request = AnnotateImageRequest.newBuilder()
.addFeatures(featureLabel)
.addFeatures(featureImageProps)
.addFeatures(featureSafeSearch)
.setImage(image)
.build();
requests.add(request);
ما 3 قابلیت کلیدی Vision API را درخواست می کنیم:
- تشخیص برچسب : برای درک آنچه در آن تصاویر وجود دارد
- ویژگی های تصویر : برای دادن ویژگی های جالب به تصویر (ما به رنگ غالب تصویر علاقه مند هستیم)
- جستجوی ایمن : برای اطلاع از اینکه آیا تصویر برای نمایش بی خطر است (این تصویر نباید حاوی محتوای بزرگسالان / پزشکی / نژادی / خشونت آمیز باشد)
در این مرحله، میتوانیم با Vision API تماس بگیریم:
...
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result = vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
...
برای مرجع، در اینجا پاسخ از Vision API به نظر می رسد:
{
"faceAnnotations": [],
"landmarkAnnotations": [],
"logoAnnotations": [],
"labelAnnotations": [
{
"locations": [],
"properties": [],
"mid": "/m/01yrx",
"locale": "",
"description": "Cat",
"score": 0.9959855675697327,
"confidence": 0,
"topicality": 0.9959855675697327,
"boundingPoly": null
},
✄ - - - ✄
],
"textAnnotations": [],
"localizedObjectAnnotations": [],
"safeSearchAnnotation": {
"adult": "VERY_UNLIKELY",
"spoof": "UNLIKELY",
"medical": "VERY_UNLIKELY",
"violence": "VERY_UNLIKELY",
"racy": "VERY_UNLIKELY",
"adultConfidence": 0,
"spoofConfidence": 0,
"medicalConfidence": 0,
"violenceConfidence": 0,
"racyConfidence": 0,
"nsfwConfidence": 0
},
"imagePropertiesAnnotation": {
"dominantColors": {
"colors": [
{
"color": {
"red": 203,
"green": 201,
"blue": 201,
"alpha": null
},
"score": 0.4175916016101837,
"pixelFraction": 0.44456374645233154
},
✄ - - - ✄
]
}
},
"error": null,
"cropHintsAnnotation": {
"cropHints": [
{
"boundingPoly": {
"vertices": [
{ "x": 0, "y": 118 },
{ "x": 1177, "y": 118 },
{ "x": 1177, "y": 783 },
{ "x": 0, "y": 783 }
],
"normalizedVertices": []
},
"confidence": 0.41695669293403625,
"importanceFraction": 1
}
]
},
"fullTextAnnotation": null,
"webDetection": null,
"productSearchResults": null,
"context": null
}
اگر خطایی برگردانده نشد، میتوانیم ادامه دهیم، به همین دلیل این بلوک را داریم:
if (responses.size() == 0) {
logger.info("No response received from Vision API.");
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
AnnotateImageResponse response = responses.get(0);
if (response.hasError()) {
logger.info("Error: " + response.getError().getMessage());
return new ResponseEntity<String>(msg, HttpStatus.BAD_REQUEST);
}
ما میخواهیم برچسبهای چیزها، دستهها یا مضامین شناسایی شده در تصویر را دریافت کنیم:
List<String> labels = response.getLabelAnnotationsList().stream()
.map(annotation -> annotation.getDescription())
.collect(Collectors.toList());
logger.info("Annotations found:");
for (String label: labels) {
logger.info("- " + label);
}
ما علاقه مندیم که رنگ غالب تصویر را بدانیم:
String mainColor = "#FFFFFF";
ImageProperties imgProps = response.getImagePropertiesAnnotation();
if (imgProps.hasDominantColors()) {
DominantColorsAnnotation colorsAnn = imgProps.getDominantColors();
ColorInfo colorInfo = colorsAnn.getColors(0);
mainColor = rgbHex(
colorInfo.getColor().getRed(),
colorInfo.getColor().getGreen(),
colorInfo.getColor().getBlue());
logger.info("Color: " + mainColor);
}
بیایید بررسی کنیم که آیا تصویر برای نمایش امن است یا خیر:
boolean isSafe = false;
if (response.hasSafeSearchAnnotation()) {
SafeSearchAnnotation safeSearch = response.getSafeSearchAnnotation();
isSafe = Stream.of(
safeSearch.getAdult(), safeSearch.getMedical(), safeSearch.getRacy(),
safeSearch.getSpoof(), safeSearch.getViolence())
.allMatch( likelihood ->
likelihood != Likelihood.LIKELY && likelihood != Likelihood.VERY_LIKELY
);
logger.info("Safe? " + isSafe);
}
ما در حال بررسی ویژگی های بزرگسالان / جعل / پزشکی / خشونت / نژادپرستانه هستیم تا ببینیم که آیا محتمل یا بسیار محتمل هستند .
اگر نتیجه جستجوی ایمن درست باشد، میتوانیم متادیتا را در Firestore ذخیره کنیم:
// Saving result to Firestore
if (isSafe) {
ApiFuture<WriteResult> writeResult =
eventService.storeImage(fileName, labels,
mainColor);
logger.info("Picture metadata saved in Firestore at " +
writeResult.get().getUpdateTime());
}
...
public ApiFuture<WriteResult> storeImage(String fileName,
List<String> labels,
String mainColor) {
FirestoreOptions firestoreOptions = FirestoreOptions.getDefaultInstance();
Firestore pictureStore = firestoreOptions.getService();
DocumentReference doc = pictureStore.collection("pictures").document(fileName);
Map<String, Object> data = new HashMap<>();
data.put("labels", labels);
data.put("color", mainColor);
data.put("created", new Date());
return doc.set(data, SetOptions.merge());
}
10. با GraalVM تصاویر برنامه بسازید
در این مرحله اختیاری، با استفاده از GraalVM یک JIT based app image
و سپس یک Native Java app image
ایجاد میکنید.
برای اجرای بیلد، باید مطمئن شوید که یک JDK مناسب و سازنده تصویر native نصب و پیکربندی شده است. چندین گزینه در دسترس است.
To start
، GraalVM 22.3.x Community Edition را دانلود کنید و دستورالعمل های صفحه نصب GraalVM را دنبال کنید.
این فرآیند را می توان تا حد زیادی با کمک SDKMAN ساده کرد!
برای نصب توزیع JDK مناسب با SDKman
، با استفاده از دستور install شروع کنید:
sdk install java 17.0.8-graal
به SDKman دستور دهید از این نسخه برای ساخت JIT و AOT استفاده کند:
sdk use java 17.0.8-graal
در Cloudshell
، برای راحتی شما، می توانید GraalVM و ابزار native-image را با این دستورات ساده نصب کنید:
# download GraalVM wget https://download.oracle.com/graalvm/17/latest/graalvm-jdk-17_linux-x64_bin.tar.gz tar -xzf graalvm-jdk-17_linux-x64_bin.tar.gz ls -lart # configure Java 17 and GraalVM for Java 17 # note the name of the latest GraalVM version, as unpacked by the tar command echo Existing JVM: $JAVA_HOME cd graalvm-jdk-17.0.8+9.1 export JAVA_HOME=$PWD cd bin export PATH=$PWD:$PATH echo JAVA HOME: $JAVA_HOME echo PATH: $PATH cd ../.. # validate the version with java -version # observe Java(TM) SE Runtime Environment Oracle GraalVM 17.0.8+9.1 (build 17.0.8+9-LTS-jvmci-23.0-b14) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 17.0.8+9.1 (build 17.0.8+9-LTS-jvmci-23.0-b14, mixed mode, sharing)
ابتدا متغیرهای محیط پروژه GCP را تنظیم کنید:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
سپس می توانید برای شروع ساخت آزمایشگاه به دایرکتوری حاوی سرویس بروید:
cd serverless-photosharing-workshop/services/image-analysis/java
تصویر برنامه JIT را بسازید:
./mvnw package
گزارش ساخت را در ترمینال مشاهده کنید:
... [INFO] Results: [INFO] [INFO] Tests run: 6, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] [INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ image-analysis --- [INFO] Building jar: /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar [INFO] [INFO] --- spring-boot-maven-plugin:3.2.0-M3:repackage (repackage) @ image-analysis --- [INFO] Replacing main artifact /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar with repackaged archive, adding nested dependencies in BOOT-INF/. [INFO] The original artifact has been renamed to /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis-0.0.1.jar.original [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.335 s [INFO] Finished at: 2023-10-10T19:33:25Z [INFO] ------------------------------------------------------------------------
تصویر Native را بسازید (از AOT استفاده می کند):
./mvnw native:compile -Pnative
گزارش ساخت را در ترمینال مشاهده کنید، از جمله گزارشهای ساخت تصویر بومی:
توجه داشته باشید که ساخت، بسته به دستگاهی که روی آن آزمایش می کنید، کمی بیشتر طول می کشد.
... [2/7] Performing analysis... [*********] (124.5s @ 4.53GB) 29,732 (93.19%) of 31,905 classes reachable 60,161 (70.30%) of 85,577 fields reachable 261,973 (67.29%) of 389,319 methods reachable 2,940 classes, 2,297 fields, and 97,421 methods registered for reflection 81 classes, 90 fields, and 62 methods registered for JNI access 4 native libraries: dl, pthread, rt, z [3/7] Building universe... (11.7s @ 4.67GB) [4/7] Parsing methods... [***] (6.1s @ 5.91GB) [5/7] Inlining methods... [****] (4.5s @ 4.39GB) [6/7] Compiling methods... [******] (35.3s @ 4.60GB) [7/7] Creating image... (12.9s @ 4.61GB) 80.08MB (47.43%) for code area: 190,483 compilation units 73.81MB (43.72%) for image heap: 660,125 objects and 189 resources 14.95MB ( 8.86%) for other data 168.84MB in total ------------------------------------------------------------------------------------------------------------------------ Top 10 packages in code area: Top 10 object types in image heap: 2.66MB com.google.cloud.vision.v1p4beta1 18.51MB byte[] for code metadata 2.60MB com.google.cloud.vision.v1 9.27MB java.lang.Class 2.49MB com.google.protobuf 7.34MB byte[] for reflection metadata 2.40MB com.google.cloud.vision.v1p3beta1 6.35MB byte[] for java.lang.String 2.17MB com.google.storage.v2 5.72MB java.lang.String 2.12MB com.google.firestore.v1 4.46MB byte[] for embedded resources 1.64MB sun.security.ssl 4.30MB c.oracle.svm.core.reflect.SubstrateMethodAccessor 1.51MB i.g.xds.shaded.io.envoyproxy.envoy.config.core.v3 4.27MB byte[] for general heap data 1.47MB com.google.cloud.vision.v1p2beta1 2.50MB com.oracle.svm.core.hub.DynamicHubCompanion 1.34MB i.g.x.shaded.io.envoyproxy.envoy.config.route.v3 1.17MB java.lang.Object[] 58.34MB for 977 more packages 9.19MB for 4667 more object types ------------------------------------------------------------------------------------------------------------------------ 13.5s (5.7% of total time) in 75 GCs | Peak RSS: 9.44GB | CPU load: 6.13 ------------------------------------------------------------------------------------------------------------------------ Produced artifacts: /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis (executable) /home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis.build_artifacts.txt (txt) ======================================================================================================================== Finished generating '/home/user/serverless-photosharing-workshop/services/image-analysis/java/target/image-analysis' in 3m 57s. [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 04:28 min [INFO] Finished at: 2023-10-10T19:53:30Z [INFO] ------------------------------------------------------------------------
11. ساخت و انتشار تصاویر کانتینر
بیایید یک تصویر ظرف در دو نسخه مختلف بسازیم: یکی به عنوان یک JIT image
و دیگری به عنوان یک Native Java image
.
ابتدا متغیرهای محیط پروژه GCP را تنظیم کنید:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
ساخت تصویر JIT:.
./mvnw spring-boot:build-image -Pji
گزارش ساخت را در ترمینال مشاهده کنید:
[INFO] [creator] Timer: Saving docker.io/library/image-analysis-maven-jit:latest... started at 2023-10-10T20:00:31Z [INFO] [creator] *** Images (4c84122a1826): [INFO] [creator] docker.io/library/image-analysis-maven-jit:latest [INFO] [creator] Timer: Saving docker.io/library/image-analysis-maven-jit:latest... ran for 6.975913605s and ended at 2023-10-10T20:00:38Z [INFO] [creator] Timer: Exporter ran for 8.068588001s and ended at 2023-10-10T20:00:38Z [INFO] [creator] Timer: Cache started at 2023-10-10T20:00:38Z [INFO] [creator] Reusing cache layer 'paketo-buildpacks/syft:syft' [INFO] [creator] Adding cache layer 'buildpacksio/lifecycle:cache.sbom' [INFO] [creator] Timer: Cache ran for 200.449002ms and ended at 2023-10-10T20:00:38Z [INFO] [INFO] Successfully built image 'docker.io/library/image-analysis-maven-jit:latest' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 43.887 s [INFO] Finished at: 2023-10-10T20:00:39Z [INFO] ------------------------------------------------------------------------
تصویر AOT (Native) را بسازید:.
./mvnw spring-boot:build-image -Pnative
گزارش ساخت را در ترمینال مشاهده کنید، از جمله گزارشهای ساخت تصویر بومی.
توجه:
- که بسته به دستگاهی که روی آن تست می کنید، ساخت کمی بیشتر طول می کشد
- تصاویر را می توان بیشتر با UPX فشرده کرد، با این حال تأثیر منفی کوچکی بر عملکرد راه اندازی دارد، بنابراین این ساخت از UPX استفاده نمی کند - همیشه یک مبادله جزئی است.
... [INFO] [creator] Saving docker.io/library/image-analysis-maven-native:latest... [INFO] [creator] *** Images (13167702674e): [INFO] [creator] docker.io/library/image-analysis-maven-native:latest [INFO] [creator] Adding cache layer 'paketo-buildpacks/bellsoft-liberica:native-image-svm' [INFO] [creator] Adding cache layer 'paketo-buildpacks/syft:syft' [INFO] [creator] Adding cache layer 'paketo-buildpacks/native-image:native-image' [INFO] [creator] Adding cache layer 'buildpacksio/lifecycle:cache.sbom' [INFO] [INFO] Successfully built image 'docker.io/library/image-analysis-maven-native:latest' [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 03:37 min [INFO] Finished at: 2023-10-10T20:05:16Z [INFO] ------------------------------------------------------------------------
تأیید کنید که تصاویر ساخته شده اند:
docker images | grep image-analysis
دو تصویر را تگ کنید و به GCR فشار دهید:
# JIT image docker tag image-analysis-maven-jit gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit # Native(AOT) image docker tag image-analysis-maven-native gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native docker push gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native
12. در Cloud Run مستقر شوید
زمان استقرار سرویس است.
شما دو بار سرویس را مستقر خواهید کرد، یک بار با استفاده از تصویر JIT و بار دوم با استفاده از تصویر AOT (Native). هر دو استقرار سرویس، برای مقاصد مقایسه، تصویر یکسانی را از سطل به صورت موازی پردازش خواهند کرد.
ابتدا متغیرهای محیط پروژه GCP را تنظیم کنید:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) gcloud config set project ${GOOGLE_CLOUD_PROJECT} gcloud config set run/region gcloud config set run/platform managed gcloud config set eventarc/location europe-west1
تصویر JIT را اجرا کنید و گزارش استقرار را در کنسول مشاهده کنید:
gcloud run deploy image-analysis-jit \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-jit \ --region europe-west1 \ --memory 2Gi --allow-unauthenticated ... Deploying container to Cloud Run service [image-analysis-jit] in project [...] region [europe-west1] ✓ Deploying... Done. ✓ Creating Revision... ✓ Routing traffic... ✓ Setting IAM Policy... Done. Service [image-analysis-jit] revision [image-analysis-jvm-00009-huc] has been deployed and is serving 100 percent of traffic. Service URL: https://image-analysis-jit-...-ew.a.run.app
تصویر Native را اجرا کنید و گزارش استقرار را در کنسول مشاهده کنید:
gcloud run deploy image-analysis-native \ --image gcr.io/${GOOGLE_CLOUD_PROJECT}/image-analysis-maven-native \ --region europe-west1 \ --memory 2Gi --allow-unauthenticated ... Deploying container to Cloud Run service [image-analysis-native] in project [...] region [europe-west1] ✓ Deploying... Done. ✓ Creating Revision... ✓ Routing traffic... ✓ Setting IAM Policy... Done. Service [image-analysis-native] revision [image-analysis-native-00005-ben] has been deployed and is serving 100 percent of traffic. Service URL: https://image-analysis-native-...-ew.a.run.app
13. Eventarc Triggers را راه اندازی کنید
Eventarc یک راه حل استاندارد برای مدیریت جریان تغییرات حالت، به نام رویدادها، بین میکروسرویس های جدا شده ارائه می دهد. هنگامی که فعال میشود، Eventarc این رویدادها را از طریق اشتراکهای Pub/Sub به مقصدهای مختلف هدایت میکند (در این سند، به مقصد رویداد مراجعه کنید) در حالی که تحویل، امنیت، مجوز، قابلیت مشاهده و مدیریت خطا را برای شما مدیریت میکند.
میتوانید یک راهانداز Eventarc ایجاد کنید تا سرویس Cloud Run شما اعلانهای یک رویداد یا مجموعهای از رویدادها را دریافت کند. با تعیین فیلترها برای تریگر، میتوانید مسیریابی رویداد، از جمله منبع رویداد و سرویس Cloud Run را پیکربندی کنید.
ابتدا متغیرهای محیط پروژه GCP را تنظیم کنید:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project) gcloud config set project ${GOOGLE_CLOUD_PROJECT} gcloud config set run/region gcloud config set run/platform managed gcloud config set eventarc/location europe-west1
اعطای pubsub.publisher
به حساب سرویس Cloud Storage:
SERVICE_ACCOUNT="$(gsutil kms serviceaccount -p ${GOOGLE_CLOUD_PROJECT})" gcloud projects add-iam-policy-binding ${GOOGLE_CLOUD_PROJECT} \ --member="serviceAccount:${SERVICE_ACCOUNT}" \ --role='roles/pubsub.publisher'
راهاندازهای Eventarc را برای تصاویر سرویس JIT و Native برای پردازش تصویر تنظیم کنید:
gcloud eventarc triggers list --location=eu gcloud eventarc triggers create image-analysis-jit-trigger \ --destination-run-service=image-analysis-jit \ --destination-run-region=europe-west1 \ --location=eu \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}" \ --service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com gcloud eventarc triggers create image-analysis-native-trigger \ --destination-run-service=image-analysis-native \ --destination-run-region=europe-west1 \ --location=eu \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}" \ --service-account=${PROJECT_NUMBER}-compute@developer.gserviceaccount.com
توجه داشته باشید که دو محرک ایجاد شده اند:
gcloud eventarc triggers list --location=eu
14. نسخه های سرویس تست
پس از اجرای موفقیت آمیز سرویس، تصویری را در Cloud Storage پست میکنید، ببینید آیا خدمات ما فراخوانی شدهاند، Vision API چه چیزی را برمیگرداند، و آیا ابرداده در Firestore ذخیره میشود.
به Cloud Storage
برگردید و روی سطلی که در ابتدای آزمایشگاه ایجاد کردیم کلیک کنید:
پس از ورود به صفحه جزئیات سطل، روی دکمه Upload files
کلیک کنید تا یک عکس آپلود شود.
به عنوان مثال، یک تصویر GeekHour.jpeg
به همراه پایگاه کد شما در زیر /services/image-analysis/java
ارائه می شود. یک تصویر را انتخاب کنید و Open button
فشار دهید:
اکنون میتوانید اجرای سرویس را بررسی کنید، با image-analysis-jit
و سپس image-analysis-native
شروع کنید.
از منوی "همبرگر" (☰)، به Cloud Run > image-analysis-jit
بروید.
روی Logs کلیک کنید و خروجی را مشاهده کنید:
و در واقع، در لیست لاگ ها، می توانم ببینم که سرویس JIT image-analysis-jit
فراخوانی شده است.
گزارش ها شروع و پایان اجرای سرویس را نشان می دهد. و در این بین، ما میتوانیم گزارشهایی را که در تابع خود قرار میدهیم با دستورات log در سطح INFO ببینیم. می بینیم:
- جزئیات رویدادی که عملکرد ما را تحریک می کند،
- نتایج خام از فراخوانی Vision API،
- برچسب هایی که در تصویری که آپلود کردیم یافت شد،
- اطلاعات رنگ های غالب،
- اینکه آیا تصویر برای نشان دادن بی خطر است،
- و در نهایت آن ابرداده های مربوط به تصویر در Firestore ذخیره شده است.
شما این فرآیند را برای سرویس image-analysis-native
تکرار خواهید کرد.
از منوی "همبرگر" (☰)، به Cloud Run > image-analysis-native
سرویس بروید.
روی Logs کلیک کنید و خروجی را مشاهده کنید:
اکنون می خواهید مشاهده کنید که آیا فراداده تصویر در Fiorestore ذخیره شده است یا خیر.
دوباره از منوی "همبرگر" (☰)، به بخش Firestore
بروید. در زیر بخش Data
(به طور پیش فرض نشان داده شده است)، باید مجموعه pictures
را با یک سند جدید اضافه کنید، مطابق با تصویری که اخیراً آپلود کرده اید:
15. تمیز کردن (اختیاری)
اگر قصد ندارید با دیگر آزمایشگاههای این سری ادامه دهید، میتوانید منابع را پاکسازی کنید تا در هزینهها صرفهجویی کنید و در کل شهروند ابری خوبی باشید. می توانید منابع را به صورت جداگانه به صورت زیر پاک کنید.
سطل را حذف کنید:
gsutil rb gs://${BUCKET_PICTURES}
حذف تابع:
gcloud functions delete picture-uploaded --region europe-west1 -q
با انتخاب حذف مجموعه از مجموعه، مجموعه Firestore را حذف کنید:
یا می توانید کل پروژه را حذف کنید:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
16. تبریک می گویم!
تبریک می گویم! شما اولین سرویس کلیدی پروژه را با موفقیت اجرا کردید!
آنچه را پوشش داده ایم
- فضای ذخیره سازی ابری
- Cloud Run
- Cloud Vision API
- Cloud Firestore
- تصاویر بومی جاوا