1. Введение
Обзор
Функции Cloud Run — это предложение «функции как услуга» от Google Cloud, работающее на базе Cloud Run и Eventarc , которое обеспечивает более расширенный контроль над производительностью и масштабируемостью, а также больший контроль над средой выполнения функций и триггерами из более чем 90 источников событий.
В этой лабораторной работе вы научитесь создавать функции Cloud Run, которые реагируют на HTTP-вызовы и активируются сообщениями Pub/Sub и журналами аудита Cloud.
В этой лабораторной работе также используются автоматические обновления базовых образов для развёртывания функций. Для этого используется флаг --base-image
указывающий базовый образ. Автоматическое обновление базовых образов для Cloud Run позволяет Google автоматически устанавливать исправления безопасности для операционной системы и компонентов среды выполнения языка базового образа. Вам не придётся пересобирать или повторно развертывать сервис для обновления базового образа. Подробнее см. в разделе «Автоматические обновления базовых образов».
Если вы предпочитаете не использовать автоматическое обновление базового образа, вы можете удалить флаг --base-image
из примеров, показанных в этой кодовой лаборатории.
Чему вы научитесь
- Обзор функций Cloud Run и как использовать автоматическое обновление базового образа.
- Как написать функцию, которая реагирует на HTTP-вызовы.
- Как написать функцию, которая реагирует на сообщения Pub/Sub.
- Как написать функцию, реагирующую на события облачного хранилища.
- Как разделить трафик между двумя ревизиями.
- Как избавиться от холодного запуска двигателя с минимальными затратами времени.
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
Эта команда использует buildpack-пакеты для преобразования исходного кода вашей функции в готовый к использованию образ контейнера.
Обратите внимание на следующее:
- Флаг
--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
учетной записи службы 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
Создавать
Создайте тему 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
учетной записи службы 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
Создавать
Создайте папку для приложения и перейдите в нее:
mkdir ../hello-storage cd ../hello-storage
Создайте файл index.js
, который просто реагирует на события облачного хранилища:
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" } }
Развертывать
Сначала создайте контейнер облачного хранилища (или используйте уже имеющийся у вас контейнер):
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.
Настраивать
Для использования функций журнала аудита облака необходимо включить журналы аудита для Eventarc. Также необходимо использовать учетную запись службы с ролью eventarc.eventReceiver
.
- Включите типы журналов облачного аудита: Admin Read , Data Read и Data Write для 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
После завершения создания виртуальной машины вы должны увидеть добавленную метку creator
на виртуальной машине в Cloud Console в разделе «Основная информация» или с помощью следующей команды:
gcloud compute instances describe $VM_NAME --zone=$ZONE
В выводе вы должны увидеть метку, как в следующем примере:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
Уборка
Обязательно удалите экземпляр виртуальной машины. Он больше не будет использоваться в этой лаборатории.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. Разделение трафика
Функции Cloud Run поддерживают множественные версии ваших функций, разделяя трафик между различными версиями и откатывая вашу функцию к предыдущей версии.
На этом этапе вы развернете 2 версии функции, а затем разделите трафик между ними в соотношении 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.
- Как написать функцию, реагирующую на события облачного хранилища.
- Как разделить трафик между двумя ревизиями.
- Как избавиться от холодного запуска двигателя с минимальными затратами времени.