1. Wprowadzenie

Przegląd
Usługi Cloud Run są odpowiednie dla kontenerów, które działają bezterminowo i nasłuchują żądań HTTP, natomiast zadania Cloud Run lepiej sprawdzają się w przypadku kontenerów, które działają do zakończenia (obecnie do 24 godzin) i nie obsługują żądań. Na przykład przetwarzanie rekordów z bazy danych, przetwarzanie listy plików z zasobnika Cloud Storage lub długotrwała operacja, taka jak obliczanie liczby Pi, sprawdzi się w przypadku implementacji jako zadanie Cloud Run.
Zadania nie mogą obsługiwać żądań ani nasłuchiwać na porcie. Oznacza to, że w przeciwieństwie do usług Cloud Run zadania nie powinny zawierać serwera WWW. Zamiast tego kontenery zadań powinny kończyć działanie po zakończeniu pracy.
W zadaniach Cloud Run możesz uruchamiać równolegle wiele kopii kontenera, określając liczbę zadań. Każde zadanie reprezentuje jedną działającą kopię kontenera. Używanie wielu zadań jest przydatne, jeśli każde z nich może niezależnie przetwarzać podzbiór danych. Na przykład przetworzenie 10 tys. rekordów z Cloud SQL lub 10 tys. plików z Cloud Storage może być szybsze, jeśli 10 zadań będzie przetwarzać po 1000 rekordów lub plików równolegle.
Korzystanie z zadań Cloud Run to proces dwuetapowy:
- Utwórz zadanie: obejmuje to całą konfigurację potrzebną do uruchomienia zadania, np. obraz kontenera, region i zmienne środowiskowe.
- Uruchom zadanie: spowoduje to utworzenie nowego wykonania zadania. Opcjonalnie możesz skonfigurować uruchamianie zadania zgodnie z harmonogramem za pomocą usługi Cloud Scheduler.
W tym laboratorium najpierw zapoznasz się z aplikacją Node.js, która robi zrzuty ekranu stron internetowych i zapisuje je w Cloud Storage. Następnie skompilujesz obraz kontenera aplikacji, uruchomisz go w zadaniach Cloud Run, zaktualizujesz zadanie, aby przetwarzać więcej stron internetowych, i uruchomisz je zgodnie z harmonogramem za pomocą Cloud Scheduler.
Czego się nauczysz
- Jak używać aplikacji do robienia zrzutów ekranu ze stron internetowych.
- Jak utworzyć obraz kontenera aplikacji.
- Jak utworzyć zadanie Cloud Run dla aplikacji.
- Jak uruchomić aplikację jako zadanie Cloud Run.
- Jak zaktualizować zadanie.
- Jak zaplanować zadanie za pomocą usługi Cloud Scheduler.
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 uczestników tego projektu. Jest to ciąg znaków, który nie jest używany przez interfejsy API Google. Zawsze możesz ją zaktualizować.
- Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i 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 ćwiczeń z programowania musisz odwoływać się do identyfikatora projektu (zwykle oznaczanego jako
PROJECT_ID). Jeśli wygenerowany identyfikator Ci się nie podoba, możesz wygenerować inny losowy identyfikator. Możesz też spróbować własnej nazwy i sprawdzić, czy jest dostępna. Po tym kroku nie można go zmienić i pozostaje on taki przez cały czas trwania projektu. - Warto wiedzieć, że istnieje trzecia wartość, numer projektu, której 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. Wykonanie tego laboratorium nie będzie kosztować dużo, a może nawet nic. Aby wyłączyć zasoby i uniknąć naliczania opłat po zakończeniu tego samouczka, możesz usunąć utworzone zasoby lub projekt. Nowi użytkownicy Google Cloud mogą skorzystać z programu bezpłatnego okresu próbnego o wartoś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 Google Cloud 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 powinny pojawić się dane wyjściowe podobne do tych:

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. Nie musisz niczego instalować.
Konfigurowanie gcloud
W Cloud Shell ustaw identyfikator projektu i region, w którym chcesz wdrożyć zadanie Cloud Run. Zapisz je jako zmienne PROJECT_ID i REGION. W przyszłości będzie można wybrać region z lokalizacji Cloud Run.
PROJECT_ID=[YOUR-PROJECT-ID] REGION=us-central1 gcloud config set core/project $PROJECT_ID
Włącz interfejsy API
Włącz wszystkie niezbędne usługi:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ run.googleapis.com
3. Pobierz kod
Najpierw zapoznasz się z aplikacją Node.js, która robi zrzuty ekranu stron internetowych i zapisuje je w Cloud Storage. Później utworzysz obraz kontenera dla aplikacji i uruchomisz go jako zadanie w Cloud Run.
W Cloud Shell uruchom to polecenie, aby sklonować kod aplikacji z repozytorium tego:
git clone https://github.com/GoogleCloudPlatform/jobs-demos.git
Przejdź do katalogu zawierającego aplikację:
cd jobs-demos/screenshot
Powinien wyświetlić się taki układ pliku:
screenshot | ├── Dockerfile ├── README.md ├── screenshot.js ├── package.json
Oto krótki opis każdego pliku:
screenshot.jszawiera kod Node.js aplikacji.package.jsonokreśla zależności biblioteki.Dockerfiledefiniuje obraz kontenera.
4. Poznaj kod
Aby przejrzeć kod, użyj wbudowanego edytora tekstu, klikając przycisk Open Editor u góry okna Cloud Shell.

Oto krótki opis każdego pliku.
screenshot.js
screenshot.js najpierw dodaje Puppeteer i Cloud Storage jako zależności. Puppeteer to biblioteka Node.js, której możesz używać do robienia zrzutów ekranu stron internetowych:
const puppeteer = require('puppeteer');
const {Storage} = require('@google-cloud/storage');
Jest funkcja initBrowser do inicjowania Puppeteer i funkcja takeScreenshot do robienia zrzutów ekranu z danego adresu URL:
async function initBrowser() {
console.log('Initializing browser');
return await puppeteer.launch();
}
async function takeScreenshot(browser, url) {
const page = await browser.newPage();
console.log(`Navigating to ${url}`);
await page.goto(url);
console.log(`Taking a screenshot of ${url}`);
return await page.screenshot({
fullPage: true
});
}
Następnie znajduje się funkcja pobierania lub tworzenia zasobnika Cloud Storage oraz kolejna funkcja przesyłania zrzutu ekranu strony internetowej do zasobnika:
async function createStorageBucketIfMissing(storage, bucketName) {
console.log(`Checking for Cloud Storage bucket '${bucketName}' and creating if not found`);
const bucket = storage.bucket(bucketName);
const [exists] = await bucket.exists();
if (exists) {
// Bucket exists, nothing to do here
return bucket;
}
// Create bucket
const [createdBucket] = await storage.createBucket(bucketName);
console.log(`Created Cloud Storage bucket '${createdBucket.name}'`);
return createdBucket;
}
async function uploadImage(bucket, taskIndex, imageBuffer) {
// Create filename using the current time and task index
const date = new Date();
date.setMinutes(date.getMinutes() - date.getTimezoneOffset());
const filename = `${date.toISOString()}-task${taskIndex}.png`;
console.log(`Uploading screenshot as '${filename}'`)
await bucket.file(filename).save(imageBuffer);
}
Funkcja main jest punktem wejścia:
async function main(urls) {
console.log(`Passed in urls: ${urls}`);
const taskIndex = process.env.CLOUD_RUN_TASK_INDEX || 0;
const url = urls[taskIndex];
if (!url) {
throw new Error(`No url found for task ${taskIndex}. Ensure at least ${parseInt(taskIndex, 10) + 1} url(s) have been specified as command args.`);
}
const bucketName = process.env.BUCKET_NAME;
if (!bucketName) {
throw new Error('No bucket name specified. Set the BUCKET_NAME env var to specify which Cloud Storage bucket the screenshot will be uploaded to.');
}
const browser = await initBrowser();
const imageBuffer = await takeScreenshot(browser, url).catch(async err => {
// Make sure to close the browser if we hit an error.
await browser.close();
throw err;
});
await browser.close();
console.log('Initializing Cloud Storage client')
const storage = new Storage();
const bucket = await createStorageBucketIfMissing(storage, bucketName);
await uploadImage(bucket, taskIndex, imageBuffer);
console.log('Upload complete!');
}
main(process.argv.slice(2)).catch(err => {
console.error(JSON.stringify({severity: 'ERROR', message: err.message}));
process.exit(1);
});
Kilka uwag o metodzie main:
- Adresy URL są przekazywane jako argumenty.
- Nazwa zasobnika jest przekazywana jako zdefiniowana przez użytkownika zmienna środowiskowa
BUCKET_NAME. Nazwa zasobnika musi być globalnie unikalna w całej usłudze Google Cloud. - Zmienna środowiskowa
CLOUD_RUN_TASK_INDEXjest przekazywana przez zadania Cloud Run. Zadania Cloud Run mogą uruchamiać wiele kopii aplikacji jako unikalne działania.CLOUD_RUN_TASK_INDEXto indeks uruchomionego zadania. Domyślnie ma wartość zero, gdy kod jest uruchamiany poza zadaniami Cloud Run. Gdy aplikacja jest uruchamiana jako wiele zadań, każde zadanie/kontener pobiera adres URL, za który jest odpowiedzialny, robi zrzut ekranu i zapisuje obraz w zasobniku.
package.json
Plik package.json definiuje aplikację i określa zależności dla Cloud Storage i Puppeteer:
{
"name": "screenshot",
"version": "1.0.0",
"description": "Create a job to capture screenshots",
"main": "screenshot.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Google LLC",
"license": "Apache-2.0",
"dependencies": {
"@google-cloud/storage": "^5.18.2",
"puppeteer": "^13.5.1"
}
}
Dockerfile
Dockerfile definiuje obraz kontenera dla aplikacji ze wszystkimi wymaganymi bibliotekami i zależnościami:
FROM ghcr.io/puppeteer/puppeteer:16.1.0 COPY package*.json ./ RUN npm ci --omit=dev COPY . . ENTRYPOINT ["node", "screenshot.js"]
5. Wdrażanie zadania
Zanim utworzysz zadanie, musisz utworzyć konto usługi, którego będziesz używać do jego uruchamiania.
gcloud iam service-accounts create screenshot-sa --display-name="Screenshot app service account"
Przyznaj kontu usługi rolę storage.admin, aby można było go używać do tworzenia zasobników i obiektów.
gcloud projects add-iam-policy-binding $PROJECT_ID \ --role roles/storage.admin \ --member serviceAccount:screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Możesz teraz wdrożyć zadanie Cloud Run, które zawiera konfigurację potrzebną do jego uruchomienia.
gcloud beta run jobs deploy screenshot \ --source=. \ --args="https://example.com" \ --args="https://cloud.google.com" \ --tasks=2 \ --task-timeout=5m \ --region=$REGION \ --set-env-vars=BUCKET_NAME=screenshot-$PROJECT_ID-$RANDOM \ --service-account=screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Wykorzystuje to wdrażanie na podstawie źródła i tworzy zadanie Cloud Run bez jego wykonywania.
Zwróć uwagę, że strony internetowe są przekazywane jako argumenty. Nazwa zasobnika, w którym mają być zapisywane zrzuty ekranu, jest przekazywana jako zmienna środowiskowa.
Możesz uruchomić równolegle wiele kopii kontenera, określając liczbę zadań do wykonania za pomocą flagi --tasks. Każde zadanie reprezentuje jedną działającą kopię kontenera. Używanie wielu zadań jest przydatne, jeśli każde z nich może niezależnie przetwarzać podzbiór danych. Aby to ułatwić, każde zadanie zna swój indeks, który jest przechowywany w zmiennej środowiskowej CLOUD_RUN_TASK_INDEX. Twój kod odpowiada za określenie, które zadanie obsługuje który podzbiór danych. Zwróć uwagę na symbol --tasks=2 w tym przykładzie. Dzięki temu uruchomimy 2 kontenery dla 2 adresów URL, które chcemy przetworzyć.
Każde zadanie może trwać maksymalnie 24 godziny. Możesz skrócić ten czas oczekiwania za pomocą flagi --task-timeout, tak jak w tym przykładzie. Aby zadanie zakończyło się sukcesem, musisz wykonać wszystkie działania. Domyślnie zadania zakończone niepowodzeniem nie są ponawiane. Możesz skonfigurować ponawianie zadań w przypadku ich niepowodzenia. Jeśli którekolwiek zadanie przekroczy liczbę ponownych prób, całe zadanie się nie powiedzie.
Domyślnie zadanie będzie uruchamiać jak najwięcej działań równolegle. Będzie to liczba zadań w Twoim projekcie, maksymalnie 100. W przypadku zadań, które uzyskują dostęp do backendu o ograniczonej skalowalności, możesz ustawić niższą równoległość. Na przykład baza danych, która obsługuje ograniczoną liczbę aktywnych połączeń. Możesz zmniejszyć wczytywanie równoległe za pomocą flagi --parallelism.
6. Uruchom zadanie
Przed uruchomieniem zadania wyświetl listę zadań, aby sprawdzić, czy zostało ono utworzone:
gcloud run jobs list ✔ JOB: screenshot REGION: us-central LAST RUN AT: CREATED: 2022-02-22 12:20:50 UTC
Uruchom zadanie za pomocą tego polecenia:
gcloud run jobs execute screenshot --region=$REGION
Spowoduje to wykonanie zadania. Możesz wyświetlić listę bieżących i wcześniejszych wykonań:
gcloud run jobs executions list --job screenshot --region=$REGION ... JOB: screenshot EXECUTION: screenshot-znkmm REGION: $REGION RUNNING: 1 COMPLETE: 1 / 2 CREATED: 2022-02-22 12:40:42 UTC
Opisz wykonanie. Powinien wyświetlić się zielony znacznik wyboru i komunikat tasks completed successfully:
gcloud run jobs executions describe screenshot-znkmm --region=$REGION ✔ Execution screenshot-znkmm in region $REGION 2 tasks completed successfully Image: $REGION-docker.pkg.dev/$PROJECT_ID/containers/screenshot at 311b20d9... Tasks: 2 Args: https://example.com https://cloud.google.com Memory: 1Gi CPU: 1000m Task Timeout: 3600s Parallelism: 2 Service account: 11111111-compute@developer.gserviceaccount.com Env vars: BUCKET_NAME screenshot-$PROJECT_ID-$RANDOM
Stan możesz też sprawdzić na stronie zadań Cloud Run w konsoli Cloud:

Jeśli sprawdzisz zasobnik Cloud Storage, zobaczysz 2 utworzone pliki z zrzutami ekranu:

Czasami może być konieczne zatrzymanie wykonania przed jego zakończeniem, np. gdy zorientujesz się, że musisz uruchomić zadanie z innymi parametrami, lub gdy w kodzie wystąpi błąd i nie chcesz niepotrzebnie wykorzystywać czasu obliczeniowego.
Aby zatrzymać wykonywanie zadania, musisz je usunąć:
gcloud run jobs executions delete screenshot-znkmm --region=$REGION
7. Aktualizowanie zadania
Nowe wersje kontenera nie są automatycznie wybierane przez zadania Cloud Run podczas następnego wykonania. Jeśli zmienisz kod zadania, musisz ponownie utworzyć kontener i zaktualizować zadanie. Używanie otagowanych obrazów pomoże Ci określić, która wersja obrazu jest obecnie używana.
Podobnie, jeśli chcesz zaktualizować niektóre zmienne konfiguracji, musisz też zaktualizować zadanie. Kolejne wykonania zadania będą korzystać z nowego kontenera i ustawień konfiguracji.
Zaktualizuj zadanie i zmień strony, z których aplikacja robi zrzuty ekranu, za pomocą flagi --args. Zaktualizuj też flagę --tasks, aby odzwierciedlała liczbę stron.
gcloud run jobs update screenshot \ --args="https://www.pinterest.com" \ --args="https://www.apartmenttherapy.com" \ --args="https://www.google.com" \ --region=$REGION \ --tasks=3
Ponownie uruchom zadanie. Przekaż ten czas w parametrze --wait, aby poczekać na zakończenie działań:
gcloud run jobs execute screenshot --region=$REGION --wait
Po kilku sekundach w zasobniku powinny pojawić się 3 kolejne zrzuty ekranu:

8. Planowanie zadania
Dotychczas zadania były uruchamiane ręcznie. W rzeczywistości prawdopodobnie chcesz uruchamiać zadania w odpowiedzi na zdarzenie lub zgodnie z harmonogramem. Zobaczmy, jak uruchomić zadanie zrzutu ekranu zgodnie z harmonogramem za pomocą usługi Cloud Scheduler.
Najpierw upewnij się, że interfejs Cloud Scheduler API jest włączony:
gcloud services enable cloudscheduler.googleapis.com
Otwórz stronę szczegółów zadań Cloud Run i kliknij sekcję Triggers:

Kliknij przycisk Add Scheduler Trigger:

Po prawej stronie otworzy się panel. Utwórz zadanie usługi Scheduler, które będzie uruchamiane codziennie o godzinie 9:00 z tą konfiguracją, i kliknij Continue:

Na następnej stronie wybierz domyślne konto usługi obliczeniowej i kliknij Create:

Powinna się teraz wyświetlać nowo utworzona reguła Cloud Scheduler:

Kliknij View Details, aby otworzyć stronę Cloud Scheduler.
Możesz poczekać do godziny 9:00, aż harmonogram zostanie uruchomiony, lub ręcznie uruchomić Cloud Scheduler, klikając Force Run:

Po kilku sekundach powinno pojawić się powiadomienie o pomyślnym wykonaniu zadania Cloud Scheduler:

Powinny się też pojawić 3 dodatkowe zrzuty ekranu dodane przez wywołanie z Cloud Scheduler:

9. Gratulacje
Gratulacje! Codelab został ukończony.
Czyszczenie (opcjonalnie)
Aby uniknąć obciążenia konta opłatami, warto usunąć zasoby.
Jeśli nie potrzebujesz projektu, możesz go po prostu usunąć:
gcloud projects delete $PROJECT_ID
Jeśli potrzebujesz projektu, możesz usunąć poszczególne zasoby.
Usuń kod źródłowy:
rm -rf ~/jobs-demos/
Usuń repozytorium Artifact Registry:
gcloud artifacts repositories delete containers --location=$REGION
Usuń konto usługi:
gcloud iam service-accounts delete screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Usuń zadanie Cloud Run:
gcloud run jobs delete screenshot --region=$REGION
Usuń zadanie Cloud Scheduler:
gcloud scheduler jobs delete screenshot-scheduler-trigger --location=$REGION
Usuń zasobnik Cloud Storage:
gcloud storage rm --recursive gs://screenshot-$PROJECT_ID
Omówione zagadnienia
- Jak używać aplikacji do robienia zrzutów ekranu ze stron internetowych.
- Jak utworzyć obraz kontenera aplikacji.
- Jak utworzyć zadanie Cloud Run dla aplikacji.
- Jak uruchomić aplikację jako zadanie Cloud Run.
- Jak zaktualizować zadanie.
- Jak zaplanować zadanie za pomocą usługi Cloud Scheduler.