1. Panoramica
In questo lab di codifica, creerai un nuovo servizio Cloud Run, il servizio di collage, che verrà attivato da Cloud Scheduler a intervalli di tempo regolari. Il servizio recupera le ultime immagini caricate e crea un collage: trova l'elenco delle immagini recenti in Cloud Firestore e poi scarica i file immagine effettivi da Cloud Storage.

Obiettivi didattici
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. Configurazione e requisiti
Configurazione dell'ambiente autonomo
- Accedi alla console Google Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o Google Workspace, devi crearne uno.



- Il nome del progetto è il nome visualizzato per i partecipanti a questo progetto. È una stringa di caratteri non utilizzata dalle API di Google e puoi aggiornarla in qualsiasi momento.
- L'ID progetto deve essere univoco in tutti i progetti Google Cloud ed è immutabile (non può essere modificato dopo essere stato impostato). Cloud Console genera automaticamente una stringa univoca, di solito non ti interessa di cosa si tratta. Nella maggior parte dei codelab, devi fare riferimento all'ID progetto (che in genere è identificato come
PROJECT_ID), quindi, se non ti piace, generane un altro casuale oppure puoi provare il tuo e vedere se è disponibile. Viene "congelato" dopo la creazione del progetto. - Esiste un terzo valore, un numero di progetto, utilizzato da alcune API. Scopri di più su tutti e tre questi valori nella documentazione.
- Successivamente, devi abilitare la fatturazione in Cloud Console per utilizzare le risorse/API Cloud. L'esecuzione di questo codelab non dovrebbe costare molto, se non nulla. Per arrestare le risorse in modo da non incorrere in costi di fatturazione al termine di questo tutorial, segui le istruzioni di "pulizia" riportate alla fine del codelab. I nuovi utenti di Google Cloud possono beneficiare del programma prova senza costi di 300$.
Avvia Cloud Shell
Sebbene Google Cloud possa essere gestito da remoto dal tuo laptop, in questo codelab utilizzerai Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.
Nella console GCP, fai clic sull'icona di Cloud Shell nella barra degli strumenti in alto a destra:

Bastano pochi istanti per eseguire il provisioning e connettersi all'ambiente. Al termine, dovresti vedere un risultato simile a questo:

Questa macchina virtuale è caricata con tutti gli strumenti per sviluppatori di cui avrai bisogno. Offre una home directory permanente da 5 GB e viene eseguita su Google Cloud, migliorando notevolmente le prestazioni e l'autenticazione della rete. Tutto il lavoro di questo lab può essere svolto semplicemente con un browser.
3. Abilita API
Avrai bisogno di Cloud Scheduler per attivare il servizio Cloud Run a intervalli regolari. Assicurati che sia abilitato:
gcloud services enable cloudscheduler.googleapis.com
Dovresti vedere che l'operazione è stata completata correttamente:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. Clona il codice
Clona il codice, se non l'hai già fatto nel lab precedente:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
A questo punto, puoi andare alla directory contenente il servizio:
cd serverless-photosharing-workshop/services/collage/nodejs
Per il servizio avrai il seguente layout dei file:
services
|
├── collage
|
├── nodejs
|
├── Dockerfile
├── index.js
├── package.json
All'interno della cartella sono presenti tre file:
index.jscontiene il codice Node.jspackage.jsondefinisce le dipendenze della libreriaDockerfiledefinisce l'immagine container
5. Esplora il codice
Dipendenze
Il file package.json definisce le dipendenze della libreria necessarie:
{
"name": "collage_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"
}
}
Ci affidiamo alla libreria Cloud Storage per leggere e salvare i file immagine in Cloud Storage. Dichiariamo una dipendenza da Cloud Firestore per recuperare i metadati delle immagini che abbiamo archiviato in precedenza. Express è un framework web JavaScript / Node. Bluebird viene utilizzato per la gestione delle promesse e imagemagick è una libreria per la manipolazione delle immagini.
Dockerfile
Dockerfile definisce l'immagine container per l'applicazione:
FROM node:14-slim
# installing Imagemagick
RUN set -ex; \
apt-get -y update; \
apt-get -y install imagemagick; \
rm -rf /var/lib/apt/lists/*
WORKDIR /picadaily/services/collage
COPY package*.json ./
RUN npm install --production
COPY . .
CMD [ "npm", "start" ]
Stiamo utilizzando un'immagine di base Node 14 leggera. Stiamo installando la libreria imagemagick. Poi installiamo i moduli NPM necessari al nostro codice ed eseguiamo il codice del nodo con npm start.
index.js
Diamo un'occhiata più da vicino al nostro codice index.js:
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');
Richiediamo le varie dipendenze necessarie per l'esecuzione del nostro programma: Express è il framework web Node che utilizzeremo, ImageMagick la libreria per la manipolazione delle immagini, Bluebird è una libreria per la gestione delle promesse JavaScript, Path viene utilizzato per la gestione dei percorsi di file e directory, mentre Storage e Firestore servono rispettivamente per lavorare con Google Cloud Storage (i nostri bucket di immagini) e con l'archivio dati Cloud Firestore.
const app = express();
app.get('/', async (req, res) => {
try {
console.log('Collage request');
/* ... */
} catch (err) {
console.log(`Error: creating the collage: ${err}`);
console.error(err);
res.status(500).send(err);
}
});
Sopra, abbiamo la struttura del nostro gestore Node: la nostra app risponde alle richieste HTTP GET. E stiamo gestendo un po' gli errori nel caso in cui si verifichi un problema. Ora diamo un'occhiata a cosa c'è all'interno di questa struttura.
const thumbnailFiles = [];
const pictureStore = new Firestore().collection('pictures');
const snapshot = await pictureStore
.where('thumbnail', '==', true)
.orderBy('created', 'desc')
.limit(4).get();
if (snapshot.empty) {
console.log('Empty collection, no collage to make');
res.status(204).send("No collage created.");
} else {
/* ... */
}
Il nostro servizio di collage richiede almeno quattro immagini (di cui sono state generate le miniature), quindi assicurati di caricarne prima quattro.
Recuperiamo le quattro immagini più recenti caricate dai nostri utenti dai metadati archiviati in Cloud Firestore. Controlliamo se la raccolta risultante è vuota o meno, quindi procediamo ulteriormente nel ramo else del nostro codice.
Raccogliamo l'elenco dei nomi dei file:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
Scaricheremo ciascuno di questi file dal bucket delle miniature, il cui nome deriva da una variabile di ambiente che abbiamo impostato al momento del deployment:
const thumbBucket = storage.bucket(process.env.BUCKET_THUMBNAILS);
await Promise.all(thumbnailFiles.map(async fileName => {
const filePath = path.resolve('/tmp', fileName);
await thumbBucket.file(fileName).download({
destination: filePath
});
}));
console.log('Downloaded all thumbnails');
Una volta caricate le miniature più recenti, utilizzeremo la libreria ImageMagick per creare una griglia 4x4 di queste miniature. Utilizziamo la libreria Bluebird e la relativa implementazione di Promise per trasformare il codice basato su callback in codice compatibile con async / await, quindi attendiamo la promessa che crea il collage di immagini:
const collagePath = path.resolve('/tmp', 'collage.png');
const thumbnailPaths = thumbnailFiles.map(f => path.resolve('/tmp', f));
const convert = Promise.promisify(im.convert);
await convert([
'(', ...thumbnailPaths.slice(0, 2), '+append', ')',
'(', ...thumbnailPaths.slice(2), '+append', ')',
'-size', '400x400', 'xc:none', '-background', 'none', '-append',
collagePath]);
console.log("Created local collage picture");
Poiché l'immagine del collage è stata salvata su disco localmente nella cartella temporanea, ora dobbiamo caricarla su Cloud Storage e restituire una risposta riuscita (codice di stato 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
Ora è il momento di fare in modo che lo script Node ascolti le richieste in arrivo:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
Alla fine del file di origine, abbiamo le istruzioni per fare in modo che Express avvii effettivamente la nostra applicazione web sulla porta predefinita 8080.
6. Testare localmente
Testa il codice localmente per assicurarti che funzioni prima del deployment nel cloud.
All'interno della cartella collage/nodejs, installa le dipendenze npm e avvia il server:
npm install; npm start
Se tutto è andato a buon fine, il server dovrebbe avviarsi sulla porta 8080:
Started collage service on port 8080
Usa CTRL-C per uscire.
7. Crea ed esegui il deployment in Cloud Run
Prima di eseguire il deployment in Cloud Run, imposta la regione Cloud Run su una delle regioni supportate e la piattaforma su managed:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
Puoi verificare che la configurazione sia impostata:
gcloud config list ... [run] platform = managed region = europe-west1
Anziché creare e pubblicare manualmente l'immagine container utilizzando Cloud Build, puoi anche fare affidamento su Cloud Run per creare l'immagine container per te utilizzando Google Cloud Buildpacks.
Esegui questo comando per creare l'immagine container:
BUCKET_THUMBNAILS=thumbnails-$GOOGLE_CLOUD_PROJECT
SERVICE_NAME=collage-service
gcloud run deploy $SERVICE_NAME \
--source . \
--no-allow-unauthenticated \
--update-env-vars BUCKET_THUMBNAILS=$BUCKET_THUMBNAILS
Prendi nota del flag –-source. Si tratta del deployment basato sull'origine in Cloud Run. Se nella directory del codice sorgente è presente un file Dockerfile, il codice sorgente caricato viene creato utilizzando questo file.Dockerfile Se nella directory del codice sorgente non è presente alcun Dockerfile, i buildpack di Google Cloud rilevano automaticamente la lingua che stai utilizzando e recuperano le dipendenze del codice per creare un'immagine container pronta per la produzione, utilizzando un'immagine di base sicura gestita da Google. Questo flag indica a Cloud Run di utilizzare i buildpack di Google Cloud per creare l'immagine container definita in Dockerfile.
Tieni presente inoltre che il deployment basato sull'origine utilizza Artifact Registry per archiviare i container creati. Artifact Registry è una versione moderna di Google Container Registry. La CLI ti chiederà di abilitare l'API se non è già abilitata nel progetto e creerà un repository con il nome cloud-run-source-deploy nella regione in cui esegui il deployment.
Il flag --no-allow-unauthenticated rende il servizio Cloud Run un servizio interno che verrà attivato solo da service account specifici.
8. Configura Cloud Scheduler
Ora che il servizio Cloud Run è pronto e di cui è stato eseguito il deployment, è il momento di creare la pianificazione regolare per richiamare il servizio ogni minuto.
Crea un service account:
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
Concedi al service account l'autorizzazione per richiamare il servizio Cloud Run:
gcloud run services add-iam-policy-binding $SERVICE_NAME \ --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --role=roles/run.invoker
Crea un job Cloud Scheduler da eseguire ogni minuto:
SERVICE_URL=$(gcloud run services describe $SERVICE_NAME --format 'value(status.url)') gcloud scheduler jobs create http $SERVICE_NAME-job --schedule "* * * * *" \ --http-method=GET \ --location=europe-west1 \ --uri=$SERVICE_URL \ --oidc-service-account-email=$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \ --oidc-token-audience=$SERVICE_URL
Puoi andare alla sezione Cloud Scheduler nella console Cloud per verificare che sia configurato e che punti all'URL del servizio Cloud Run:

9. Testare il servizio
Per verificare se la configurazione funziona, controlla nel bucket thumbnails l'immagine del collage (denominata collage.png). Puoi anche controllare i log del servizio:

10. Pulizia (facoltativo)
Se non intendi continuare con gli altri lab della serie, puoi eseguire la pulizia delle risorse per risparmiare sui costi e per essere un buon cittadino del cloud. Puoi ripulire le risorse singolarmente nel seguente modo.
Elimina il servizio:
gcloud run services delete $SERVICE_NAME -q
Elimina il job Cloud Scheduler:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
In alternativa, puoi eliminare l'intero progetto:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. Complimenti!
Complimenti! Hai creato un servizio pianificato: grazie a Cloud Scheduler, che invia un messaggio ogni minuto a un argomento Pub/Sub, il tuo servizio di collage Cloud Run viene richiamato ed è in grado di unire le immagini per creare l'immagine risultante.
Argomenti trattati
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore