1. Przegląd
W tym module szkoleniowym utworzysz nową usługę Cloud Run o nazwie collage service, która będzie wywoływana przez Cloud Scheduler w regularnych odstępach czasu. Usługa pobiera najnowsze przesłane zdjęcia i tworzy z nich kolaż: znajduje listę ostatnich zdjęć w Cloud Firestore, a następnie pobiera pliki zdjęć z Cloud Storage.

Czego się nauczysz
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail lub Google Workspace, musisz je utworzyć.



- Nazwa projektu to wyświetlana nazwa dla uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Możesz go w dowolnym momencie zaktualizować.
- Identyfikator projektu musi być unikalny we wszystkich projektach Google Cloud i jest niezmienny (nie można go zmienić po ustawieniu). Konsola Cloud automatycznie generuje unikalny ciąg znaków. Zwykle nie musisz się nim przejmować. W większości przewodników programistycznych musisz odwoływać się do identyfikatora projektu (zwykle oznaczanego jako
PROJECT_ID). Jeśli Ci się nie podoba, wygeneruj inny losowy identyfikator lub spróbuj użyć własnego i sprawdź, czy jest dostępny. Po utworzeniu projektu jest on „zamrażany”. - Istnieje też trzecia wartość, czyli numer projektu, którego używają niektóre interfejsy API. Więcej informacji o tych 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć płatności w konsoli Cloud, aby korzystać z zasobów i interfejsów API Google Cloud. Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Aby wyłączyć zasoby i uniknąć naliczenia opłat po zakończeniu tego samouczka, postępuj zgodnie z instrukcjami „czyszczenia” na końcu ćwiczenia. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.
Uruchom Cloud Shell
Z Google Cloud można korzystać zdalnie na laptopie, ale w tym ćwiczeniu użyjesz Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
W konsoli GCP kliknij ikonę Cloud Shell na pasku narzędzi w prawym górnym rogu:

Uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil. Po zakończeniu powinno wyświetlić się coś takiego:

Ta maszyna wirtualna zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Wszystkie zadania w tym laboratorium możesz wykonać w przeglądarce.
3. Włącz interfejsy API
Aby regularnie wywoływać usługę Cloud Run, potrzebujesz usługi Cloud Scheduler. Sprawdź, czy jest włączona:
gcloud services enable cloudscheduler.googleapis.com
Operacja powinna się zakończyć:
Operation "operations/acf.5c5ef4f6-f734-455d-b2f0-ee70b5a17322" finished successfully.
4. Klonowanie kodu
Sklonuj kod, jeśli nie masz go jeszcze z poprzedniego modułu:
git clone https://github.com/GoogleCloudPlatform/serverless-photosharing-workshop
Następnie możesz przejść do katalogu zawierającego usługę:
cd serverless-photosharing-workshop/services/collage/nodejs
Usługa będzie miała ten układ pliku:
services
|
├── collage
|
├── nodejs
|
├── Dockerfile
├── index.js
├── package.json
W folderze znajdują się 3 pliki:
index.jszawiera kod Node.js.package.jsonokreśla zależności biblioteki.Dockerfiledefiniuje obraz kontenera.
5. Poznaj kod
Zależności
Plik package.json określa potrzebne zależności biblioteki:
{
"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"
}
}
Do odczytywania i zapisywania plików obrazów w Cloud Storage używamy biblioteki Cloud Storage. Deklarujemy zależność od Cloud Firestore, aby pobrać metadane obrazu, które zostały wcześniej zapisane. Express to platforma internetowa JavaScript / Node. Bluebird służy do obsługi obietnic, a imagemagick to biblioteka do manipulowania obrazami.
Dockerfile
Dockerfile określa obraz kontenera aplikacji:
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" ]
Używamy lekkiego obrazu podstawowego Node 14. Instalujemy bibliotekę imagemagick. Następnie instalujemy moduły NPM potrzebne do naszego kodu i uruchamiamy kod węzła za pomocą polecenia npm start.
index.js
Przyjrzyjmy się bliżej naszemu 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');
Wymagamy różnych zależności potrzebnych do działania naszego programu: Express to platforma internetowa Node, której będziemy używać, ImageMagick to biblioteka do manipulowania obrazami, Bluebird to biblioteka do obsługi obietnic JavaScript, Path służy do obsługi ścieżek plików i katalogów, a Storage i Firestore służą odpowiednio do pracy z Google Cloud Storage (naszymi zasobnikami obrazów) i magazynem danych 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);
}
});
Powyżej widzimy strukturę naszego modułu obsługi Node.js: nasza aplikacja odpowiada na żądania HTTP GET. Wprowadzamy też obsługę błędów na wypadek, gdyby coś poszło nie tak. Przyjrzyjmy się teraz, co znajduje się w tej strukturze.
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 {
/* ... */
}
Nasza usługa kolażu wymaga co najmniej 4 zdjęć (z wygenerowanymi miniaturami), więc najpierw prześlij 4 zdjęcia.
Pobieramy 4 najnowsze zdjęcia przesłane przez użytkowników z metadanych przechowywanych w Cloud Firestore. Sprawdzamy, czy wynikowa kolekcja jest pusta, a następnie przechodzimy dalej w gałęzi else naszego kodu.
Zbierzmy listę nazw plików:
snapshot.forEach(doc => {
thumbnailFiles.push(doc.id);
});
console.log(`Picture file names: ${JSON.stringify(thumbnailFiles)}`);
Pobierzemy każdy z tych plików z segmentu miniatur, którego nazwa pochodzi ze zmiennej środowiskowej ustawionej w momencie wdrażania:
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');
Po przesłaniu najnowszych miniatur użyjemy biblioteki ImageMagick, aby utworzyć siatkę 4x4 z tych miniatur. Używamy biblioteki Bluebird i jej implementacji Promise, aby przekształcić kod oparty na wywołaniach zwrotnych w kod przyjazny dla async / await, a następnie czekamy na obietnicę, która tworzy kolaż obrazów:
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");
Ponieważ kolaż został zapisany lokalnie na dysku w folderze tymczasowym, musimy teraz przesłać go do Cloud Storage, a następnie zwrócić odpowiedź z informacją o powodzeniu (kod stanu 2xx):
await thumbBucket.upload(collagePath);
console.log("Uploaded collage to Cloud Storage bucket ${process.env.BUCKET_THUMBNAILS}");
res.status(204).send("Collage created.");
Teraz czas, aby skrypt Node nasłuchiwał przychodzących żądań:
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Started collage service on port ${PORT}`);
});
Na końcu pliku źródłowego znajdują się instrukcje, które powodują, że Express uruchamia aplikację internetową na domyślnym porcie 8080.
6. Testowanie lokalne
Przed wdrożeniem w chmurze przetestuj kod lokalnie, aby sprawdzić, czy działa.
W folderze collage/nodejs zainstaluj zależności npm i uruchom serwer:
npm install; npm start
Jeśli wszystko przebiegło pomyślnie, serwer powinien zostać uruchomiony na porcie 8080:
Started collage service on port 8080
Aby wyjść, użyj CTRL-C.
7. Kompilowanie i wdrażanie w Cloud Run
Przed wdrożeniem w Cloud Run ustaw region Cloud Run na jeden z obsługiwanych regionów, a platformę na managed:
gcloud config set run/region europe-west1 gcloud config set run/platform managed
Możesz sprawdzić, czy konfiguracja jest ustawiona:
gcloud config list ... [run] platform = managed region = europe-west1
Zamiast ręcznie tworzyć i publikować obraz kontenera za pomocą Cloud Build, możesz też polegać na Cloud Run, który utworzy obraz kontenera za Ciebie za pomocą pakietów kompilacji Google Cloud.
Aby utworzyć obraz kontenera, uruchom to polecenie:
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
Zwróć uwagę na flagę –-source. Jest to wdrożenie oparte na źródle w Cloud Run. Jeśli w katalogu kodu źródłowego znajduje się plik Dockerfile, przesłany kod źródłowy jest kompilowany przy użyciu tego pliku Dockerfile. Jeśli w katalogu kodu źródłowego nie ma pliku Dockerfile, pakiety kompilacji Google Cloud automatycznie wykrywają używany język i pobierają zależności kodu, aby utworzyć obraz kontenera gotowy do wykorzystania w środowisku produkcyjnym, używając bezpiecznego obrazu bazowego zarządzanego przez Google. Oznacza to, że Cloud Run ma używać pakietów kompilacji Google Cloud do tworzenia obrazu kontenera zdefiniowanego w Dockerfile.
Pamiętaj też, że wdrożenie na podstawie źródła korzysta z Artifact Registry do przechowywania utworzonych kontenerów. Artifact Registry to nowoczesna wersja Google Container Registry. CLI wyświetli prośbę o włączenie interfejsu API, jeśli nie jest on jeszcze włączony w projekcie, i utworzy repozytorium o nazwie cloud-run-source-deploy w regionie, w którym wdrażasz.
Flaga --no-allow-unauthenticated sprawia, że usługa Cloud Run staje się usługą wewnętrzną, która będzie wywoływana tylko przez określone konta usługi.
8. Konfigurowanie Cloud Scheduler
Usługa Cloud Run jest już gotowa i wdrożona, więc możemy utworzyć regularny harmonogram, aby wywoływać usługę co minutę.
Utwórz konto usługi:
SERVICE_ACCOUNT=collage-scheduler-sa gcloud iam service-accounts create $SERVICE_ACCOUNT \ --display-name "Collage Scheduler Service Account"
Przyznaj kontu usługi uprawnienia do wywoływania usługi 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
Utwórz zadanie Cloud Scheduler, które będzie wykonywane co 1 minutę:
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
Aby sprawdzić, czy usługa Cloud Scheduler jest skonfigurowana i wskazuje adres URL usługi Cloud Run, otwórz sekcję Cloud Scheduler w konsoli Cloud:

9. Testowanie usługi
Aby sprawdzić, czy konfiguracja działa, poszukaj w zasobniku thumbnails obrazu kolażu (o nazwie collage.png). Możesz też sprawdzić logi usługi:
10. Zwalnianie miejsca (opcjonalnie)
Jeśli nie zamierzasz kontynuować pracy z pozostałymi ćwiczeniami z tej serii, możesz zwalniać miejsce, aby zaoszczędzić koszty i być dobrym obywatelem chmury. Możesz zwolnić miejsce, usuwając poszczególne zasoby w ten sposób.
Usuń usługę:
gcloud run services delete $SERVICE_NAME -q
Usuń zadanie Cloud Scheduler:
gcloud scheduler jobs delete $SERVICE_NAME-job -q
Możesz też usunąć cały projekt:
gcloud projects delete $GOOGLE_CLOUD_PROJECT
11. Gratulacje!
Gratulacje! Utworzono usługę zaplanowaną: dzięki Cloud Scheduler, która co minutę wysyła wiadomość do tematu Pub/Sub, usługa kolażu Cloud Run jest wywoływana i może łączyć zdjęcia, aby utworzyć wynikowy obraz.
Omówione zagadnienia
- Cloud Run
- Cloud Scheduler
- Cloud Storage
- Cloud Firestore