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ługo trwająca operacja, taka jak obliczanie liczby Pi, sprawdzi się w przypadku wdrożenia 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 zadanie 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 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 ćwiczeniu 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 dla 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 jeszcze 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 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 ćwiczeniu użyjesz 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 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. 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. Następnie 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
Układ pliku powinien wyglądać tak:
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. W tym celu kliknij przycisk Open Editor u góry okna Cloud Shell.

Oto krótkie wyjaśnienie 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. - Zadania Cloud Run przekazują zmienną środowiskową
CLOUD_RUN_TASK_INDEX. Zadania Cloud Run mogą uruchamiać wiele kopii aplikacji jako unikalne działania.CLOUD_RUN_TASK_INDEXoznacza 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 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 zadanie 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 znak --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 być wykonywane przez maksymalnie 24 godziny. Możesz skrócić ten czas oczekiwania za pomocą flagi --task-timeout, jak w tym przykładzie. Aby zadanie zostało wykonane, 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 uruchamiane z jak największą liczbą równoległych działań. 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 jego listę, aby sprawdzić, czy zostało 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
Uruchom zadanie ponownie. Przekaż ten czas w parametrze --wait, aby poczekać na zakończenie wykonania:
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 wybierz Continue:

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

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

Kliknij View Details, aby otworzyć stronę Cloud Scheduler.
Możesz poczekać do godziny 9:00, aż harmonogram zacznie działać, 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.