Pic-a-daily: Lab 3 – Eine Collage aus den neuesten Bildern erstellen

1. Übersicht

In diesem Code-Lab erstellen Sie einen neuen Cloud Run-Dienst, den Collagendienst, der in regelmäßigen Abständen von Cloud Scheduler ausgelöst wird. Der Dienst ruft die zuletzt hochgeladenen Bilder ab und erstellt eine Collage aus diesen Bildern. Dazu sucht er in Cloud Firestore nach der Liste der aktuellen Bilder und lädt dann die eigentlichen Bilddateien aus Cloud Storage herunter.

df20f5d0402b54b4.png

Lerninhalte

  • Cloud Run
  • Cloud Scheduler
  • Cloud Storage
  • Cloud Firestore

2. Einrichtung und Anforderungen

Umgebung für das selbstbestimmte Lernen einrichten

  1. Melden Sie sich in der Google Cloud Console an und erstellen Sie ein neues Projekt oder verwenden Sie ein vorhandenes Projekt. Wenn Sie noch kein Gmail- oder Google Workspace-Konto haben, müssen Sie eines erstellen.

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

  • Der Projektname ist der Anzeigename für die Projektteilnehmer. Es handelt sich um eine Zeichenfolge, die von Google APIs nicht verwendet wird und jederzeit aktualisiert werden kann.
  • Die Projekt-ID muss für alle Google Cloud-Projekte eindeutig sein und ist unveränderlich. Sie kann nach dem Festlegen nicht mehr geändert werden. Die Cloud Console generiert automatisch einen eindeutigen String. ist Ihnen meist egal, was es ist. In den meisten Codelabs musst du auf die Projekt-ID verweisen, die in der Regel als PROJECT_ID identifiziert wird. Wenn es dir nicht gefällt, kannst du eine weitere zufällige Projekt-ID generieren. Du kannst aber auch selbst eine andere testen, um zu sehen, ob sie verfügbar ist. Dann ist es „eingefroren“ nachdem das Projekt erstellt wurde.
  • Es gibt einen dritten Wert, die Projektnummer, die von einigen APIs verwendet wird. Weitere Informationen zu allen drei Werten finden Sie in der Dokumentation.
  1. Als Nächstes müssen Sie in der Cloud Console die Abrechnung aktivieren, um Cloud-Ressourcen/APIs verwenden zu können. Dieses Codelab sollte ohne großen Aufwand betrieben werden. Wenn Sie Ressourcen beenden möchten, damit über diese Anleitung hinaus keine Kosten anfallen, führen Sie eine Bereinigung durch am Ende des Codelabs. Neue Google Cloud-Nutzer haben Anspruch auf eine kostenlose Testversion von 300$.

Cloud Shell starten

Sie können Google Cloud zwar von Ihrem Laptop aus aus der Ferne bedienen, in diesem Codelab verwenden Sie jedoch Google Cloud Shell, eine Befehlszeilenumgebung, die in der Cloud ausgeführt wird.

Klicken Sie in der GCP Console oben rechts in der Symbolleiste auf das Cloud Shell-Symbol:

bce75f34b2c53987.png

Die Bereitstellung und Verbindung mit der Umgebung dauert nur einen Moment. Wenn er abgeschlossen ist, sollten Sie in etwa Folgendes sehen:

f6ef2b5f13479f3a.png

Diese virtuelle Maschine verfügt über sämtliche Entwicklertools, die Sie benötigen. Es bietet ein Basisverzeichnis mit 5 GB nichtflüchtigem Speicher und läuft auf Google Cloud, wodurch die Netzwerkleistung und Authentifizierung erheblich verbessert werden. Sie können alle Aufgaben in diesem Lab ganz einfach in einem Browser erledigen.

3. APIs aktivieren

Sie benötigen einen Cloud Scheduler, um den Cloud Run-Dienst in regelmäßigen Abständen auszulösen. Prüfen Sie, ob sie aktiviert ist:

gcloud services enable cloudscheduler.googleapis.com

Der Vorgang sollte jetzt erfolgreich abgeschlossen werden:

Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.

4. Code klonen

Klonen Sie den Code, falls Sie dies noch nicht im vorherigen Code-Lab getan haben:

git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop

Sie können dann in das Verzeichnis wechseln, das den Dienst enthält:

cd serverless-photosharing-workshop/services/collage/nodejs

Sie haben das folgende Dateilayout für den Dienst:

services
 |
 ├── collage
      |
      ├── nodejs
           |
           ├── Dockerfile
           ├── index.js
           ├── package.json

Der Ordner enthält drei Dateien:

  • index.js enthält den Node.js-Code.
  • package.json definiert die Bibliotheksabhängigkeiten.
  • Dockerfile definiert das Container-Image

5. Code ansehen

Abhängigkeiten

Die Datei package.json definiert die erforderlichen Bibliotheksabhängigkeiten:

{
  "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"
  }
}

Wir sind auf die Cloud Storage-Bibliothek angewiesen, um Bilddateien in Cloud Storage zu lesen und zu speichern. Wir deklarieren eine Abhängigkeit von Cloud Firestore, um Bildmetadaten abzurufen, die wir zuvor gespeichert haben. Express ist ein JavaScript / Node-Web-Framework. Bluebird wird für die Verarbeitung von Versprechen verwendet und imagemagick ist eine Bibliothek zum Bearbeiten von Bildern.

Dockerfile

Dockerfile definiert das Container-Image für die Anwendung:

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" ]

Wir verwenden ein leichtes Node 14-Basis-Image. Die Imagemagick-Bibliothek wird installiert. Dann installieren wir die NPM-Module, die für den Code benötigt werden, und führen den Knotencode mit „npm start“ aus.

index.js

Sehen wir uns unseren index.js-Code genauer an:

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');

Wir benötigen die verschiedenen Abhängigkeiten, die für unser Programm erforderlich sind: Express ist das Node-Web-Framework, das wir verwenden werden, ImageMagick die Bibliothek für die Bildbearbeitung, Bluebird ist eine Bibliothek für die Verarbeitung von JavaScript-Promis, „Path“ wird für die Verarbeitung von Datei- und Verzeichnispfaden verwendet und „Storage“ und „Firestore“ sind für die Arbeit mit Google Cloud Storage (unseren Bild-Buckets) und dem Cloud Firestore-Datenspeicher.

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);
    }
});

Oben sehen Sie die Struktur unseres Node-Handlers: Unsere App antwortet auf HTTP GET-Anfragen. Und wir führen eine Fehlerbehandlung durch, falls etwas schiefgehen sollte. Sehen wir uns nun die Struktur dieser Struktur an.

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 {

    /* ... */

}

Unser Collagenservice benötigt mindestens vier Bilder, deren Miniaturansichten erstellt wurden. Achten Sie also darauf, zuerst vier Bilder hochzuladen.

Wir rufen die vier zuletzt von unseren Nutzern hochgeladenen Bilder aus den Metadaten ab, die in Cloud Firerstore gespeichert sind. Wir prüfen, ob die resultierende Sammlung leer ist oder nicht, und fahren dann mit dem else-Zweig unseres Codes fort.

Schauen wir uns die Liste der Dateinamen an:

snapshot.forEach(doc => {
    thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);

Wir laden jede dieser Dateien aus dem Thumbnail-Bucket herunter, dessen Name von einer Umgebungsvariablen stammt, die wir bei der Bereitstellung festgelegt haben:

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');

Sobald die neuesten Thumbnails hochgeladen sind, erstellen wir mithilfe der ImageMagick-Bibliothek ein 4x4-Raster dieser Thumbnail-Bilder. Wir verwenden die Bluebird-Bibliothek und ihre Promise-Implementierung, um den Callback-gesteuerten Code in async / await-kompatiblen Code umzuwandeln. Dann warten wir auf das Versprechen für die Bildcollage:

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");

Da das Collagenbild lokal im temporären Ordner auf der Festplatte gespeichert wurde, müssen wir es jetzt in Cloud Storage hochladen und dann eine erfolgreiche Antwort zurückgeben (Statuscode 2xx):

await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");

res.status(204).send("Collage created.");

Lassen Sie jetzt das Node-Skript eingehende Anfragen überwachen:

const PORT = process.env.PORT || 8080;

app.listen(PORT, () => {
    console.log(`Started collage service on port ${PORT}`);
});

Am Ende unserer Quelldatei finden Sie die Anweisungen, dass Express unsere Webanwendung auf dem Standardport 8080 starten soll.

6. Lokal testen

Testen Sie den Code lokal, um sicherzustellen, dass er funktioniert, bevor Sie ihn in der Cloud bereitstellen.

Installieren Sie im Ordner collage/nodejs die npm-Abhängigkeiten und starten Sie den Server:

npm install; npm start

Wenn alles gut gelaufen ist, sollte der Server auf Port 8080 gestartet werden:

Started collage service on port 8080

Verwende zum Beenden CTRL-C.

7. In Cloud Run erstellen und bereitstellen

Legen Sie vor der Bereitstellung in Cloud Run für die Cloud Run-Region eine der unterstützten Regionen und Plattformen auf managed fest:

gcloud config set run/region europe-west1
gcloud config set run/platform managed

Sie können prüfen, ob die Konfiguration festgelegt ist:

gcloud config list

...
[run]
platform = managed
region = europe-west1

Anstatt das Container-Image mit Cloud Build manuell zu erstellen und zu veröffentlichen, können Sie sich auch darauf verlassen, dass Cloud Run das Container-Image mithilfe von Google Cloud Buildpacks für Sie erstellt.

Führen Sie den folgenden Befehl aus, um das Container-Image zu erstellen:

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

Beachten Sie das Flag –-source. Dies ist die quellbasierte Bereitstellung in Cloud Run. Wenn im Quellcodeverzeichnis ein Dockerfile vorhanden ist, wird der hochgeladene Quellcode mit diesem Dockerfile erstellt. Wenn kein Dockerfile im Quellcodeverzeichnis vorhanden ist, erkennen Google Cloud-Buildpacks automatisch die von Ihnen verwendete Sprache und ruft die Abhängigkeiten des Codes ab, um mithilfe eines von Google verwalteten sicheren Basis-Images ein produktionsbereites Container-Image zu erstellen. Dadurch wird Cloud Run zur Verwendung von Google Cloud-Buildpacks gekennzeichnet, um das in Dockerfile definierte Container-Image zu erstellen.

Beachten Sie auch, dass bei der quellbasierten Bereitstellung Artifact Registry zum Speichern erstellter Container verwendet wird. Artifact Registry ist eine moderne Version von Google Container Registry. Die Befehlszeile fordert zum Aktivieren der API auf, falls sie im Projekt noch nicht aktiviert ist, und erstellt ein Repository mit dem Namen cloud-run-source-deploy in der Region, in der Sie die Bereitstellung vornehmen.

Mit dem Flag --no-allow-unauthenticated wird der Cloud Run-Dienst zu einem internen Dienst, der nur von bestimmten Dienstkonten ausgelöst wird.

8. Cloud Scheduler einrichten

Der Cloud Run-Dienst ist nun bereit und bereitgestellt. Als Nächstes erstellen Sie den regulären Zeitplan, um den Dienst jede Minute aufzurufen.

Erstellen Sie ein Dienstkonto:

SERVICE_ACCOUNT=collage-scheduler-sa
gcloud iam service-accounts create $SERVICE_ACCOUNT \
   --display-name "Collage Scheduler Service Account"

Gewähren Sie dem Dienstkonto die Berechtigung zum Aufrufen des Cloud Run-Dienstes:

gcloud run services add-iam-policy-binding $SERVICE_NAME \
   --member=serviceAccount:$SERVICE_ACCOUNT@$GOOGLE_CLOUD_PROJECT.iam.gserviceaccount.com \
   --role=roles/run.invoker

Erstellen Sie einen Cloud Scheduler-Job, der jede Minute ausgeführt wird:

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

Sie können in der Cloud Console zum Abschnitt „Cloud Scheduler“ gehen, um zu sehen, ob er eingerichtet ist und auf die URL des Cloud Run-Dienstes verweist:

35119e28c1da53f3.png

9. Dienst testen

Um zu testen, ob die Einrichtung funktioniert, suchen Sie im Bucket thumbnails nach dem Collagenbild (collage.png). Sie können auch die Logs des Dienstes prüfen:

93922335a384be2e.png

10. Bereinigen (optional)

Wenn Sie nicht vorhaben, mit den anderen Labs dieser Reihe fortzufahren, können Sie Ressourcen bereinigen, um Kosten zu sparen und insgesamt ein guter Cloud-Nutzer zu sein. Sie können Ressourcen wie folgt einzeln bereinigen.

Löschen Sie den Dienst:

gcloud run services delete $SERVICE_NAME -q

Löschen Sie den Cloud Scheduler-Job:

gcloud scheduler jobs delete $SERVICE_NAME-job -q

Alternativ können Sie das gesamte Projekt löschen:

gcloud projects delete $GOOGLE_CLOUD_PROJECT

11. Glückwunsch!

Glückwunsch! Sie haben einen geplanten Dienst erstellt: Dank Cloud Scheduler, der jede Minute eine Nachricht an ein Pub/Sub-Thema sendet, wird Ihr Cloud Run-Collagendienst aufgerufen und kann Bilder zusammenfügen, um ein daraus resultierendes Bild zu erstellen.

Behandelte Themen

  • Cloud Run
  • Cloud Scheduler
  • Cloud Storage
  • Cloud Firestore

Nächste Schritte