1. Введение
Чтобы начать писать функции Cloud Run, вы можете использовать следующие лаборатории кода:
- Начало работы с функциями HTTP Cloud Run
- Начало работы с функциями Cloud Run, управляемыми событиями
В противном случае в этой лаборатории кода вы узнаете, как создавать облачные функции (2-го поколения).
Обзор
Cloud Functions (2-го поколения) — это следующая версия Google Cloud Functions , предложения Google Cloud «Функции как услуга». Эта новая версия поставляется с расширенным набором функций и теперь работает на базе Cloud Run и Eventarc , предоставляя вам более расширенный контроль над производительностью и масштабируемостью, а также больший контроль над временем выполнения функций и триггерами из более чем 90+ источников событий.
В этой лаборатории кода вы узнаете, как создавать облачные функции, которые отвечают на HTTP-вызовы и активируются сообщениями Pub/Sub и журналами облачного аудита.
Что нового?
Эта новая версия Cloud Functions обеспечивает расширенные возможности FaaS на базе Cloud Run, Cloud Build, Artifact Registry и Eventarc.
Расширенная инфраструктура
- Более длительная обработка запросов. Запускайте облачные функции дольше, чем 5 минут по умолчанию, что упрощает выполнение более длительных рабочих нагрузок по запросам, таких как обработка больших потоков данных из Cloud Storage или BigQuery. Для функций HTTP это время составляет до 60 минут. Для функций, управляемых событиями, в настоящее время это время составляет до 10 минут.
- Инстансы большего размера. Воспользуйтесь преимуществом до 16 ГБ ОЗУ и 4 виртуальных ЦП в облачных функциях, позволяя выполнять более крупные, ресурсоемкие и параллельные рабочие нагрузки в памяти.
- Параллельность: обработка до 1000 одновременных запросов с помощью одного экземпляра функции, сводя к минимуму холодный запуск и уменьшая задержку при масштабировании.
- Минимальное количество экземпляров. Предусмотрите предварительно разогретые экземпляры, чтобы сократить холодный запуск и убедиться, что время загрузки вашего приложения не влияет на производительность приложения.
- Разделение трафика: поддержка нескольких версий ваших функций, разделение трафика между разными версиями и возврат функции к предыдущей версии.
Более широкий охват событий и поддержка CloudEvents
- Интеграция с Eventarc: Cloud Functions теперь включает встроенную поддержку Eventarc, которая объединяет более 90 источников событий с использованием журналов Cloud Audit (BigQuery, Cloud SQL, Cloud Storage...), и, конечно же, Cloud Functions по-прежнему поддерживает события из пользовательских источников путем публикации в Cloud Pub/Sub напрямую.
- Формат CloudEvent: все функции, управляемые событиями, соответствуют отраслевому стандарту CloudEvents ( cloudevents.io ), независимо от источника, что обеспечивает единообразие работы разработчиков. Полезные нагрузки отправляются через структурированный CloudEvent с полезной нагрузкой cloudevent.data и реализуют стандарт CloudEvent.
Что вы узнаете
- Обзор облачных функций (2-го поколения).
- Как написать функцию, отвечающую на HTTP-вызовы.
- Как написать функцию, которая отвечает на сообщения Pub/Sub.
- Как написать функцию, реагирующую на события Cloud Storage.
- Как написать функцию, реагирующую на журналы облачного аудита.
- Как разделить трафик между двумя ревизиями.
- Как избавиться от холодного запуска с минимальными затратами.
- Как настроить параллелизм.
2. Настройка и требования
Самостоятельная настройка среды
- Войдите в Google Cloud Console и создайте новый проект или повторно используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .
- Имя проекта — это отображаемое имя для участников этого проекта. Это строка символов, не используемая API Google. Вы можете обновить его в любое время.
- Идентификатор проекта должен быть уникальным для всех проектов Google Cloud и неизменяемым (нельзя изменить после его установки). Cloud Console автоматически генерирует уникальную строку; обычно тебя не волнует, что это такое. В большинстве лабораторий кода вам потребуется указать идентификатор проекта (обычно он обозначается как
PROJECT_ID
). Если вам не нравится сгенерированный идентификатор, вы можете создать другой случайный идентификатор. Кроме того, вы можете попробовать свой собственный и посмотреть, доступен ли он. Его нельзя изменить после этого шага, и он останется в силе на протяжении всего проекта. - К вашему сведению, есть третье значение — номер проекта , который используют некоторые API. Подробнее обо всех трех этих значениях читайте в документации .
- Затем вам необходимо включить выставление счетов в Cloud Console, чтобы использовать облачные ресурсы/API. Прохождение этой лаборатории кода не должно стоить много, если вообще стоит. Чтобы отключить ресурсы и не платить за выставление счетов за пределами этого руководства, вы можете удалить созданные вами ресурсы или удалить весь проект. Новые пользователи Google Cloud имеют право на участие в программе бесплатной пробной версии стоимостью 300 долларов США .
Запустить Cloud Shell
Хотя Google Cloud можно управлять удаленно с вашего ноутбука, в этой лаборатории вы будете использовать Google Cloud Shell , среду командной строки, работающую в облаке.
В Google Cloud Console щелкните значок Cloud Shell на верхней правой панели инструментов:
Подготовка и подключение к среде займет всего несколько минут. Когда все будет готово, вы должны увидеть что-то вроде этого:
Эта виртуальная машина оснащена всеми необходимыми инструментами разработки. Он предлагает постоянный домашний каталог объемом 5 ГБ и работает в Google Cloud, что значительно повышает производительность сети и аутентификацию. Всю работу в этой лаборатории кода можно выполнять в браузере. Вам не нужно ничего устанавливать.
Настройка gcloud
В Cloud Shell убедитесь, что идентификатор вашего проекта установлен и сохранен в переменной PROJECT_ID
, а для REGION
установлено значение us-west1
:
gcloud config set project [YOUR-PROJECT-ID] PROJECT_ID=$(gcloud config get-value project) REGION=us-west1
Включить API
Включите все необходимые службы:
gcloud services enable \ artifactregistry.googleapis.com \ cloudfunctions.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 $_
Создайте файл index.js
, который просто отвечает на HTTP-запросы:
const functions = require('@google-cloud/functions-framework'); functions.http('helloWorld', (req, res) => { res.status(200).send('HTTP with Node.js in GCF 2nd gen!'); });
Создайте файл package.json
, чтобы указать зависимости:
{ "name": "nodejs-functions-gen2-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Развертывать
Разверните функцию:
gcloud functions deploy nodejs-http-function \ --gen2 \ --runtime nodejs16 \ --entry-point helloWorld \ --source . \ --region $REGION \ --trigger-http \ --timeout 600s
Хотя на этом этапе это не является строго необходимым, обратите внимание на тайм-аут в 600 секунд. Это позволяет функции иметь более длительный таймаут для ответа на HTTP-запросы.
После развертывания функции вы сможете увидеть ее в разделе «Облачные функции» облачной консоли:
Тест
Проверьте функцию с помощью следующей команды:
gcloud functions call nodejs-http-function \ --gen2 --region $REGION
Вы должны увидеть сообщение HTTP with Node.js in GCF 2nd gen!
в качестве ответа.
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-functions-gen2-topic gcloud pubsub topics create $TOPIC
Создайте папку для приложения и перейдите в нее:
mkdir ~/hello-pubsub && cd $_
Создайте файл main.py
, который просто записывает сообщение, содержащее идентификатор CloudEvent:
import functions_framework @functions_framework.cloud_event def hello_pubsub(cloud_event): print('Pub/Sub with Python in GCF 2nd gen! Id: ' + cloud_event['id'])
Создайте файл requirements.txt
со следующим содержимым, чтобы указать зависимости:
functions-framework==3.*
Развертывать
Разверните функцию:
gcloud functions deploy python-pubsub-function \ --gen2 \ --runtime python39 \ --entry-point hello_pubsub \ --source . \ --region $REGION \ --trigger-topic $TOPIC
После развертывания функции вы сможете увидеть ее в разделе «Облачные функции» облачной консоли:
Тест
Протестируйте функцию, отправив сообщение в тему:
gcloud pubsub topics publish $TOPIC --message="Hello World"
Вы должны увидеть полученное CloudEvent в журналах:
gcloud functions logs read python-pubsub-function \ --region $REGION --gen2 --format "value(log)"
5. Функция облачного хранения
Для следующей функции давайте создадим функцию Node.js, которая реагирует на события из сегмента Cloud Storage.
Настраивать
Чтобы использовать функции 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 $_
Создайте файл index.js
, который просто реагирует на события Cloud Storage:
const functions = require('@google-cloud/functions-framework'); functions.cloudEvent('helloStorage', (cloudevent) => { console.log('Cloud Storage event with Node.js in GCF 2nd gen!'); console.log(cloudevent); });
Создайте файл package.json
, чтобы указать зависимости:
{ "name": "nodejs-functions-gen2-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Развертывать
Сначала создайте корзину Cloud Storage (или используйте уже имеющуюся корзину):
export BUCKET="gs://gcf-gen2-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Разверните функцию:
gcloud functions deploy nodejs-storage-function \ --gen2 \ --runtime nodejs16 \ --entry-point helloStorage \ --source . \ --region $REGION \ --trigger-bucket $BUCKET \ --trigger-location $REGION
После развертывания функции вы сможете увидеть ее в разделе «Облачные функции» облачной консоли.
Тест
Протестируйте функцию, загрузив файл в корзину:
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
Вы должны увидеть полученное CloudEvent в журналах:
gcloud functions logs read nodejs-storage-function \ --region $REGION --gen2 --limit=100 --format "value(log)"
6. Функция журналов облачного аудита
Для следующей функции давайте создадим функцию Node.js, которая получает событие журнала аудита облака при создании экземпляра виртуальной машины Compute Engine. В ответ он добавляет метку к вновь созданной виртуальной машине, указывая создателя виртуальной машины.
Определите вновь созданные виртуальные машины Compute Engine.
Compute Engine создает 2 журнала аудита при создании виртуальной машины.
Первый генерируется в начале создания ВМ и выглядит следующим образом:
Второй генерируется после создания ВМ и выглядит следующим образом:
Обратите внимание на поле операции со значениями first: true
и last: true
. Второй журнал аудита содержит всю информацию, необходимую для маркировки экземпляра, поэтому мы будем использовать флаг last: true
чтобы обнаружить его в облачных функциях.
Настраивать
Чтобы использовать функции журнала аудита облака, необходимо включить журналы аудита для Eventarc. Вам также необходимо использовать учетную запись службы с ролью eventarc.eventReceiver
.
- Включите журналы аудита облака: административное чтение , чтение данных и запись данных для Compute Engine API:
- Предоставьте учетной записи службы 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
Получить код
Клонируйте репозиторий, содержащий приложение:
git clone https://github.com/GoogleCloudPlatform/eventarc-samples.git
Перейдите в каталог приложения:
cd eventarc-samples/gce-vm-labeler/gcf/nodejs
Файл index.js
содержит код приложения, который получает журнал аудита, завернутый в CloudEvent. Затем он извлекает сведения об экземпляре виртуальной машины Compute Engine и присваивает экземпляру виртуальной машины метку. Вы можете изучить index.js
более подробно самостоятельно.
Развертывать
Вы можете развернуть эту функцию с помощью gcloud
как и раньше. Обратите внимание, как функция фильтрует журналы аудита для вставок Compute Engine с флагом --trigger-event-filters
:
gcloud functions deploy gce-vm-labeler \ --gen2 \ --runtime nodejs16 \ --entry-point labelVmCreation \ --source . \ --region $REGION \ --trigger-event-filters="type=google.cloud.audit.log.v1.written,serviceName=compute.googleapis.com,methodName=beta.compute.instances.insert" \ --trigger-location us-central1
Вы также можете развернуть эту функцию и добавить триггер Eventarc из Google Cloud Console.
Сначала перейдите в раздел «Облачные функции» и создайте функцию со средой 2-го поколения:
Нажмите кнопку Add Eventarc Trigger
:
Откроется боковая панель справа, где вы можете выбрать различных поставщиков событий и события для триггера Eventarc.
Выберите правильного поставщика событий и событие, а затем нажмите Save Trigger
:
Наконец, на следующей странице вы можете обновить файлы index.js
и package.json
с помощью файлов index.js
и package.json
на GitHub и нажать кнопку Deploy
:
Тест
Чтобы протестировать функцию журнала аудита, вам необходимо создать виртуальную машину Compute Engine в облачной консоли (вы также можете создавать виртуальные машины с помощью gcloud
но, похоже, он не создает журналы аудита).
Перейдите в раздел Compute Engine > Экземпляры виртуальных машин Cloud Console и создайте новую виртуальную машину. После завершения создания виртуальной машины вы должны увидеть добавленную метку creator
на виртуальной машине в облачной консоли в разделе «Основная информация» или с помощью следующей команды:
gcloud compute instances describe YOUR_VM_NAME
В выводе вы должны увидеть метку, как показано в следующем примере:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
7. Разделение трафика
Облачные функции (2-го поколения) поддерживают несколько версий ваших функций, разделяя трафик между разными версиями и откатывая вашу функцию до предыдущей версии. Это возможно, поскольку функции второго поколения представляют собой службы Cloud Run.
На этом этапе вы развернете две версии функции, а затем разделите трафик между ними 50-50.
Создавать
Создайте папку для приложения и перейдите в нее:
mkdir ~/traffic-splitting && cd $_
Создайте файл 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>'
Развертывать
Разверните первую версию функции с оранжевым фоном:
COLOR=orange gcloud functions deploy hello-world-colored \ --gen2 \ --runtime python39 \ --entry-point hello_world \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
На этом этапе, если вы протестируете функцию, просмотрев триггер HTTP (выходные данные URI приведенной выше команды развертывания) в своем браузере, вы должны увидеть Hello World
на оранжевом фоне:
Разверните вторую ревизию с желтым фоном:
COLOR=yellow gcloud functions deploy hello-world-colored \ --gen2 \ --runtime python39 \ --entry-point hello_world \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Поскольку это последняя версия, если вы протестируете функцию, вы должны увидеть Hello World
на желтом фоне:
Разделите трафик 50-50
Чтобы разделить трафик между оранжевой и желтой версиями, вам необходимо найти идентификаторы версий базовых сервисов Cloud Run. Это команда для просмотра идентификаторов ревизий:
gcloud run revisions list --service hello-world-colored \ --region $REGION --format 'value(REVISION)'
Вывод должен быть похож на следующий:
hello-world-colored-00001-man hello-world-colored-00002-wok
Теперь разделите трафик между этими двумя ревизиями следующим образом (обновите X-XXX
в соответствии с именами ваших ревизий):
gcloud run services update-traffic hello-world-colored \ --region $REGION \ --to-revisions hello-world-colored-0000X-XXX=50,hello-world-colored-0000X-XXX=50
Тест
Проверьте функцию, посетив ее общедоступный URL-адрес. В половине случаев вы должны видеть оранжевую версию, а в другой половине — желтую версию:
Дополнительные сведения см. в разделе откаты, постепенное развертывание и миграция трафика .
8. Минимум экземпляров
В облачных функциях (2-го поколения) можно указать минимальное количество экземпляров функций, которые будут поддерживаться в рабочем состоянии и быть готовыми к обслуживанию запросов. Это полезно для ограничения количества холодных запусков.
На этом этапе вы развернете функцию с медленной инициализацией. Вы заметите проблему холодного запуска. Затем вы развернете функцию с минимальным значением экземпляра, равным 1, чтобы избавиться от холодного запуска.
Создавать
Создайте папку для приложения и перейдите к ней:
mkdir ~/min-instances && cd $_
Создайте файл 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 GCF 2nd gen!") }
Развертывать
Разверните первую версию функции с минимальным значением экземпляра по умолчанию, равным нулю:
gcloud functions deploy slow-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated
Проверьте функцию с помощью этой команды:
gcloud functions call slow-function \ --gen2 --region $REGION
Вы увидите 10-секундную задержку (холодный старт) при первом вызове, а затем увидите сообщение. Последующие вызовы должны немедленно возвращаться.
Установить минимальное количество экземпляров
Чтобы избавиться от холодного запуска при первом запросе, переразверните функцию с флагом --min-instances
установленным в 1, следующим образом:
gcloud functions deploy slow-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --min-instances 1
Тест
Проверьте функцию еще раз:
gcloud functions call slow-function \ --gen2 --region $REGION
Вы больше не должны видеть 10-секундную задержку в первом запросе. Проблема холодного запуска при первом вызове (после долгого отсутствия) устранена благодаря минимальному количеству экземпляров!
Дополнительные сведения см. в разделе Использование минимального количества экземпляров .
9. Параллелизм
В облачных функциях (2-го поколения) экземпляр функции по умолчанию обрабатывает 1 одновременный запрос, но вы можете указать количество одновременных запросов, которые может обрабатываться экземпляром одновременно. Это также может быть полезно для предотвращения холодного запуска, поскольку не нужно создавать новый экземпляр функции для каждого параллельного запроса.
На этом этапе вы будете использовать функцию с медленной инициализацией из предыдущего шага. Вы отправите ему 10 запросов и снова столкнетесь с проблемой холодного запуска, поскольку для обработки запросов необходимо создать новые экземпляры функций.
Чтобы устранить проблему холодного запуска, вы развернете еще одну функцию со значением параллелизма, равным 100. Вы увидите, что 10 запросов теперь не вызывают проблемы холодного запуска, и один экземпляр функции может обрабатывать все запросы.
Тестирование без параллелизма
Получите URL-адрес функции:
SLOW_URL=$(gcloud functions describe slow-function --region $REGION --gen2 --format="value(serviceConfig.uri)")
Используйте инструмент сравнительного анализа с открытым исходным кодом под названием hey
чтобы отправить 10 одновременных запросов к медленной функции. hey
уже установлен в Cloud Shell:
hey -n 10 -c 10 $SLOW_URL
В выводе команды hey
вы должны увидеть, что некоторые запросы выполняются долго:
Summary: Total: 10.9053 secs Slowest: 10.9048 secs Fastest: 0.4439 secs Average: 9.7930 secs Requests/sec: 0.9170 Total data: 310 bytes Size/request: 31 bytes Response time histogram: 0.444 [1] |■■■■ 1.490 [0] | 2.536 [0] | 3.582 [0] | 4.628 [0] | 5.674 [0] | 6.720 [0] | 7.767 [0] | 8.813 [0] | 9.859 [0] | 10.905 [9] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
Это связано с тем, что для обработки запросов создается больше экземпляров функций. Если вы проверите количество активных экземпляров функции, вы также увидите, что в какой-то момент было создано более одного экземпляра, и это вызывает проблему холодного запуска:
Развертывать
Разверните новую функцию, идентичную предыдущей. После развертывания вы увеличите его параллелизм:
gcloud functions deploy slow-concurrent-function \ --gen2 \ --runtime go116 \ --entry-point HelloWorld \ --source . \ --region $REGION \ --trigger-http \ --allow-unauthenticated \ --min-instances 1
Установить параллелизм
Установите для функции параллелизм базовой службы Cloud Run равным 100 (максимум 1000). Это гарантирует, что один экземпляр функции может обработать не менее 100 запросов:
gcloud run services update slow-concurrent-function \ --concurrency 100 \ --cpu 1 \ --region $REGION
Тестирование с параллелизмом
Получите URL-адрес функции:
SLOW_CONCURRENT_URL=$(gcloud functions describe slow-concurrent-function --region $REGION --gen2 --format="value(serviceConfig.uri)")
Затем используйте hey
, чтобы отправить 10 одновременных запросов:
hey -n 10 -c 10 $SLOW_CONCURRENT_URL
В выводе команды hey
вы должны увидеть, что все запросы обрабатываются быстро:
Summary: Total: 0.2164 secs Slowest: 0.2163 secs Fastest: 0.0921 secs Average: 0.2033 secs Requests/sec: 46.2028 Total data: 310 bytes Size/request: 31 bytes Response time histogram: 0.092 [1] |■■■■ 0.105 [0] | 0.117 [0] | 0.129 [0] | 0.142 [0] | 0.154 [0] | 0.167 [0] | 0.179 [0] | 0.191 [0] | 0.204 [0] | 0.216 [9] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
Один экземпляр функции смог обработать все запросы, и проблема холодного запуска исчезла благодаря увеличению параллелизма!
См. параллелизм для получения дополнительной информации.
10. Поздравляем!
Поздравляем с завершением работы над кодом!
Что мы рассмотрели
- Обзор облачных функций (2-го поколения).
- Как написать функцию, отвечающую на HTTP-вызовы.
- Как написать функцию, которая отвечает на сообщения Pub/Sub.
- Как написать функцию, реагирующую на события Cloud Storage.
- Как написать функцию, реагирующую на журналы облачного аудита.
- Как разделить трафик между двумя ревизиями.
- Как избавиться от холодного запуска с минимальными затратами.
- Как настроить параллелизм.