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 ani Google Workspace, musisz je utworzyć.



- Nazwa projektu to wyświetlana nazwa 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 modułów z kodem 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 bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.
Uruchamianie Cloud Shell
Z Google Cloud można korzystać zdalnie na laptopie, ale w tym module praktycznym będziesz używać 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 module 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 zakończyć się powodzeniem:
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 wymagane 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 działania naszego kodu i uruchamiamy kod węzła za pomocą polecenia npm start.
index.js
Przyjrzyjmy się bliżej naszemu index.js kodowi:
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 środku tej konstrukcji.
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 do gałęzi else w naszym kodzie.
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ę tworzenia kolażu 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");
Obraz kolażu został zapisany na dysku lokalnym w folderze tymczasowym, więc musimy go teraz przesłać 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 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 oparte na źródle 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 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
W sekcji Cloud Scheduler w konsoli Cloud możesz sprawdzić, czy usługa jest skonfigurowana i wskazuje adres URL usługi Cloud Run:

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 innymi ćwiczeniami z tej serii, możesz usunąć zasoby, aby zaoszczędzić pieniądze i być dobrym użytkownikiem chmury. Możesz zwolnić miejsce, czyszczą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óry 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