۱. مقدمه
نمای کلی
توابع Cloud Run پیشنهاد «توابع بهعنوان سرویس» Google Cloud است که توسط Cloud Run و Eventarc پشتیبانی میشود و به شما کنترل پیشرفتهتری بر عملکرد و مقیاسپذیری و کنترل بیشتری بر زمان اجرای توابع و راهاندازها از بیشاز ۹۰ منبع رویداد میدهد.
این codelab شما را در ایجاد کردن توابع Cloud Run که به تماسهای HTTP پاسخ میدهند و توسط پیامهای Pub/Sub و Cloud Audit Logs راهاندازی میشوند راهنمایی میکند.
این codelab همچنین از بهروزرسانیهای خودکار تصویر پایه برای استقرار توابع با مشخص کردن یک تصویر پایه بااستفاده از پرچم --base-image استفاده میکند. بهروزرسانیهای خودکار تصویر پایه برای Cloud Run به Google امکان میدهد وصلههای امنیتی را بهطور خودکار در سیستمعامل و مؤلفههای زمان اجرای زبان تصویر پایه اعمال کند. برای بهروزرسانی تصویر پایه، لازم نیست سرویس خود را بازسازی یا مجدداً مستقر کنید. برای اطلاعات بیشتر، بهروزرسانیهای خودکار تصویر پایه را بررسی کنید
اگر ترجیح میدهید از بهروزرسانیهای خودکار تصویر پایه استفاده نکنید، میتوانید پرچم --base-image را از نمونههای نشاندادهشده در این codelab بردارید.
آنچه خواهید آموخت
- نمای کلی توابع Cloud Run و نحوه استفاده از بهروزرسانیهای خودکار تصویر پایه.
- نحوه نوشتن تابعی که به تماسهای HTTP پاسخ میدهد.
- نحوه نوشتن تابعی که به پیامهای Pub/Sub پاسخ میدهد.
- نحوه نوشتن تابعی که به رویدادهای «فضای ذخیرهسازی ابری» پاسخ میدهد.
- نحوه تقسیم ترافیک بین دو نسخه.
- چگونه با حداقل نمونهها از شروع سرد خلاص شویم.
۲. راهاندازی و الزامات
ایجاد پوشه ریشه
پوشه ریشهای برای همه نمونهها ایجاد کنید.
mkdir crf-codelab cd crf-codelab
راهاندازی متغیرهای محیطی
متغیرهای محیطی را که در سراسر این codelab استفاده خواهد شد تنظیم کنید/
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
فعال کردن میاناهای برنامهسازی کاربردی
فعال کردن همه سرویسهای لازم:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
۳. تابع HTTP
برای تابع اول، بیایید یک تابع Node.js اصالتسنجیشده ایجاد کنیم که به درخواستهای HTTP پاسخ میدهد. بیایید از یک مهلت ۱۰ دقیقهای نیز استفاده کنیم تا نشان دهیم چگونه یک تابع میتواند زمان بیشتری برای پاسخ به درخواستهای 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 داشته باشد. در این مثال، از ۶۰۰ ثانیه برای نشان دادن زمان پاسخ ۱۰ دقیقهای استفاده شده است. - (اختیاری)
--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! را بهعنوان پاسخ ببینید.
۴. تابع Pub/Sub
برای تابع دوم، بیایید یک تابع پایتون ایجاد کنیم که با پیام Pub/Sub منتشرشده در یک موضوع خاص راهاندازی میشود.
راهاندازی کردن کدهای اصالتسنجی Pub/Sub
اگر حساب سرویس Pub/Sub را در ۸ آوریل ۲۰۲۱ یا قبلاز آن فعال کردهاید، نقش 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
۵. تابع فضای ذخیرهسازی ابری
برای تابع بعدی، بیایید تابع Node.js ایجاد کنیم که به رویدادهای باکت «فضای ذخیرهسازی ابری» پاسخ میدهد.
تنظیم کردن
برای استفاده از توابع Cloud Storage، نقش pubsub.publisher IAM را به حساب سرویس 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 ایجاد کنید که بهسادگی به رویدادهای 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 bucket ایجاد کنید (یا از bucket موجودی که ازقبل دارید استفاده کنید):
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
۶. Cloud Audit Logs
برای تابع بعدی، بیایید تابع Node.js ایجاد کنیم که وقتی نمونه ماشین مجازی Compute Engine ایجاد میشود، رویداد گزارش ممیزی Cloud را دریافت میکند. در پاسخ، برچسبی به VM تازه ایجادشده اضافه میکند که سازنده VM را مشخص میکند.
تعیین کردن ماشینهای مجازی Compute Engine جدیداً ایجادشده
Compute Engine هنگام ایجاد VM، دو «گزارش ممیزی» صادر میکند.
اولین مورد در شروع ایجاد ماشین مجازی منتشر میشود. دومی پساز ایجاد VM منتشر میشود.
در گزارشهای ممیزی، فیلدهای عملیات متفاوت هستند و حاوی مقادیر first: true و last: true هستند. دومین «گزارش ممیزی» حاوی تمام اطلاعاتی است که برای برچسبگذاری نمونه نیاز داریم، بنابراین از پرچم last: true برای شناسایی آن در توابع Cloud Run استفاده خواهیم کرد.
تنظیم کردن
برای استفاده از توابع Cloud Audit Log، باید Audit Logs را برای Eventarc فعال کنید. همچنین باید از حساب سرویسی با نقش eventarc.eventReceiver استفاده کنید.
- فعال کردن Cloud Audit Logs Admin Read، Data Read، و Data Write انواع گزارش برای Compute Engine API.
- نقش
eventarc.eventReceiverIAM را به حساب سرویس Compute Engine پیشفرض اعطا کنید:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
ایجاد تابع
این codelab از 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
فرمان زیر را برای ایجاد VM اجرا کنید:
gcloud compute instances create $VM_NAME --zone=$ZONE --machine-type=e2-medium --image-family=debian-11 --image-project=debian-cloud
پساز تکمیل ایجاد VM، باید برچسب creator اضافهشده را در VM در «کنسول ابری» در بخش اطلاعات پایه یا بااستفاده از فرمان زیر ببینید:
gcloud compute instances describe $VM_NAME --zone=$ZONE
باید برچسب را در خروجی مانند مثال زیر ببینید:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
مرتبسازی
حتماً نمونه VM را حذف کنید. دیگر در این آزمایش از آن استفاده نخواهد شد.
gcloud compute instances delete $VM_NAME --zone=$ZONE
۷. توزیع کردن ترافیک
توابع Cloud Run از چندین بازبینی توابع شما، تقسیم ترافیک بین بازبینیهای مختلف، و برگرداندن تابع شما به نسخه قبلی پشتیبانی میکند.
در این مرحله، ۲ بازبینی از یک تابع را مستقر خواهید کرد و سپس ترافیک را بهصورت ۵۰-۵۰ بین آنها توزیع خواهید کرد.
ایجاد
پوشهای برای برنامه ایجاد کنید و به آن پوشه بروید:
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 را با پسزمینه زرد ببینید:

ترافیک را بهصورت ۵۰-۵۰ تقسیم کنید
برای توزیع ترافیک بین بازبینیهای نارنجی و زرد، باید شناسههای بازبینی سرویسهای 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
آزمایش
با مراجعه به نشانی وب عمومی تابع، آن را آزمایش کنید. نیمی از مواقع باید نسخه نارنجی و نیمی دیگر نسخه زرد را ببینید:

برای اطلاعات بیشتر، بازگرداندن، عرضه تدریجی، و انتقال ترافیک را ببینید.
۸. حداقل نمونهها
در توابع Cloud Run، میتوانید حداقل تعداد نمونههای تابع را مشخص کنید تا گرم و آماده برای ارائه درخواستها نگه داشته شوند. این کار برای محدود کردن تعداد شروعهای سرد مفید است.
در این مرحله، تابعی با مقداردهی اولیه آهسته را مستقر خواهید کرد. مشکل شروع سرد را مشاهده خواهید کرد. سپس، تابع را با حداقل مقدار نمونه تنظیمشده روی ۱ مستقر خواهید کرد تا از راهاندازی سرد خلاص شوید.
ایجاد
پوشهای برای برنامه ایجاد کنید و به آن پیمایش کنید:
mkdir ../min-instances cd ../min-instances
فایل main.go ایجاد کنید. این سرویس Go دارای تابع init است که برای شبیهسازی مقداردهی اولیه طولانی، بهمدت ۱۰ ثانیه غیرفعال میشود. همچنین دارای تابع 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
در اولین تماس، ۱۰ ثانیه تأخیر (شروع سرد) را مشاهده خواهید کرد و سپس پیام را خواهید دید. تماسهای بعدی باید فوراً برگردانده شوند.
تنظیم حداقل نمونهها
برای خلاص شدن از شروع سرد در اولین درخواست، تابع را با پرچم --min-instances تنظیمشده روی ۱ بهصورت زیر مجدداً مستقر کنید:
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
دیگر نباید تأخیر ۱۰ ثانیهای را در درخواست اول ببینید. بهلطف حداقل نمونهها، مشکل شروع سرد برای اولین فراخوانی (پساز مدت طولانی بدون فراخوانی) برطرف شده است!
برای اطلاعات بیشتر، به استفاده از حداقل نمونهها مراجعه کنید.
۹. تبریک!
بابت تکمیل codelab به شما تبریک میگوییم!
آنچه پوشش دادیم
- نمای کلی توابع Cloud Run و نحوه استفاده از بهروزرسانیهای خودکار تصویر پایه.
- نحوه نوشتن تابعی که به تماسهای HTTP پاسخ میدهد.
- نحوه نوشتن تابعی که به پیامهای Pub/Sub پاسخ میدهد.
- نحوه نوشتن تابعی که به رویدادهای «فضای ذخیرهسازی ابری» پاسخ میدهد.
- نحوه تقسیم ترافیک بین دو نسخه.
- چگونه با حداقل نمونهها از شروع سرد خلاص شویم.