1. Введение
Обзор
Cloud Run Functions — это сервис Google Cloud Functions-as-a-Service, работающий на базе Cloud Run и Eventarc , предоставляющий более широкий контроль над производительностью и масштабируемостью, а также над средой выполнения функций и триггерами из более чем 90 источников событий.
В этом практическом занятии вы узнаете, как создавать функции Cloud Run, которые отвечают на HTTP-запросы и запускаются сообщениями Pub/Sub и журналами аудита Cloud.
В этом практическом занятии также используется автоматическое обновление базового образа для развертывания функций путем указания базового образа с помощью флага --base-image . Автоматическое обновление базового образа для Cloud Run позволяет Google автоматически вносить исправления безопасности в компоненты операционной системы и среды выполнения языка программирования, входящие в базовый образ. Вам не нужно пересобирать или повторно развертывать сервис для обновления базового образа. Для получения дополнительной информации ознакомьтесь с информацией об автоматическом обновлении базового образа.
Если вы предпочитаете не использовать автоматическое обновление базового образа, вы можете удалить флаг --base-image из примеров, показанных в этом практическом руководстве.
Что вы узнаете
- Обзор функций Cloud Run и способов использования автоматического обновления базового образа.
- Как написать функцию, которая отвечает на HTTP-запросы.
- Как написать функцию, которая обрабатывает сообщения в режиме Pub/Sub.
- Как написать функцию, которая реагирует на события в Cloud Storage.
- Как распределить трафик между двумя версиями.
- Как избавиться от проблем с холодным запуском при минимальном количестве экземпляров системы.
2. Настройка и требования
Создайте корневую папку
Создайте корневую папку для всех примеров.
mkdir crf-codelab cd crf-codelab
Настройте переменные среды
Установите переменные окружения, которые будут использоваться на протяжении всего этого практического занятия.
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
Включить API
Включите все необходимые службы:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. Функция HTTP
Для первой функции давайте создадим аутентифицированную функцию Node.js, которая отвечает на HTTP-запросы. Также давайте используем 10-минутный тайм-аут, чтобы показать, как функция может иметь больше времени для ответа на HTTP-запросы.
Создавать
Создайте папку для приложения и перейдите в эту папку:
mkdir hello-http cd hello-http
Создайте файл index.js , который будет обрабатывать 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!');
});
Создайте файл package.json , чтобы указать зависимости:
{
"name": "nodejs-run-functions-codelab",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Развертывать
Разверните функцию:
gcloud run deploy nodejs-run-function \
--source . \
--function helloWorld \
--base-image nodejs22 \
--region $REGION \
--timeout 600 \
--no-allow-unauthenticated
Эта команда использует buildpacks для преобразования исходного кода вашей функции в готовый к использованию в производственной среде образ контейнера.
Обратите внимание на следующее:
- Флаг
--sourceиспользуется для того, чтобы указать Cloud Run скомпилировать функцию в исполняемый контейнерный сервис. - Флаг
--function(новый) используется для установки точки входа нового сервиса в качестве сигнатуры функции, которую вы хотите вызвать. - Флаг
--base-image(новый) указывает базовую среду образа для вашей функции, например,nodejs22,python312,go123,java21,dotnet8,ruby33илиphp83. Более подробную информацию о базовых образах и пакетах, включенных в каждый образ, см. в разделе «Базовые образы среды выполнения» . - (Необязательный) Флаг
--timeoutпозволяет функции установить более длительный тайм-аут для ответа на HTTP-запросы. В этом примере используется значение 600 секунд, чтобы продемонстрировать время ответа в 10 минут. - (необязательно) параметр
--no-allow-unauthenticated, чтобы предотвратить публичный вызов вашей функции.
Тест
Проверьте работу функции с помощью следующих команд:
# 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
В ответ вы должны увидеть сообщение HTTP with Node.js in Cloud Run functions! .
4. Функция публикации/подписки
Для второй функции давайте создадим функцию на Python, которая будет запускаться сообщением Pub/Sub, опубликованным в определенной теме.
Настройка токенов аутентификации Pub/Sub
Если вы включили учетную запись службы Pub/Sub 8 апреля 2021 года или ранее, предоставьте этой учетной записи службы роль iam.serviceAccountTokenCreator :
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
Создавать
Создайте тему Pub/Sub для использования в примере:
TOPIC=cloud-run-functions-pubsub-topic gcloud pubsub topics create $TOPIC
Создайте папку для приложения и перейдите в эту папку:
mkdir ../hello-pubsub cd ../hello-pubsub
Создайте файл main.py , который будет записывать в лог сообщение, содержащее идентификатор события 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'])
Создайте файл requirements.txt со следующим содержимым, чтобы указать зависимости:
functions-framework==3.*
Развертывать
Разверните функцию:
gcloud run deploy python-pubsub-function \
--source . \
--function hello_pubsub \
--base-image python313 \
--region $REGION \
--no-allow-unauthenticated
Получите номер проекта, который будет использоваться в качестве идентификатора учетной записи службы.
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)')
Создайте триггер
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
Тест
Проверьте работу функции, отправив сообщение в указанную тему:
gcloud pubsub topics publish $TOPIC --message="Hello World"
В журналах вы должны увидеть полученное событие CloudEvent:
gcloud run services logs read python-pubsub-function --region $REGION --limit=10
5. Функция облачного хранения
Для следующей функции давайте создадим функцию Node.js, которая будет реагировать на события из хранилища Cloud Storage.
Настраивать
Для использования функций облачного хранилища предоставьте учетной записи службы облачного хранилища роль IAM pubsub.publisher :
SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/pubsub.publisher
Создавать
Создайте папку для приложения и перейдите в эту папку:
mkdir ../hello-storage cd ../hello-storage
Создайте файл index.js , который просто реагирует на события 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);
});
Создайте файл package.json , чтобы указать зависимости:
{
"name": "nodejs-crf-cloud-storage",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Развертывать
Сначала создайте хранилище Cloud Storage (или используйте уже имеющееся у вас хранилище):
export BUCKET_NAME="gcf-storage-$PROJECT_ID" export BUCKET="gs://gcf-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Разверните функцию:
gcloud run deploy nodejs-crf-cloud-storage \ --source . \ --base-image nodejs22 \ --function helloStorage \ --region $REGION \ --no-allow-unauthenticated
После развертывания функции вы сможете увидеть ее в разделе Cloud Run в консоли Cloud Console.
Теперь создайте триггер 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
Тест
Проверьте работу функции, загрузив файл в хранилище:
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
В журналах вы должны увидеть полученное событие CloudEvent:
gcloud run services logs read nodejs-crf-cloud-storage --region $REGION --limit=10
6. Журналы аудита облачных сервисов
Для следующей функции давайте создадим функцию Node.js, которая получает событие Cloud Audit Log при создании экземпляра виртуальной машины Compute Engine. В ответ она добавляет метку к только что созданной виртуальной машине, указывая её создателя.
Определите местоположение вновь созданных виртуальных машин Compute Engine.
Compute Engine генерирует 2 журнала аудита при создании виртуальной машины.
Первый сигнал генерируется в начале создания виртуальной машины. Второй сигнал генерируется после создания виртуальной машины.
В журналах аудита поля операций различаются и содержат значения first: true и last: true . Второй журнал аудита содержит всю необходимую информацию для присвоения метки экземпляру, поэтому мы будем использовать флаг last: true для его обнаружения в функциях Cloud Run.
Настраивать
Для использования функций Cloud Audit Log необходимо включить журналы аудита для Eventarc. Также требуется использовать учетную запись службы с ролью eventarc.eventReceiver .
- Включите типы журналов аудита облака: «Чтение администратора» , «Чтение данных» и «Запись данных» для API Compute Engine.
- Предоставьте учетной записи службы Compute Engine по умолчанию роль IAM
eventarc.eventReceiver:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
Создайте функцию
В этом практическом занятии используется Node.js, но другие примеры можно найти по адресу https://github.com/GoogleCloudPlatform/eventarc-samples
Создайте файл package.json
{
"dependencies": {
"googleapis": "^84.0.0"
}
}
Создайте файл 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;
}
Развертывать
Разверните функцию:
gcloud run deploy gce-vm-labeler \ --source . \ --function labelVmCreation \ --region $REGION \ --no-allow-unauthenticated
Теперь создайте триггер. Обратите внимание, как функция фильтрует журналы аудита на предмет вставок в Compute Engine с помощью флага --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
Тест
Установите переменные окружения:
# if you're using europe-west1 as your region
ZONE=europe-west1-d
VM_NAME=codelab-crf-auditlog
Для создания виртуальной машины выполните следующую команду:
gcloud compute instances create $VM_NAME --zone=$ZONE --machine-type=e2-medium --image-family=debian-11 --image-project=debian-cloud
После завершения создания виртуальной машины в разделе «Основная информация» в консоли Cloud Console или с помощью следующей команды вы должны увидеть добавленную метку creator виртуальной машины:
gcloud compute instances describe $VM_NAME --zone=$ZONE
В выходных данных вы должны увидеть метку, как в следующем примере:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
Уборка
Обязательно удалите экземпляр виртуальной машины. В этой лабораторной работе он больше не будет использоваться.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. Разделение транспортных потоков
Функция Cloud Run поддерживает несколько версий ваших функций, распределяя трафик между различными версиями и откатывая функцию к предыдущей версии.
На этом этапе вы развернете две версии функции, а затем разделите трафик между ними поровну (50/50).
Создавать
Создайте папку для приложения и перейдите в эту папку:
mkdir ../traffic-splitting cd ../traffic-splitting
Создайте файл main.py с функцией Python, которая считывает переменную окружения, указывающую цвет, и возвращает сообщение Hello World в этом цвете фона:
import os
color = os.environ.get('COLOR')
def hello_world(request):
return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
Создайте файл requirements.txt со следующим содержимым, чтобы указать зависимости:
functions-framework==3.*
Развертывать
Разверните первую версию функции с оранжевым фоном:
COLOR=orange gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
На этом этапе, если вы проверите работу функции, просмотрев HTTP-триггер (URI, полученный в результате выполнения указанной выше команды развертывания) в браузере, вы должны увидеть Hello World на оранжевом фоне:

Разверните вторую версию с желтым фоном:
COLOR=yellow gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Поскольку это последняя версия, при тестировании функции вы должны увидеть Hello World на жёлтом фоне:

Разделите трафик пополам (50/50).
Чтобы разделить трафик между оранжевой и жёлтой версиями, необходимо найти идентификаторы версий служб Cloud Run. Вот команда для просмотра идентификаторов версий:
gcloud run revisions list --service hello-world-colors \ --region $REGION --format 'value(REVISION)'
Результат должен выглядеть примерно так:
hello-world-colors-00001-man hello-world-colors-00002-wok
Теперь разделите трафик между этими двумя версиями следующим образом (обновите X-XXX в соответствии с названиями ваших версий):
gcloud run services update-traffic hello-world-colors \ --region $REGION \ --to-revisions hello-world-colors-0000X-XXX=50,hello-world-colors-0000X-XXX=50
Тест
Проверьте функцию, перейдя по её общедоступному URL. В половине случаев вы должны увидеть оранжевую версию, а в другой половине — жёлтую:


Дополнительную информацию см. в разделах «Откаты», «Постепенное внедрение» и «Перенос трафика» .
8. Минимальное количество экземпляров
В функциях Cloud Run можно указать минимальное количество экземпляров функции, которые должны оставаться в состоянии готовности к обработке запросов. Это полезно для ограничения количества холодных запусков.
На этом этапе вы развернете функцию с медленной инициализацией. Вы понаблюдаете за проблемой холодного старта. Затем вы развернете функцию, установив минимальное значение экземпляра равным 1, чтобы избавиться от холодного старта.
Создавать
Создайте папку для приложения и перейдите в неё:
mkdir ../min-instances cd ../min-instances
Создайте файл main.go Этот Go-сервис имеет функцию init , которая приостанавливает выполнение на 10 секунд, имитируя длительную инициализацию. Он также содержит функцию HelloWorld , которая отвечает на 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!")
}
Развертывать
Разверните первую версию функции с минимальным значением экземпляра по умолчанию, равным нулю:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated
Проверьте работу функции с помощью этой команды:
# 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
При первом звонке вы заметите 10-секундную задержку (холодный старт), после чего увидите сообщение. На последующие звонки ответ должен поступать немедленно.
Установите минимальное количество экземпляров
Чтобы избежать холодного старта при первом запросе, повторно разверните функцию, установив флаг --min-instances в значение 1 следующим образом:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated \ --min-instances 1
Тест
Проверьте функцию еще раз:
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Теперь вы больше не должны видеть 10-секундную задержку при первом запросе. Проблема холодного старта при первом запуске (после длительного перерыва) исчезла благодаря минимальному количеству экземпляров!
Дополнительную информацию см. в разделе «Использование минимального количества экземпляров» .
9. Поздравляем!
Поздравляем с завершением практического занятия!
Что мы рассмотрели
- Обзор функций Cloud Run и способов использования автоматического обновления базового образа.
- Как написать функцию, которая отвечает на HTTP-запросы.
- Как написать функцию, которая обрабатывает сообщения в режиме Pub/Sub.
- Как написать функцию, которая реагирует на события в Cloud Storage.
- Как распределить трафик между двумя версиями.
- Как избавиться от проблем с холодным запуском при минимальном количестве экземпляров системы.