1. Wprowadzenie
Omówienie
Funkcje Cloud Run to usługa Google Cloud typu „funkcje jako usługa” oparta na technologii Cloud Run i Eventarc. Zapewnia ona zaawansowane zarządzanie wydajnością i skalowalnością oraz większą kontrolę nad środowiskiem wykonawczym funkcji i aktywatorami z ponad 90 źródeł zdarzeń.
W tym samouczku dowiesz się, jak tworzyć funkcje Cloud Run, które odpowiadają na wywołania HTTP i są wywoływane przez wiadomości Pub/Sub oraz logi kontrolne Cloud.
W tym samouczku używamy też automatycznych aktualizacji obrazu podstawowego na potrzeby wdrożeń funkcji, określając obraz podstawowy za pomocą flagi --base-image. Automatyczne aktualizacje obrazu bazowego w Cloud Run umożliwiają Google automatyczne wprowadzanie poprawek zabezpieczeń do systemu operacyjnego i komponentów środowiska wykonawczego języka obrazu bazowego. Aby zaktualizować obraz bazowy, nie musisz ponownie tworzyć ani wdrażać usługi. Więcej informacji znajdziesz w artykule automatyczne aktualizacje obrazu bazowego.
Jeśli nie chcesz korzystać z automatycznych aktualizacji obrazu bazowego, możesz usunąć flagę --base-image z przykładów podanych w tym samouczku.
Czego się nauczysz
- Omówienie funkcji Cloud Run i sposobu korzystania z automatycznych aktualizacji obrazu podstawowego.
- Jak napisać funkcję, która odpowiada na wywołania HTTP.
- Jak napisać funkcję, która odpowiada na wiadomości Pub/Sub.
- Jak napisać funkcję, która reaguje na zdarzenia Cloud Storage.
- Jak podzielić ruch między 2 wersje.
- Jak uniknąć uruchomień „na zimno” dzięki minimalnej liczbie instancji.
2. Konfiguracja i wymagania
Tworzenie folderu głównego
Utwórz folder główny dla wszystkich przykładów.
mkdir crf-codelab cd crf-codelab
Konfigurowanie zmiennych środowiskowych
Ustaw zmienne środowiskowe, które będą używane w tych ćwiczeniach z programowania.
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
Włącz interfejsy API
Włącz wszystkie niezbędne usługi:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. Funkcja HTTP
W przypadku pierwszej funkcji utwórzmy uwierzytelnioną funkcję Node.js, która odpowiada na żądania HTTP. Użyjmy też 10-minutowego limitu czasu, aby pokazać, jak funkcja może mieć więcej czasu na odpowiedź na żądania HTTP.
Utwórz
Utwórz folder aplikacji i przejdź do niego:
mkdir hello-http cd hello-http
Utwórz plik index.js, który odpowiada na żądania HTTP:
const functions = require('@google-cloud/functions-framework');
functions.http('helloWorld', (req, res) => {
res.status(200).send('HTTP with Node.js in Cloud Run functions!');
});
Utwórz plik package.json, aby określić zależności:
{
"name": "nodejs-run-functions-codelab",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Wdróż
Wdróż funkcję:
gcloud run deploy nodejs-run-function \
--source . \
--function helloWorld \
--base-image nodejs22 \
--region $REGION \
--timeout 600 \
--no-allow-unauthenticated
To polecenie używa pakietów kompilacji do przekształcenia kodu źródłowego funkcji w obraz kontenera gotowy do wykorzystania w środowisku produkcyjnym.
Uwaga:
- Flaga
--sourceinformuje Cloud Run, że funkcja ma zostać skompilowana w usługę opartą na kontenerze, którą można uruchomić. - Flaga
--function(nowa) służy do ustawiania punktu wejścia nowej usługi jako sygnatury funkcji, którą chcesz wywołać. - Flaga
--base-image(nowa) określa środowisko obrazu bazowego dla funkcji, np.nodejs22,python312,go123,java21,dotnet8,ruby33lubphp83. Więcej informacji o obrazach bazowych i pakietach zawartych w każdym obrazie znajdziesz w artykule Obrazy bazowe środowisk wykonawczych. - (opcjonalnie) flaga
--timeoutumożliwia funkcji dłuższy czas oczekiwania na odpowiedź na żądania HTTP. W tym przykładzie użyto 600 sekund, aby zademonstrować 10-minutowy czas reakcji. - (opcjonalnie)
--no-allow-unauthenticated, aby uniemożliwić publiczne wywoływanie funkcji.
Test
Przetestuj funkcję za pomocą tych poleceń:
# get the Service URL SERVICE_URL="$(gcloud run services describe nodejs-run-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
W odpowiedzi powinien pojawić się komunikat HTTP with Node.js in Cloud Run functions!.
4. Funkcja Pub/Sub
W przypadku drugiej funkcji utwórzmy funkcję w Pythonie aktywowaną przez wiadomość Pub/Sub opublikowaną w określonym temacie.
Konfigurowanie tokenów uwierzytelniania Pub/Sub
Jeśli konto usługi Pub/Sub zostało włączone 8 kwietnia 2021 r. lub wcześniej, przypisz rolę iam.serviceAccountTokenCreator do konta usługi Pub/Sub:
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)') gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role roles/iam.serviceAccountTokenCreator
Utwórz
Utwórz temat Pub/Sub, który będzie używany w przykładzie:
TOPIC=cloud-run-functions-pubsub-topic gcloud pubsub topics create $TOPIC
Utwórz folder aplikacji i przejdź do niego:
mkdir ../hello-pubsub cd ../hello-pubsub
Utwórz plik main.py, który rejestruje wiadomość zawierającą identyfikator CloudEvent:
import functions_framework
@functions_framework.cloud_event
def hello_pubsub(cloud_event):
print('Pub/Sub with Python in Cloud Run functions! Id: ' + cloud_event['id'])
Aby określić zależności, utwórz plik requirements.txt o tej treści:
functions-framework==3.*
Wdróż
Wdróż funkcję:
gcloud run deploy python-pubsub-function \
--source . \
--function hello_pubsub \
--base-image python313 \
--region $REGION \
--no-allow-unauthenticated
Pobierz numer projektu, który będzie używany jako tożsamość konta usługi.
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)')
Tworzenie aktywatora
gcloud eventarc triggers create python-pubsub-function-trigger \
--location=$REGION \
--destination-run-service=python-pubsub-function \
--destination-run-region=$REGION \
--event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \
--transport-topic=projects/$PROJECT_ID/topics/$TOPIC \
--service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Test
Przetestuj funkcję, wysyłając wiadomość do tematu:
gcloud pubsub topics publish $TOPIC --message="Hello World"
W logach powinien pojawić się odebrany CloudEvent:
gcloud run services logs read python-pubsub-function --region $REGION --limit=10
5. Funkcja Cloud Storage
W przypadku następnej funkcji utwórzmy funkcję Node.js, która reaguje na zdarzenia z zasobnika Cloud Storage.
Skonfiguruj
Aby korzystać z funkcji Cloud Storage, przypisz rolę pubsub.publisher do konta usługi Cloud Storage:
SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/pubsub.publisher
Utwórz
Utwórz folder aplikacji i przejdź do niego:
mkdir ../hello-storage cd ../hello-storage
Utwórz plik index.js, który po prostu reaguje na zdarzenia Cloud Storage:
const functions = require('@google-cloud/functions-framework');
functions.cloudEvent('helloStorage', (cloudevent) => {
console.log('Cloud Storage event with Node.js in Cloud Run functions!');
console.log(cloudevent);
});
Utwórz plik package.json, aby określić zależności:
{
"name": "nodejs-crf-cloud-storage",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Wdróż
Najpierw utwórz zasobnik Cloud Storage (lub użyj istniejącego zasobnika):
export BUCKET_NAME="gcf-storage-$PROJECT_ID" export BUCKET="gs://gcf-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Wdróż funkcję:
gcloud run deploy nodejs-crf-cloud-storage \ --source . \ --base-image nodejs22 \ --function helloStorage \ --region $REGION \ --no-allow-unauthenticated
Po wdrożeniu funkcji możesz ją zobaczyć w sekcji Cloud Run w Cloud Console.
Teraz utwórz aktywator Eventarc.
BUCKET_REGION=$REGION gcloud eventarc triggers create nodejs-crf-cloud-storage-trigger \ --location=$BUCKET_REGION \ --destination-run-service=nodejs-crf-cloud-storage \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=$BUCKET_NAME" \ --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Test
Przetestuj funkcję, przesyłając plik do zasobnika:
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
W logach powinien pojawić się odebrany CloudEvent:
gcloud run services logs read nodejs-crf-cloud-storage --region $REGION --limit=10
6. Logi kontrolne Cloud
W przypadku następnej funkcji utwórzmy funkcję Node.js, która będzie odbierać zdarzenie Cloud Audit Log, gdy zostanie utworzona instancja maszyny wirtualnej Compute Engine. W odpowiedzi dodaje etykietę do nowo utworzonej maszyny wirtualnej, określając jej twórcę.
Określanie nowo utworzonych maszyn wirtualnych Compute Engine
Gdy tworzona jest maszyna wirtualna, Compute Engine wysyła 2 logi kontrolne.
Pierwsze zdarzenie jest emitowane na początku tworzenia maszyny wirtualnej. Drugi jest emitowany po utworzeniu maszyny wirtualnej.
W logach kontrolnych pola operacji są różne i zawierają wartości first: true i last: true. Drugi dziennik kontrolny zawiera wszystkie informacje potrzebne do oznaczenia instancji, dlatego użyjemy flagi last: true, aby wykryć ją w funkcjach Cloud Run.
Skonfiguruj
Aby korzystać z funkcji Cloud Audit Log, musisz włączyć logi kontrolne dla Eventarc. Musisz też używać konta usługi z rolą eventarc.eventReceiver.
- Włącz dzienniki kontroli Cloud dla typów logów Odczyt przez administratora, Odczyt danych i Zapis danych w przypadku interfejsu Compute Engine API.
- Przyznaj domyślnemu kontu usługi Compute Engine rolę uprawnień
eventarc.eventReceiver:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
Tworzenie funkcji
W tym samouczku używamy node.js, ale inne przykłady znajdziesz na stronie https://github.com/GoogleCloudPlatform/eventarc-samples.
Tworzenie pliku package.json
{
"dependencies": {
"googleapis": "^84.0.0"
}
}
Tworzenie pliku node.js
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const { google } = require("googleapis");
var compute = google.compute("v1");
exports.labelVmCreation = async (cloudevent) => {
const data = cloudevent.body;
// in case an event has >1 audit log
// make sure we respond to the last event
if (!data.operation || !data.operation.last) {
console.log("Operation is not last, skipping event");
return;
}
// projects/dogfood-gcf-saraford/zones/us-central1-a/instances/instance-1
var resourceName = data.protoPayload.resourceName;
var resourceParts = resourceName.split("/");
var project = resourceParts[1];
var zone = resourceParts[3];
var instanceName = resourceParts[5];
var username = data.protoPayload.authenticationInfo.principalEmail.split("@")[0];
console.log(`Setting label username: ${username} to instance ${instanceName} for zone ${zone}`);
var authClient = await google.auth.getClient({
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
});
// per docs: When updating or adding labels in the API,
// you need to provide the latest labels fingerprint with your request,
// to prevent any conflicts with other requests.
var labelFingerprint = await getInstanceLabelFingerprint(authClient, project, zone, instanceName);
var responseStatus = await setVmLabel(
authClient,
labelFingerprint,
username,
project,
zone,
instanceName
);
// log results of setting VM label
console.log(JSON.stringify(responseStatus, null, 2));
};
async function getInstanceLabelFingerprint(authClient, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
auth: authClient
};
var response = await compute.instances.get(request);
var labelFingerprint = response.data.labelFingerprint;
return labelFingerprint;
}
async function setVmLabel(authClient, labelFingerprint, username, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
resource: {
labels: { "creator": username },
labelFingerprint: labelFingerprint
},
auth: authClient
};
var response = await compute.instances.setLabels(request);
return response.statusText;
}
Wdróż
Wdróż funkcję:
gcloud run deploy gce-vm-labeler \ --source . \ --function labelVmCreation \ --region $REGION \ --no-allow-unauthenticated
Teraz utwórz regułę. Zwróć uwagę, jak funkcja filtruje logi kontrolne dotyczące wstawień w Compute Engine z użyciem flagi --trigger-event-filters.
gcloud eventarc triggers create gce-vm-labeler-trigger \ --location=$REGION \ --destination-run-service=gce-vm-labeler \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.audit.log.v1.written,serviceName=compute.googleapis.com,methodName=v1.compute.instances.insert" \ --service-account=$ROJECT_NUMBER-compute@developer.gserviceaccount.com
Test
Ustaw zmienne środowiskowe:
# if you're using europe-west1 as your region
ZONE=europe-west1-d
VM_NAME=codelab-crf-auditlog
Aby utworzyć maszynę wirtualną, uruchom to polecenie:
gcloud compute instances create $VM_NAME --zone=$ZONE --machine-type=e2-medium --image-family=debian-11 --image-project=debian-cloud
Po utworzeniu maszyny wirtualnej w sekcji Informacje podstawowe w konsoli Google Cloud lub za pomocą tego polecenia powinna być widoczna dodana etykieta creator:
gcloud compute instances describe $VM_NAME --zone=$ZONE
W danych wyjściowych powinna się pojawić etykieta, jak w tym przykładzie:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
Czyszczenie danych
Pamiętaj, aby usunąć instancję maszyny wirtualnej. Nie będzie już używana w tym module.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. Dzielenie ruchu
Funkcje Cloud Run obsługują wiele wersji funkcji, dzielenie ruchu między różne wersje i przywracanie funkcji do poprzedniej wersji.
W tym kroku wdrożysz 2 wersje funkcji, a następnie podzielisz między nie ruch w stosunku 50:50.
Utwórz
Utwórz folder aplikacji i przejdź do niego:
mkdir ../traffic-splitting cd ../traffic-splitting
Utwórz plik main.py z funkcją Pythona, która odczytuje zmienną środowiskową koloru i odpowiada komunikatem Hello World w tym kolorze tła:
import os
color = os.environ.get('COLOR')
def hello_world(request):
return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
Aby określić zależności, utwórz plik requirements.txt o tej treści:
functions-framework==3.*
Wdróż
Wdróż pierwszą wersję funkcji z pomarańczowym tłem:
COLOR=orange gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Jeśli w tym momencie przetestujesz funkcję, wyświetlając w przeglądarce aktywator HTTP (adres URI wyjściowy powyższego polecenia wdrożenia), powinna się pojawić ikona Hello World na pomarańczowym tle:

Wdróż drugą wersję z żółtym tłem:
COLOR=yellow gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Ponieważ jest to najnowsza wersja, po przetestowaniu funkcji powinna się wyświetlić wartość Hello World na żółtym tle:

Podziel ruch po równo
Aby podzielić ruch między wersje pomarańczową i żółtą, musisz znaleźć identyfikatory wersji usług Cloud Run. Aby wyświetlić identyfikatory wersji, użyj tego polecenia:
gcloud run revisions list --service hello-world-colors \ --region $REGION --format 'value(REVISION)'
Dane wyjściowe powinny być podobne do tych:
hello-world-colors-00001-man hello-world-colors-00002-wok
Teraz podziel ruch między te 2 wersje w ten sposób (zaktualizuj X-XXX zgodnie z nazwami wersji):
gcloud run services update-traffic hello-world-colors \ --region $REGION \ --to-revisions hello-world-colors-0000X-XXX=50,hello-world-colors-0000X-XXX=50
Test
Przetestuj funkcję, otwierając jej publiczny adres URL. W połowie przypadków powinna się wyświetlać wersja pomarańczowa, a w pozostałych – żółta:

Więcej informacji znajdziesz w artykule Przywracanie, wdrażanie stopniowe oraz migracja ruchu.
8. Minimalna liczba instancji
W funkcjach Cloud Run możesz określić minimalną liczbę instancji funkcji, które mają być utrzymywane w gotowości do obsługi żądań. Pomaga to ograniczyć liczbę uruchomień „na zimno”.
W tym kroku wdrożysz funkcję z powolną inicjalizacją. Zauważysz problem z uruchomieniem „na zimno”. Następnie wdrożysz funkcję z minimalną liczbą instancji ustawioną na 1, aby wyeliminować uruchomienie „na zimno”.
Utwórz
Utwórz folder aplikacji i przejdź do niego:
mkdir ../min-instances cd ../min-instances
Utwórz plik main.go. Ta usługa Go ma funkcję init, która usypia ją na 10 sekund, aby zasymulować długą inicjalizację. Ma też funkcję HelloWorld, która odpowiada na wywołania HTTP:
package p
import (
"fmt"
"net/http"
"time"
)
func init() {
time.Sleep(10 * time.Second)
}
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Slow HTTP Go in Cloud Run functions!")
}
Wdróż
Wdróż pierwszą wersję funkcji z domyślną minimalną wartością instancji równą zero:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated
Przetestuj funkcję za pomocą tego polecenia:
# get the Service URL SERVICE_URL="$(gcloud run services describe go-slow-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Podczas pierwszego połączenia zobaczysz komunikat po 10-sekundowym opóźnieniu (zimny start). Kolejne wywołania powinny być zwracane natychmiast.
Ustawianie minimalnej liczby instancji
Aby uniknąć uruchamiania „na zimno” przy pierwszym żądaniu, ponownie wdróż funkcję z ustawioną na 1 flagą --min-instances w ten sposób:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated \ --min-instances 1
Test
Ponownie przetestuj funkcję:
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
W pierwszym żądaniu nie powinno już być 10-sekundowego opóźnienia. Dzięki minimalnej liczbie instancji problem z uruchomieniem „na zimno” przy pierwszym wywołaniu (po długim czasie bez wywołań) został rozwiązany.
Więcej informacji znajdziesz w artykule o używaniu minimalnej liczby instancji.
9. Gratulacje!
Gratulujemy ukończenia ćwiczenia!
Omówione zagadnienia
- Omówienie funkcji Cloud Run i sposobu korzystania z automatycznych aktualizacji obrazu podstawowego.
- Jak napisać funkcję, która odpowiada na wywołania HTTP.
- Jak napisać funkcję, która odpowiada na wiadomości Pub/Sub.
- Jak napisać funkcję, która reaguje na zdarzenia Cloud Storage.
- Jak podzielić ruch między 2 wersje.
- Jak uniknąć uruchamiania „na zimno” dzięki minimalnej liczbie instancji.