1. Genel Bakış
Bu kod laboratuvarında, önceki laboratuvarı geliştirecek ve bir küçük resim hizmeti ekleyeceksiniz. Küçük resim hizmeti, büyük resimler çeken ve bunlardan küçük resimler oluşturan bir web kapsayıcısıdır.
Resim Cloud Storage'a yüklenirken, Cloud Pub/Sub aracılığıyla bir Cloud Run web container'ına bildirim gönderilir. Bu bildirim, görüntüleri yeniden boyutlandırıp Cloud Storage'daki başka bir pakete kaydeder.
Neler öğreneceksiniz?
- Cloud Run
- Cloud Storage
- Cloud Pub/Sub
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 ve bunu istediğiniz zaman güncelleyebilirsiniz.
- Proje Kimliği, tüm Google Cloud projelerinde benzersiz olmalıdır 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ğine referans vermeniz gerekir (ve bu kimlik genellikle
PROJECT_ID
olarak tanımlanır). Beğenmezseniz başka bir rastgele kod oluşturun ya da kendi proje kimliğinizi deneyip mevcut olup olmadığına bakın. Sıcaklık "soğudu" takip etmeniz gerekir. - Bazı API'lerin kullandığı üçüncü bir değer, yani Proje Numarası daha vardır. Bu değerlerin üçü hakkında daha fazla bilgiyi belgelerde bulabilirsiniz.
- Ardından, 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ırmayla karşılaşmamak için kaynakları kapatmak istiyorsanız tüm "temizleme" işlemlerini uygulayın buradaki talimatları uygulayın. 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.
GCP Console'da, sağ üstteki araç çubuğunda yer alan 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 laboratuvardaki tüm çalışmalarınızı yalnızca bir tarayıcıyla yapabilirsiniz.
3. API'leri etkinleştir
Bu laboratuvarda, container görüntüleri derlemek için Cloud Build, container'ı dağıtmak için Cloud Run'a ihtiyacınız olacak.
Cloud Shell'den her iki API'yi de etkinleştirin:
gcloud services enable cloudbuild.googleapis.com \ run.googleapis.com
İşlemin başarıyla tamamlandığını göreceksiniz:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. Başka bir paket oluştur
Yüklenen resimlerin küçük resimlerini başka bir grupta depolayacaksınız. İkinci paketi oluşturmak için gsutil
kullanalım.
Cloud Shell'in içinde 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. Ardından tek tip düzeyde erişimle, Avrupa'da herkese açık çok bölgeli paket oluşturun:
BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT gsutil mb -l EU gs://$BUCKET_THUMBNAILS gsutil uniformbucketlevelaccess set on gs://$BUCKET_THUMBNAILS gsutil iam ch allUsers:objectViewer gs://$BUCKET_THUMBNAILS
Sonuç olarak, yeni bir herkese açık paketiniz olur:
5. Kodu klonlama
Kodu klonlayın ve hizmeti içeren dizine gidin:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop cd serverless-photosharing-workshop/services/thumbnails/nodejs
Hizmet için aşağıdaki dosya düzenine sahip olursunuz:
services | ├── thumbnails | ├── nodejs | ├── Dockerfile ├── index.js ├── package.json
thumbnails/nodejs
klasörünün içinde 3 dosya var:
index.js
, Node.js kodunu içerirpackage.json
, kitaplık bağımlılıklarını tanımlarDockerfile
, container görüntüsünü tanımlar
6. Kodu inceleyin
Kodu keşfetmek için Cloud Shell penceresinin üst kısmındaki Open Editor
düğmesini tıklayarak yerleşik metin düzenleyiciyi kullanabilirsiniz:
Daha fazla ekran alanı elde etmek için düzenleyiciyi özel bir tarayıcı penceresinde de açabilirsiniz.
Bağımlılıklar
package.json
dosyası, gerekli kitaplık bağımlılıklarını tanımlar:
{
"name": "thumbnail_service",
"version": "0.0.1",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"bluebird": "^3.7.2",
"express": "^4.17.1",
"imagemagick": "^0.1.3",
"@google-cloud/firestore": "^4.9.9",
"@google-cloud/storage": "^5.8.3"
}
}
Cloud Storage kitaplığı, Cloud Storage'da görüntü dosyalarını okumak ve kaydetmek için kullanılır. Resim meta verilerini güncellemek için Firestore. Express, bir JavaScript / Düğüm web çerçevesidir. Gövde ayrıştırıcı modülü, gelen istekleri kolayca ayrıştırmak için kullanılır. Bluebird, verilen görevleri yerine getirmek için kullanılıyor. Imagemagick, resimleri değiştirmek için kullanılan bir kitaplıktır.
Dockerfile
Dockerfile
, uygulamanın container görüntüsünü tanımlar:
FROM node:14-slim
# installing Imagemagick
RUN set -ex; \
apt-get -y update; \
apt-get -y install imagemagick; \
rm -rf /var/lib/apt/lists/*; \
mkdir /tmp/original; \
mkdir /tmp/thumbnail;
WORKDIR /picadaily/services/thumbnails
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]
Temel görüntü Düğüm 14'tür ve imagemagick kitaplığı, görüntü işleme için kullanılır. Orijinal dosyaları ve küçük resim dosyalarını saklamak için bazı geçici dizinler oluşturulur. Ardından, kodumuzun gerektirdiği NPM modülleri, kod npm start
ile başlatılmadan önce yüklenir.
index.js
Bu programın işlevini daha iyi anlayabilmemiz için kodu parçalar halinde inceleyelim.
const express = require('express');
const imageMagick = require('imagemagick');
const Promise = require("bluebird");
const path = require('path');
const {Storage} = require('@google-cloud/storage');
const Firestore = require('@google-cloud/firestore');
const app = express();
app.use(express.json());
İlk olarak, gerekli bağımlılıkları gerekli kılıp Express web uygulamamızı oluşturuyoruz. Ayrıca, gelen istekler aslında uygulamamıza bir POST isteği aracılığıyla gönderilen JSON yükleri olduğundan, JSON gövde ayrıştırıcısını kullanmak istediğimizi de belirtiyoruz.
app.post('/', async (req, res) => {
try {
// ...
} catch (err) {
console.log(`Error: creating the thumbnail: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
Bu gelen yüklemeleri / temel URL'den alıyoruz ve Google Cloud web konsolundaki Stackdriver Logging arayüzünde görülebilecek günlüklere bakarak kodumuzdaki bir şeyin neden başarısız olabileceğine dair daha iyi bilgi edinmek amacıyla kodumuzu hata mantığı işlemeyle sarmalıyoruz.
const pubSubMessage = req.body;
console.log(`PubSub message: ${JSON.stringify(pubSubMessage)}`);
const fileEvent = JSON.parse(Buffer.from(pubSubMessage.message.data, 'base64').toString().trim());
console.log(`Received thumbnail request for file ${fileEvent.name} from bucket ${fileEvent.bucket}`);
Cloud Run platformunda Pub/Sub mesajları şu biçimdeki JSON yükleri şeklinde HTTP POST istekleri aracılığıyla gönderilir:
{
"message": {
"attributes": {
"bucketId": "uploaded-pictures",
"eventTime": "2020-02-27T09:22:43.255225Z",
"eventType": "OBJECT_FINALIZE",
"notificationConfig": "projects/_/buckets/uploaded-pictures/notificationConfigs/28",
"objectGeneration": "1582795363255481",
"objectId": "IMG_20200213_181159.jpg",
"payloadFormat": "JSON_API_V1"
},
"data": "ewogICJraW5kIjogInN0b3JhZ2Ujb2JqZWN...FQUU9Igp9Cg==",
"messageId": "1014308302773399",
"message_id": "1014308302773399",
"publishTime": "2020-02-27T09:22:43.973Z",
"publish_time": "2020-02-27T09:22:43.973Z"
},
"subscription": "projects/serverless-picadaily/subscriptions/gcs-events-subscription"
}
Ancak bu JSON belgesinde asıl ilginç olan, yalnızca bir dize olan ancak gerçek yükü Base 64'e kodlayan message.data
özelliğinin içinde yer almasıdır. Bu nedenle, yukarıdaki kodumuz bu özelliğin Base 64 içeriğinin kodunu çözmektedir. Kodu çözüldüğünde bu data
özelliği, Cloud Storage etkinlik ayrıntılarını temsil eden başka bir JSON belgesi içerir. Bu belge, diğer meta verilerin yanı sıra dosya adını ve paket adını da belirtir.
{
"kind": "storage#object",
"id": "uploaded-pictures/IMG_20200213_181159.jpg/1582795363255481",
"selfLink": "https://www.googleapis.com/storage/v1/b/uploaded-pictures/o/IMG_20200213_181159.jpg",
"name": "IMG_20200213_181159.jpg",
"bucket": "uploaded-pictures",
"generation": "1582795363255481",
"metageneration": "1",
"contentType": "image/jpeg",
"timeCreated": "2020-02-27T09:22:43.255Z",
"updated": "2020-02-27T09:22:43.255Z",
"storageClass": "STANDARD",
"timeStorageClassUpdated": "2020-02-27T09:22:43.255Z",
"size": "4944335",
"md5Hash": "QzBIoPJBV2EvqB1EVk1riw==",
"mediaLink": "https://www.googleapis.com/download/storage/v1/b/uploaded-pictures/o/IMG_20200213_181159.jpg?generation=1582795363255481&alt=media",
"crc32c": "hQ3uHg==",
"etag": "CLmJhJu08ecCEAE="
}
Kodumuz, küçük resim kullanımı için bu resmi paketten getireceğinden resim ve grup adlarıyla ilgileniyoruz:
const bucket = storage.bucket(fileEvent.bucket);
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
const originalFile = path.resolve('/tmp/original', fileEvent.name);
const thumbFile = path.resolve('/tmp/thumbnail', fileEvent.name);
await bucket.file(fileEvent.name).download({
destination: originalFile
});
console.log(`Downloaded picture into ${originalFile}`);
Çıkış depolama paketinin adını bir ortam değişkeninden alıyoruz.
Dosya oluşturulması Cloud Run hizmetimizi tetikleyen kaynak paketimiz ve üretilen görüntüyü depolayacağımız hedef paketimiz var. imagemagick kitaplığı, küçük resmi yerel olarak /tmp
geçici dizininde oluşturacağından, yerel dosya işlemeyi gerçekleştirmek için path
yerleşik API'sini kullanıyoruz. Yüklenen resim dosyasını indirmek üzere eşzamansız bir çağrı için await
.
const resizeCrop = Promise.promisify(im.crop);
await resizeCrop({
srcPath: originalFile,
dstPath: thumbFile,
width: 400,
height: 400
});
console.log(`Created local thumbnail in ${thumbFile}`);
Imagemagick modülü pek de async
/ await
uyumlu değil. Bu nedenle, söz konusu modülü bir JavaScript taahhüdü (Bluebird modülü tarafından sağlanır) kapsamında tamamladık. Ardından, kaynak ve hedef dosyaların parametreleri ve oluşturmak istediğimiz küçük resmin boyutlarını kullanarak oluşturduğumuz eşzamansız yeniden boyutlandırma / kırpma işlevini çağırıyoruz.
await thumbBucket.upload(thumbFile);
console.log(`Uploaded thumbnail to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}`);
Küçük resim dosyası Cloud Storage'a yüklendikten sonra, Cloud Firestore'daki meta verileri de güncelleyerek bu resmin küçük resminin gerçekten oluşturulduğunu belirten bir boole işareti ekleriz:
const pictureStore = new Firestore().collection('pictures');
const doc = pictureStore.doc(fileEvent.name);
await doc.set({
thumbnail: true
}, {merge: true});
console.log(`Updated Firestore about thumbnail creation for ${fileEvent.name}`);
res.status(204).send(`${fileEvent.name} processed`);
İsteğimiz bittikten sonra, dosyanın düzgün bir şekilde işlendiğini belirten HTTP POST isteğine yanıt veririz.
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started thumbnail generator on port ${PORT}`);
});
Kaynak dosyamızın sonunda, Express'in web uygulamamızı gerçekten 8080 varsayılan bağlantı noktasında başlatmasını sağlama talimatlarını bulabilirsiniz.
7. Yerel olarak test et
Buluta dağıtmadan önce çalıştığından emin olmak için kodu yerel olarak test edin.
thumbnails/nodejs
klasörünün içinde, npm bağımlılarını yükleyin ve sunucuyu başlatın:
npm install; npm start
Her şey yolundaysa sunucu, 8080 numaralı bağlantı noktasından başlatılmalıdır:
Started thumbnail generator on port 8080
Çıkmak için CTRL-C
tuşunu kullanın.
8. Container görüntüsünü derleyip yayınlayın
Cloud Run, container'ları çalıştırır ancak önce container görüntüsünü oluşturmanız gerekir (Dockerfile
içinde tanımlanır). Google Cloud Build, container görüntüleri derlemek ve ardından Google Container Registry'de barındırmak için kullanılabilir.
Dockerfile
klasörünün bulunduğu thumbnails/nodejs
klasöründe kapsayıcı görüntüsünü oluşturmak için aşağıdaki komutu verin:
gcloud builds submit --tag gcr.io/$GOOGLE_CLOUD_PROJECT/thumbnail-service
Bir veya iki dakika sonra derleme işlemi başarılı olur:
Cloud Build "geçmişi" bölümünde başarılı derleme de gösterilmelidir:
"Derleme yapıları" bölümünde ayrıntılar görünümünü almak için derleme kimliğini tıklama sekmesinde container görüntüsünün Cloud Registry'ye (GCR) yüklendiğini göreceksiniz:
İsterseniz container görüntüsünün Cloud Shell'de yerel olarak çalışıp çalışmadığını tekrar kontrol edebilirsiniz:
docker run -p 8080:8080 gcr.io/$GOOGLE_CLOUD_PROJECT/thumbnail-service
Sunucu, kapsayıcıdaki bağlantı noktası 8080'den başlatılır:
Started thumbnail generator on port 8080
Çıkmak için CTRL-C
tuşunu kullanın.
9. Cloud Run'a dağıt
Cloud Run'a dağıtmadan önce Cloud Run bölgesini desteklenen bölgelerden birine ve platformu managed
olarak ayarlayın:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
Yapılandırmanın ayarlanıp ayarlanmadığını kontrol edebilirsiniz:
gcloud config list ... [run] platform = managed region = europe-west1
Container görüntüsünü Cloud Run'da dağıtmak için aşağıdaki komutu çalıştırın:
SERVICE_NAME=thumbnail-service gcloud run deploy $SERVICE_NAME \ --image gcr.io/$GOOGLE_CLOUD_PROJECT/thumbnail-service \ --no-allow-unauthenticated \ --update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS
--no-allow-unauthenticated
işaretine dikkat edin. Bu işlem, Cloud Run hizmetini yalnızca belirli hizmet hesapları tarafından tetiklenecek dahili bir hizmet haline getirir.
Dağıtım başarılı olursa aşağıdaki çıkışı görürsünüz:
Cloud Console kullanıcı arayüzüne gittiğinizde hizmetin başarıyla dağıtıldığını da görürsünüz:
10. Cloud Storage etkinliklerini Pub/Sub üzerinden Cloud Run'a taşıma
Hizmet hazır ancak yeni oluşturulan Cloud Run hizmetine Cloud Storage etkinlikleri oluşturmanız gerekiyor. Cloud Storage, dosya oluşturma etkinliklerini Cloud Pub/Sub üzerinden gönderebilir. Ancak bu işlevi gerçekleştirmenin birkaç adımı vardır.
İletişim ardışık düzeni olarak bir Pub/Sub konusu oluşturun:
TOPIC_NAME=cloudstorage-cloudrun-topic gcloud pubsub topics create $TOPIC_NAME
Dosyalar pakette depolandığında Pub/Sub bildirimleri oluşturun:
BUCKET_PICTURES=uploaded-pictures-$GOOGLE_CLOUD_PROJECT gsutil notification create -t $TOPIC_NAME -f json gs://$BUCKET_PICTURES
Pub/Sub aboneliği için daha sonra oluşturacağımız bir hizmet hesabı oluşturun:
SERVICE_ACCOUNT=$TOPIC_NAME-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Cloud Run Pub/Sub Invoker"
Hizmet hesabına bir Cloud Run hizmetini çağırma izni verin:
SERVICE_NAME=thumbnail-service gcloud run services add-iam-policy-binding $SERVICE_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --role=roles/run.invoker
Pub/Sub hizmet hesabını 8 Nisan 2021'de veya öncesinde etkinleştirdiyseniz Pub/Sub hizmet hesabına iam.serviceAccountTokenCreator
rolünü verin:
PROJECT_NUMBER=$(gcloud projects describe $GOOGLE_CLOUD_PROJECT --format='value(projectNumber)') gcloud projects add-iam-policy-binding $GOOGLE_CLOUD_PROJECT \ --member=serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role=roles/iam.serviceAccountTokenCreator
IAM değişikliklerinin uygulanması birkaç dakika sürebilir.
Son olarak, hizmet hesabıyla bir Pub/Sub aboneliği oluşturun:
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)') gcloud pubsub subscriptions create $TOPIC_NAME-subscription --topic $TOPIC_NAME \ --push-endpoint=$SERVICE_URL \ --push-auth-service-account=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com
Bir aboneliğin oluşturulup oluşturulmadığını kontrol edebilirsiniz. Konsolda Pub/Sub'a gidin, gcs-events
konusunu seçin ve en altta aboneliği göreceksiniz:
11. Hizmeti test etme
Kurulumun çalışıp çalışmadığını test etmek için uploaded-pictures
paketine yeni bir resim yükleyin ve thumbnails
paketinde, yeniden boyutlandırılan yeni resimlerin beklendiği gibi görünüp görünmediğini kontrol edin.
Ayrıca, Cloud Run hizmetinin çeşitli adımları izleyeceğinden günlük kaydı mesajlarının görüntülendiğini görmek için günlükleri bir kez daha kontrol edebilirsiniz:
12. 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_THUMBNAILS
Hizmeti silin:
gcloud run services delete $SERVICE_NAME -q
Pub/Sub konusunu silin:
gcloud pubsub topics delete $TOPIC_NAME
Alternatif olarak projenin tamamını silebilirsiniz:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
13. Tebrikler!
Artık her şey yerli yerinde:
- Cloud Storage'da, yeni bir resim yüklendiğinde bir konuda Pub/Sub mesajları gönderen bir bildirim oluşturuldu.
- Gerekli IAM bağlamalarını ve hesapları tanımlayın (tamamen otomatik olduğu Cloud Functions'ın aksine, burada manuel olarak yapılandırılır).
- Cloud Run hizmetimizin Pub/Sub mesajlarını alması için bir abonelik oluşturuldu.
- Pakete her yeni resim yüklendiğinde, yeni Cloud Run hizmeti sayesinde resim yeniden boyutlandırılır.
İşlediklerimiz
- Cloud Run
- Cloud Storage
- Cloud Pub/Sub