1. Genel Bakış
İlk kod laboratuvarında resimleri bir pakette depolayacaksınız. Bu işlem, Cloud Run'da dağıtılan bir hizmet tarafından işlenecek bir dosya oluşturma etkinliği oluşturur. Hizmet, görüntü analizi yapmak ve sonuçları bir veri deposuna kaydetmek için Vision API'ye çağrı yapar.
Neler öğreneceksiniz?
- Cloud Storage
- Cloud Run
- Cloud Vision API
- Cloud Firestore
2. Kurulum ve Gereksinimler
Kendi hızınızda ortam kurulumu
- Google Cloud Console'da oturum açıp yeni bir proje oluşturun veya mevcut bir projeyi yeniden kullanın. Gmail veya Google Workspace hesabınız yoksa hesap oluşturmanız gerekir.
- Proje adı, bu projenin katılımcıları için görünen addır. Google API'leri tarafından kullanılmayan bir karakter dizesidir. İstediğiniz zaman güncelleyebilirsiniz.
- Proje Kimliği, tüm Google Cloud projelerinde benzersizdir ve değiştirilemez (belirlendikten sonra değiştirilemez). Cloud Console, otomatik olarak benzersiz bir dize oluşturur. bunun ne olduğunu umursamıyorsunuz. Çoğu codelab'de proje kimliğinizi (genellikle
PROJECT_ID
olarak tanımlanır) belirtmeniz gerekir. Oluşturulan kimliği beğenmezseniz rastgele bir kimlik daha oluşturabilirsiniz. Alternatif olarak, kendi ölçümünüzü deneyip mevcut olup olmadığına bakabilirsiniz. Bu adımdan sonra değiştirilemez ve proje süresince kalır. - Bilginiz olması açısından, bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
- Sonraki adımda, Cloud kaynaklarını/API'lerini kullanmak için Cloud Console'da faturalandırmayı etkinleştirmeniz gerekir. Bu codelab'i çalıştırmanın maliyeti, yüksek değildir. Bu eğitim dışında faturalandırmanın tekrarlanmasını önlemek amacıyla kaynakları kapatmak için oluşturduğunuz kaynakları silebilir veya projeyi silebilirsiniz. Yeni Google Cloud kullanıcıları 300 ABD doları değerindeki ücretsiz denemeden yararlanabilir.
Cloud Shell'i başlatma
Google Cloud dizüstü bilgisayarınızdan uzaktan çalıştırılabilse de bu codelab'de, Cloud'da çalışan bir komut satırı ortamı olan Google Cloud Shell'i kullanacaksınız.
Google Cloud Console'da, sağ üstteki araç çubuğunda bulunan Cloud Shell simgesini tıklayın:
Ortamı sağlamak ve bağlamak yalnızca birkaç dakika sürer. Tamamlandığında şuna benzer bir sonuç görmeniz gerekir:
İhtiyacınız olan tüm geliştirme araçlarını bu sanal makinede bulabilirsiniz. 5 GB boyutunda kalıcı bir ana dizin sunar ve Google Cloud üzerinde çalışarak ağ performansını ve kimlik doğrulamasını büyük ölçüde iyileştirir. Bu codelab'deki tüm çalışmalarınız tarayıcıda yapılabilir. Herhangi bir şey yüklemeniz gerekmez.
3. API'leri etkinleştir
Bu laboratuvarda Cloud Functions ve Vision API'yi kullanacaksınız ancak bunların önce Cloud Console'da veya gcloud
ile etkinleştirilmesi gerekir.
Cloud Console'da Vision API'yi etkinleştirmek için arama çubuğunda Cloud Vision API
ifadesini arayın:
Cloud Vision API sayfasına yönlendirilirsiniz:
ENABLE
düğmesini tıklayın.
Alternatif olarak, gcloud komut satırı aracını kullanarak Cloud Shell'i de etkinleştirebilirsiniz.
Cloud Shell'in içinde aşağıdaki komutu çalıştırın:
gcloud services enable vision.googleapis.com
İşlemin başarıyla tamamlandığını göreceksiniz:
Operation "operations/acf.12dba18b-106f-4fd2-942d-fea80ecc5c1c" finished successfully.
Cloud Run ve Cloud Build'i de etkinleştirin:
gcloud services enable cloudbuild.googleapis.com \ run.googleapis.com
4. Paketi oluşturma (konsol)
Resimler için bir depolama paketi oluşturun. Bu işlemi Google Cloud Platform konsolundan ( console.cloud.google.com) veya Cloud Shell'den ya da yerel geliştirme ortamınızdan gsutil komut satırı aracıyla yapabilirsiniz.
Depolama alanına git
"Hamburger"den (Gönder) menüsünden Storage
sayfasına gidin.
Paketinizi adlandırma
CREATE BUCKET
düğmesini tıklayın.
CONTINUE
simgesini tıklayın.
Konum Seçin
Seçtiğiniz bölgede çok bölgeli bir paket oluşturun (burada Europe
).
CONTINUE
simgesini tıklayın.
Varsayılan depolama sınıfını seçme
Verileriniz için Standard
depolama sınıfını seçin.
CONTINUE
simgesini tıklayın.
Erişim Denetimini Ayarlama
Herkesin erişebileceği görüntülerle çalışacağınız için bu pakette depolanan tüm resimlerimizin aynı tek tip erişim denetimine sahip olmasını istersiniz.
Uniform
erişim denetimi seçeneğini belirleyin.
CONTINUE
simgesini tıklayın.
Korumayı/Şifrelemeyi Ayarlama
Varsayılan değeri koruyun (Kendi şifreleme anahtarlarınızı kullanmayacağınız için Google-managed key)
.
Paket oluşturma işlemini tamamlamak için CREATE
düğmesini tıklayın.
allUsers'ı depolama alanı görüntüleyici olarak ekle
Permissions
sekmesine gidin:
Aşağıdaki gibi, Storage > Storage Object Viewer
rolüne sahip bir allUsers
üyesini pakete ekleyin:
SAVE
simgesini tıklayın.
5. Paket (gsutil) oluşturma
Paket oluşturmak için Cloud Shell'deki gsutil
komut satırı aracını da kullanabilirsiniz.
Cloud Shell'de benzersiz paket adı için bir değişken ayarlayın. Cloud Shell'de GOOGLE_CLOUD_PROJECT
, benzersiz proje kimliğinize zaten ayarlanmış. Bunu paket adına ekleyebilirsiniz.
Örneğin:
export BUCKET_PICTURES=uploaded-pictures-${GOOGLE_CLOUD_PROJECT}
Avrupa'da standart bir çok bölgeli alt bölge oluşturun:
gsutil mb -l EU gs://${BUCKET_PICTURES}
Tek tip paket düzeyinde erişim sağlayın:
gsutil uniformbucketlevelaccess set on gs://${BUCKET_PICTURES}
Paketi herkese açık hale getirin:
gsutil iam ch allUsers:objectViewer gs://${BUCKET_PICTURES}
Konsolun Cloud Storage
bölümüne giderseniz herkese açık bir uploaded-pictures
paketiniz olur:
Pakete resim yükleyemediğinizi ve yüklenen resimlerin önceki adımda açıklandığı gibi herkese açık olup olmadığını test edin.
6. Pakete herkese açık erişimi test etme
Depolama tarayıcısına geri döndüğünüzde, paketinizi listede "Herkese açık" olarak görürsünüz. (ilgili grubun içeriğine herhangi birinin erişimi olduğunu hatırlatan bir uyarı işareti dahil).
Paketiniz artık resim almaya hazır.
Paket adını tıklarsanız paket ayrıntılarını görürsünüz.
Buradan, pakete resim ekleyip ekleyebileceğinizi test etmek için Upload files
düğmesini deneyebilirsiniz. Dosya seçici pop-up'ında bir dosya seçmeniz istenir. Seçildikten sonra paketinize yüklenir ve bu yeni dosyayla otomatik olarak ilişkilendirilen public
erişimini tekrar görürsünüz.
Public
erişim etiketinin yanında küçük bir bağlantı simgesi de göreceksiniz. Resmi tıkladığınızda, tarayıcınız ilgili resmin herkese açık URL'sine gider. Bu URL şu biçimde olur:
https://storage.googleapis.com/BUCKET_NAME/PICTURE_FILE.png
BUCKET_NAME
, paketiniz için seçtiğiniz genel olarak benzersiz addır ve ardından resminizin dosya adıdır.
Resim adının yanındaki onay kutusunu işaretleyerek DELETE
düğmesi etkinleşir ve bu ilk resmi silebilirsiniz.
7. Veritabanını hazırlama
Vision API'nin sağladığı resimle ilgili bilgileri hızlı, tümüyle yönetilen, sunucusuz ve bulutta yerel bir NoSQL belge veritabanı olan Cloud Firestore veritabanında saklarsınız. Cloud Console'un Firestore
bölümüne giderek veritabanınızı hazırlayın:
İki seçenek sunulmaktadır: Native mode
veya Datastore mode
. Çevrimdışı destek ve gerçek zamanlı senkronizasyon gibi ek özellikler sunan yerel modu kullanın.
SELECT NATIVE MODE
seçeneğini tıklayın.
Çoklu bölge seçin (Avrupa'da ancak tercihen en azından işlevinizin ve depolama paketinizin bulunduğu bölgeyle aynı bölge).
CREATE DATABASE
düğmesini tıklayın.
Veritabanı oluşturulduktan sonra şunu göreceksiniz:
+ START COLLECTION
düğmesini tıklayarak yeni bir koleksiyon oluşturun.
pictures
ad koleksiyonu.
Doküman oluşturmanız gerekmez. Yeni resimler Cloud Storage'da depolanıp Vision API tarafından analiz edilirken bu resimleri programatik olarak eklersiniz.
Save
simgesini tıklayın.
Firestore, yeni oluşturulan koleksiyonda ilk varsayılan dokümanı oluşturur. Faydalı herhangi bir bilgi içermediğinden bu dokümanı güvenle silebilirsiniz:
Koleksiyonumuzda programlı olarak oluşturulacak dokümanlar 4 alan içerecektir:
- name (dize): yüklenen resmin dosya adı ve aynı zamanda dokümanın anahtarıdır
- labels (dize dizisi): Vision API tarafından tanınan öğelerin etiketleri
- color (dize): baskın rengin onaltılık renk kodu (ör. #ab12ef)
- create (tarih): Bu görsele ait meta verilerin saklandığı zaman damgası
- thumbnail (boole): Bu resim için bir küçük resim oluşturulmuşsa mevcut ve doğru olacak isteğe bağlı bir alan
Küçük resimleri olan resimleri bulmak için Firestore'da arama yapacağımızdan ve oluşturma tarihine göre sıralayacağımız için bir arama dizini oluşturmamız gerekecek.
Dizini Cloud Shell'de aşağıdaki komutla oluşturabilirsiniz:
gcloud firestore indexes composite create \
--collection-group=pictures \
--field-config field-path=thumbnail,order=descending \
--field-config field-path=created,order=descending
Bu işlemi Cloud Console'dan da yapabilirsiniz. Bunun için soldaki gezinme sütununda Indexes
simgesini tıklayın ve ardından aşağıda gösterildiği gibi bir birleşik dizin oluşturun:
Create
simgesini tıklayın. Dizin oluşturma birkaç dakika sürebilir.
8. Kodu klonlama
Önceki kod laboratuvarında yapmadıysanız kodu klonlayın:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
Ardından, hizmeti içeren dizine giderek laboratuvarı derlemeye başlayabilirsiniz:
cd serverless-photosharing-workshop/services/image-analysis/java
Hizmet için aşağıdaki dosya düzenine sahip olursunuz:
9. Hizmet kodunu keşfedin
Bir BOM kullanarak, pom.xml
içindeki Java İstemci Kitaplıklarının nasıl etkinleştirildiğine bakarak başlayın:
Öncelikle, Java uygulamamızın bağımlılıklarının listelendiği pom.xml
dosyasını açın; Vision, Cloud Storage ve Firestore API'lerinin kullanımına odaklanıyor.
<?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>
İşlevler, EventController
sınıfında uygulanmıştır. Pakete her yeni resim yüklendiğinde hizmet, aşağıdakileri işlemesi için bir bildirim alır:
@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 {
...
}
Kod, Cloud Events
başlıklarını doğrulamaya devam eder:
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);
}
Artık bir istek oluşturulabilir ve kod, bu tür bir isteği Vision API
cihazına göndermek için hazırlar:
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);
Vision API'nin 3 temel özelliğini istiyoruz:
- Etiket algılama: Resimlerdekileri anlamak için
- Resim özellikleri: Resmin ilgi çekici özelliklerini vermek için (resmin baskın rengiyle ilgileniyoruz)
- Güvenli arama: resmin gösterilmesinin güvenli olup olmadığını öğrenmek (yetişkinlere uygun / tıbbi / müstehcen / şiddet barındıran içerik barındırmamalıdır)
Bu noktada Vision API'ye çağrı yapabiliriz:
...
logger.info("Calling the Vision API...");
BatchAnnotateImagesResponse result = vision.batchAnnotateImages(requests);
List<AnnotateImageResponse> responses = result.getResponsesList();
...
Referans olarak, Vision API'nin yanıtı şu şekilde görünür:
{
"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
}
Herhangi bir hata döndürülmezse işleme devam edebiliriz. Dolayısıyla, engelleme durumunda neden şu hatayı gördüğümüz:
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);
}
Resimde algılanan öğelerin, kategorilerin veya temaların etiketlerini alacağız:
List<String> labels = response.getLabelAnnotationsList().stream()
.map(annotation -> annotation.getDescription())
.collect(Collectors.toList());
logger.info("Annotations found:");
for (String label: labels) {
logger.info("- " + label);
}
Resmin baskın rengini öğrenmek istiyoruz:
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);
}
Resmin gösterilmesinin güvenli olup olmadığını kontrol edelim:
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);
}
Olası veya çok olası olup olmadıklarını görmek için yetişkinlere uygun / adres sahteciliği / tıbbi / şiddet / müstehcenlik özelliklerini kontrol ediyoruz.
Güvenli aramanın sonucu uygunsa meta verileri Firestore'da depolayabiliriz:
// 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 ile Uygulama Görüntüleri Derleme
Bu isteğe bağlı adımda, GraalVM kullanarak önce bir JIT based app image
, ardından bir Native Java app image
oluşturacaksınız.
Derlemeyi çalıştırmak için uygun bir JDK'nın ve yerel görüntü oluşturucunun yüklü ve yapılandırılmış olduğundan emin olmanız gerekir. Birkaç seçenek vardır.
To start
, GraalVM 22.3.x Community Edition'ı indirin ve GraalVM yükleme sayfasındaki talimatları uygulayın.
Bu işlem, SDKMAN!
SDKman
ile uygun JDK dağıtımını yüklemek için yükleme komutunu kullanarak başlayın:
sdk install java 17.0.8-graal
SDKman'a hem JIT hem de AOT derlemeleri için bu sürümü kullanma talimatı verin:
sdk use java 17.0.8-graal
Cloudshell
ürününde, aşağıdaki basit komutlarla GraalVM ve yerel görüntü yardımcı programını yükleyebilirsiniz:
# 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)
İlk olarak GCP proje ortamı değişkenlerini ayarlayın:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
Ardından, hizmeti içeren dizine giderek laboratuvarı derlemeye başlayabilirsiniz:
cd serverless-photosharing-workshop/services/image-analysis/java
JIT uygulama görüntüsünü oluşturun:
./mvnw package
Terminaldeki derleme günlüğünü inceleyin:
... [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 kullanır) görüntüsünü oluşturun:
./mvnw native:compile -Pnative
Terminalde yerel görüntü derleme günlükleri de dahil olmak üzere derleme günlüğünü inceleyin:
Derlemenin test ettiğiniz makineye bağlı olarak çok daha uzun süreceğini unutmayın.
... [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. Kapsayıcı Görüntüleri Oluşturma ve Yayınlama
Şimdi, biri JIT image
ve diğeri Native Java image
olacak şekilde iki farklı sürümde bir container görüntüsü oluşturalım.
İlk olarak GCP proje ortamı değişkenlerini ayarlayın:
export GOOGLE_CLOUD_PROJECT=$(gcloud config get-value project)
JIT görüntüsünü oluşturun:
./mvnw spring-boot:build-image -Pji
Terminaldeki derleme günlüğünü inceleyin:
[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(Yerel) görüntüsünü oluşturun:
./mvnw spring-boot:build-image -Pnative
Terminalde yerel görüntü derleme günlükleri de dahil olmak üzere derleme günlüğünü inceleyin.
Not:
- üzerinde test ettiğiniz makineye bağlı olarak, derlemenin çok daha uzun sürmesi
- resimler UPX ile daha fazla sıkıştırılabilir, ancak başlangıç performansı üzerinde küçük bir olumsuz etkiye sahiptir. Bu nedenle, bu derleme UPX kullanmaz. Her zaman hafif bir denge sağlar.
... [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] ------------------------------------------------------------------------
Resimlerin derlendiğini doğrulayın:
docker images | grep image-analysis
İki görüntüyü etiketleyip GCR'ye aktarın:
# 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'a dağıt
Hizmeti dağıtma zamanı.
Hizmeti, biri JIT görüntüsünü, ikincisinde AOT(Yerel) görüntüsünü kullanarak iki kez dağıtacaksınız. Her iki hizmet dağıtımı da karşılaştırma amacıyla paketteki aynı görüntüyü paralel olarak işler.
İlk olarak GCP proje ortamı değişkenlerini ayarlayın:
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 görüntüsünü dağıtın ve konsolda dağıtım günlüğünü inceleyin:
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
Yerel görüntüyü dağıtın ve dağıtım günlüğünü konsolda inceleyin:
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 Tetikleyicileri Ayarlama
Eventarc, ayrıştırılan mikro hizmetler arasındaki durum değişikliklerinin (etkinlik adı verilen) akışını yönetmek amacıyla standartlaştırılmış bir çözüm sunar. Eventarc, tetiklendiğinde bu etkinlikleri Pub/Sub abonelikleri üzerinden çeşitli hedeflere (bu belgede, Etkinlik hedeflerine bakın) yönlendirir ve sizin için yayınlama, güvenlik, yetkilendirme, gözlemlenebilirlik ve hata işleme süreçlerini yönetir.
Cloud Run hizmetinizin belirli bir etkinlik veya etkinlik kümesinden bildirim alması için bir Eventarc tetikleyicisi oluşturabilirsiniz. Tetikleyici için filtreler belirterek, etkinlik kaynağı ve hedef Cloud Run hizmeti de dahil olmak üzere etkinliğin yönlendirmesini yapılandırabilirsiniz.
İlk olarak GCP proje ortamı değişkenlerini ayarlayın:
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
Cloud Storage hizmet hesabına pubsub.publisher
izni verin:
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'
Resmi işlemek üzere hem JIT hem de Yerel hizmet görüntüleri için Eventarc tetikleyicileri oluşturun:
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
İki tetikleyicinin oluşturulduğunu inceleyin:
gcloud eventarc triggers list --location=eu
14. Test Hizmeti Sürümleri
Hizmet dağıtımları başarılı olduktan sonra Cloud Storage'da bir resim yayınlayarak hizmetlerimizin çağrılıp çağrılmadığını, Vision API'nin ne döndürdüğünü ve meta verilerin Firestore'da depolanıp depolanmadığını görürsünüz.
Cloud Storage
hizmetine geri dönün ve laboratuvarın başında oluşturduğumuz paketi tıklayın:
Paket ayrıntıları sayfasına geldiğinizde, resim yüklemek için Upload files
düğmesini tıklayın.
Örneğin, /services/image-analysis/java
altında kod tabanınızla birlikte bir GeekHour.jpeg
resmi sağlanır. Bir resim seçip Open button
tuşuna basın:
Artık hizmetin yürütülmesini image-analysis-jit
ile başlayıp image-analysis-native
ile devam ettirebilirsiniz.
"Hamburger"den (Gönder) menüsünden Cloud Run > image-analysis-jit
hizmetine gidin.
Günlükler'i tıklayın ve sonucu inceleyin:
Hatta günlük listesinde image-analysis-jit
JIT hizmetinin çağrıldığını görüyorum.
Günlükler, hizmet yürütme işleminin başlangıcını ve bitişini gösterir. Bunların arasında, işlevimize koyduğumuz günlükleri, günlük ifadeleriyle INFO düzeyinde görebiliriz. Şunları görürüz:
- İşlevimizi tetikleyen olayın ayrıntıları,
- Vision API çağrısından gelen ham sonuçlar,
- Yüklediğimiz resimde bulunan etiketler,
- Baskın renklerle ilgili bilgiler,
- Resmin gösterilmesinin güvenli olup olmadığı,
- Sonunda resimle ilgili bu meta veriler Firestore'da saklanır.
image-analysis-native
hizmeti için bu işlemi tekrarlayacaksınız.
"Hamburger"den (Gönder) menüsünden Cloud Run > image-analysis-native
hizmetine gidin.
Günlükler'i tıklayın ve sonucu inceleyin:
Resim meta verilerinin Fiorestore'da depolanıp depolanmadığını şimdi gözlemlemek isteyebilirsiniz.
Yine "hamburger"den (Gönder) menüsünden Firestore
bölümüne gidin. Data
alt bölümünde (varsayılan olarak gösterilmektedir), az önce yüklediğiniz resimle ilgili yeni bir doküman eklenmiş pictures
koleksiyonunu görürsünüz:
15. Temizleme (İsteğe bağlı)
Serideki diğer laboratuvarlarla devam etmeyi düşünmüyorsanız maliyet tasarrufu yapmak ve genel olarak iyi bir bulut vatandaşı olmak için kaynakları temizleyebilirsiniz. Kaynakları aşağıda açıklandığı şekilde tek tek temizleyebilirsiniz.
Paketi silin:
gsutil rb gs://${BUCKET_PICTURES}
İşlevi silin:
gcloud functions delete picture-uploaded --region europe-west1 -q
Koleksiyondan koleksiyonu sil'i seçerek Firestore koleksiyonunu silin:
Alternatif olarak projenin tamamını silebilirsiniz:
gcloud projects delete ${GOOGLE_CLOUD_PROJECT}
16. Tebrikler!
Tebrikler! Projenin ilk anahtar hizmetini başarıyla uyguladınız.
İşlediklerimiz
- Cloud Storage
- Cloud Run
- Cloud Vision API
- Cloud Firestore
- Yerel Java Görüntüleri