1. Wprowadzenie
Omówienie
Usługi Cloud Run dobrze sprawdzają się w przypadku kontenerów, które działają bezterminowo i nasłuchują żądań HTTP. Z kolei zadania w Cloud Run lepiej sprawdzają się w przypadku kontenerów, które działają do końca (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 (np. obliczanie liczby π) to dobre rozwiązanie, gdy zostanie wdrożone jako zadanie Cloud Run.
Zadania nie mają możliwości obsługi żądań ani nasłuchiwania na porcie. Oznacza to, że w przeciwieństwie do usług Cloud Run zadania nie powinny być połączone z serwerem WWW. Zamiast tego kontenery zadań powinny być zamykane po zakończeniu.
Określ liczbę działań, aby w zadaniach Cloud Run równolegle uruchamiać wiele kopii kontenera. Każde zadanie odpowiada jednej bieżącej kopii kontenera. Używanie wielu zadań jest przydatne, jeśli każde z nich może niezależnie przetwarzać podzbiór danych. Na przykład przetwarzanie 10 tys. rekordów z Cloud SQL lub 10 000 plików z Cloud Storage można było wykonać szybciej, gdyby 10 zadań przetwarzało 1000 rekordów lub plików jednocześnie.
Korzystanie z zadań Cloud Run to proces dwuetapowy:
- Utwórz zadanie:zawiera całą konfigurację potrzebną do uruchomienia zadania, w tym obraz kontenera, region i zmienne środowiskowe.
- Uruchomienie zadania: powoduje utworzenie nowego wykonania zadania. Opcjonalnie możesz skonfigurować zadanie tak, aby było uruchamiane zgodnie z harmonogramem za pomocą usługi Cloud Scheduler.
W ramach tego ćwiczenia w Codelabs dowiesz się, jak używać aplikacji Node.js i robisz zrzuty ekranu stron internetowych, a następnie zapisujesz je w Cloud Storage. Następnie utworzysz obraz kontenera aplikacji, uruchomisz go w zadaniach Cloud Run, zaktualizujesz zadanie, aby przetwarzało więcej stron internetowych, i uruchamiaj je zgodnie z harmonogramem za pomocą usługi Cloud Scheduler.
Czego się nauczysz
- Jak używać aplikacji do robienia zrzutów ekranu ze stronami internetowymi.
- 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 wykorzystaj już istniejący. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.
- Nazwa projektu jest wyświetlaną nazwą uczestników tego projektu. To ciąg znaków, który nie jest używany przez interfejsy API Google. W każdej chwili możesz ją zaktualizować.
- Identyfikator projektu jest unikalny we wszystkich projektach Google Cloud i nie można go zmienić (po jego ustawieniu nie można go zmienić). Cloud Console automatycznie wygeneruje unikalny ciąg znaków. zwykle nieważne, co ona jest. W większości ćwiczeń w Codelabs musisz podać swój identyfikator projektu (zwykle identyfikowany jako
PROJECT_ID
). Jeśli nie podoba Ci się wygenerowany identyfikator, możesz wygenerować kolejny losowy. Możesz też spróbować własnych sił i sprawdzić, czy jest dostępna. Po wykonaniu tej czynności nie można jej już zmienić. Pozostanie ona przez cały czas trwania projektu. - Jest jeszcze trzecia wartość, numer projektu, z którego korzystają niektóre interfejsy API. Więcej informacji o wszystkich 3 wartościach znajdziesz w dokumentacji.
- Następnie musisz włączyć płatności w Cloud Console, aby korzystać z zasobów Cloud/interfejsów API. Ukończenie tego ćwiczenia z programowania nic nie kosztuje. Aby wyłączyć zasoby w celu uniknięcia 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
Google Cloud można obsługiwać zdalnie z laptopa, ale w ramach tego ćwiczenia z programowania wykorzystasz Google Cloud Shell – środowisko wiersza poleceń działające w chmurze.
W konsoli Google Cloud kliknij ikonę Cloud Shell na górnym pasku narzędzi:
Uzyskanie dostępu do środowiska i połączenie się z nim powinno zająć tylko kilka chwil. Po zakończeniu powinno pojawić się coś takiego:
Ta maszyna wirtualna ma wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, znacząco zwiększając wydajność sieci i uwierzytelnianie. Wszystkie zadania w ramach tego ćwiczenia z programowania można wykonywać 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 jednej 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 zapoznaj się z aplikacją Node.js, aby zrobić zrzuty ekranu stron internetowych i zapisać je w Cloud Storage. Później utworzysz obraz kontenera aplikacji i uruchomisz go jako zadanie w Cloud Run.
Aby skopiować kod aplikacji z tego repozytorium, uruchom w Cloud Shell to polecenie:
git clone https://github.com/GoogleCloudPlatform/jobs-demos.git
Przejdź do katalogu zawierającego aplikację:
cd jobs-demos/screenshot
Powinien pojawić się taki układ pliku:
screenshot | ├── Dockerfile ├── README.md ├── screenshot.js ├── package.json
Oto krótki opis każdego pliku:
screenshot.js
zawiera kod Node.js aplikacji.package.json
definiuje zależności biblioteki.Dockerfile
definiuje obraz kontenera.
4. Zapoznaj się z kodem
Aby zapoznać się z kodem, 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 z tych plików.
screenshot.js
screenshot.js
najpierw dodaje Puppeteer i Cloud Storage jako zależności. Puppeteer to biblioteka środowiska Node.js, której używasz do robienia zrzutów ekranu stron internetowych:
const puppeteer = require('puppeteer'); const {Storage} = require('@google-cloud/storage');
Istnieje funkcja initBrowser
do inicjowania Puppeteer oraz 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 }); }
Kolejna funkcja pozwala pobrać lub utworzyć zasobnik Cloud Storage albo dodać do zasobnika zrzut ekranu strony internetowej:
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); }
Na koniec 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); });
Zwróć uwagę na te kwestie 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 we wszystkich usługach Google Cloud. - Zmienna środowiskowa
CLOUD_RUN_TASK_INDEX
jest przekazywana przez zadania Cloud Run. Zadania Cloud Run mogą uruchamiać wiele kopii aplikacji jako unikalne zadania.CLOUD_RUN_TASK_INDEX
reprezentuje indeks uruchomionego zadania. Wartość domyślna to 0, gdy kod jest uruchamiany poza zadaniami Cloud Run. Gdy aplikacja jest uruchamiana jako kilka zadań, każde zadanie/kontener pobiera URL, za który odpowiada, 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
określa 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 uruchamiania zadania.
gcloud iam service-accounts create screenshot-sa --display-name="Screenshot app service account"
Przypisz do konta usługi rolę storage.admin
, aby mogła być używana 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ę niezbędną 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 \ --service-account=screenshot-sa@$PROJECT_ID.iam.gserviceaccount.com
Wykorzystuje wdrożenie na podstawie źródła i tworzy zadanie Cloud Run bez jego wykonania.
Zwróć uwagę, że strony internetowe są przekazywane jako argumenty. Nazwa zasobnika, w którym można zapisać zrzuty ekranu, jest przekazywana jako zmienna środowiskowa.
Możesz równolegle uruchamiać wiele kopii kontenera, określając liczbę zadań do uruchomienia z flagą --tasks
. Każde zadanie odpowiada jednej bieżącej kopii 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 wybrany podzbiór danych. Zwróć uwagę na --tasks=2
w tym fragmencie. Dzięki temu 2 kontenery będą działać w przypadku 2 adresów URL, które chcemy przetworzyć.
Każde zadanie może działać przez maksymalnie 24 godziny. Możesz skrócić ten czas za pomocą flagi --task-timeout
, jak w tym przykładzie. Aby zadanie zostało ukończone, wszystkie zadania muszą zostać zakończone powodzeniem. Domyślnie nieudane zadania nie są ponawiane. Możesz skonfigurować powtarzanie zadań, które mają być ponawiane w przypadku niepowodzenia. Jeśli któreś zadanie przekroczy liczbę ponownych prób, całe zadanie zakończy się niepowodzeniem.
Domyślnie Twoje zadanie będzie uruchamiane z jak największą liczbą zadań równolegle. Jest ona równa liczbie zadań dla Twojego zadania i może wynosić maksymalnie 100. Możesz zmniejszyć poziom równoległości w przypadku zadań uzyskujących dostęp do backendu o ograniczonej skalowalności. Może to być na przykład baza danych, która obsługuje ograniczoną liczbę aktywnych połączeń. Możesz zmniejszyć poziom równoległości za pomocą flagi --parallelism
.
6. Uruchom zadanie
Przed uruchomieniem zadania wyświetl 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. Powinny się wyświetlić 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
Stan możesz też sprawdzić na stronie zadań Cloud Run w konsoli Cloud:
W zasobniku Cloud Storage powinny być widoczne 2 utworzone pliki zrzutów ekranu:
Czasami konieczne może być zatrzymanie wykonania przed jego zakończeniem – na przykład dlatego, że zdajesz sobie sprawę, że musisz uruchomić zadanie z innymi parametrami lub w kodzie występuje błąd i nie chcesz używać niepotrzebnego czasu obliczeniowego.
Aby zatrzymać wykonanie zadania, musisz je usunąć:
gcloud run jobs executions delete screenshot-znkmm --region=$REGION
7. Aktualizowanie zadania
Nowe wersje kontenera nie będą automatycznie pobierane przez zadania Cloud Run przy następnym wykonaniu. Jeśli zmienisz kod zadania, musisz ponownie skompilować kontener i zaktualizować zadanie. Użycie otagowanych obrazów pomoże Ci ustalić, która wersja obrazu jest obecnie używana.
Podobnie musisz też zaktualizować zadanie, jeśli chcesz zaktualizować niektóre zmienne konfiguracji. Kolejne wykonania zadania będą korzystać z nowego kontenera i ustawień konfiguracji.
Zaktualizuj zadanie i zmień strony, których aplikacja robi zrzuty ekranu, we fladze --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. Ten przedział czasu we fladze --wait
w oczekiwaniu na zakończenie wykonań:
gcloud run jobs execute screenshot --region=$REGION --wait
Po kilku sekundach do zasobnika powinny pojawić się jeszcze 3 zrzuty ekranu:
8. Zaplanuj zadanie
Obecnie uruchamiasz zadania ręcznie. W rzeczywistości możesz prawdopodobnie uruchamiać zadania w odpowiedzi na wydarzenie 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ę z informacjami o zadaniach Cloud Run i kliknij sekcję Triggers
:
Kliknij przycisk Add Scheduler Trigger
:
Po prawej stronie wyświetli się panel. Utwórz zadanie algorytmu szeregowania, które będzie uruchamiane codziennie o 9:00 z tą konfiguracją, i wybierz Continue
:
Na następnej stronie wybierz domyślne konto usługi Compute i kliknij Create
:
Powinien zostać utworzony nowy aktywator Cloud Scheduler:
Kliknij View Details
, aby otworzyć stronę usługi Cloud Scheduler.
Możesz zaczekać do 9:00, aż algorytm szeregowania zacznie działać. Możesz też ręcznie aktywować Cloud Scheduler, wybierając Force Run
:
Po kilku sekundach zadanie Cloud Scheduler powinno zostać wykonane:
Powinny być również widoczne 3 dodatkowe zrzuty ekranu dodane przez wywołanie pochodzące z usługi Cloud Scheduler:
9. Gratulacje
Gratulacje. Udało Ci się ukończyć ćwiczenia z programowania.
Czyszczenie (opcjonalnie)
Aby uniknąć opłat, warto wyczyścić zasoby.
Jeśli nie potrzebujesz projektu, możesz go po prostu usunąć:
gcloud projects delete $PROJECT_ID
Jeśli potrzebujesz projektu, możesz usuwać zasoby pojedynczo.
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 stronami internetowymi.
- 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.