۱. مقدمه
نمای کلی
Cloud Run functions ، یک سرویس تابع محور گوگل کلود است که توسط Cloud Run و Eventarc ارائه میشود و به شما کنترل پیشرفتهتری بر عملکرد و مقیاسپذیری و همچنین کنترل بیشتری بر زمان اجرای توابع و تریگرها از بیش از ۹۰+ منبع رویداد میدهد.
این آزمایشگاه کد، شما را در ایجاد توابع Cloud Run که به فراخوانیهای HTTP پاسخ میدهند و توسط پیامهای Pub/Sub و گزارشهای حسابرسی ابری فعال میشوند، راهنمایی میکند.
این آزمایشگاه کد همچنین با مشخص کردن یک تصویر پایه با استفاده از پرچم --base-image ، از بهروزرسانیهای خودکار تصویر پایه برای استقرار توابع استفاده میکند. بهروزرسانیهای خودکار تصویر پایه برای Cloud Run به گوگل این امکان را میدهد که بهطور خودکار وصلههای امنیتی را برای سیستم عامل و اجزای زمان اجرای زبان تصویر پایه ایجاد کند. برای بهروزرسانی تصویر پایه، نیازی به بازسازی یا استقرار مجدد سرویس خود ندارید. برای اطلاعات بیشتر، بهروزرسانیهای خودکار تصویر پایه را بررسی کنید.
اگر ترجیح میدهید از بهروزرسانیهای خودکار تصویر پایه استفاده نکنید ، میتوانید پرچم --base-image را از مثالهای نشان داده شده در این آزمایشگاه کد حذف کنید.
آنچه یاد خواهید گرفت
- مروری بر عملکردهای 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)
فعال کردن APIها
فعال کردن تمام سرویسهای لازم:
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(new) برای تنظیم نقطه ورودی سرویس جدید به عنوان امضای تابعی که میخواهید فراخوانی شود، استفاده میشود. - پرچم
--base-image(جدید) محیط تصویر پایه را برای تابع شما مشخص میکند، مانندnodejs22،python312،go123،java21،dotnet8،ruby33یاphp83. برای جزئیات بیشتر در مورد تصاویر پایه و بستههای موجود در هر تصویر، به Runtimes base images مراجعه کنید. - (اختیاری) پرچم
--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، نقش 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 ایجاد کنید که به سادگی به رویدادهای 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"
}
}
استقرار
ابتدا، یک سطل ذخیرهسازی ابری ایجاد کنید (یا از یک سطل موجود که از قبل دارید استفاده کنید):
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
۶. گزارشهای حسابرسی ابری
برای تابع بعدی، بیایید یک تابع Node.js ایجاد کنیم که هنگام ایجاد یک نمونه ماشین مجازی Compute Engine، یک رویداد Cloud Audit Log دریافت کند. در پاسخ، یک برچسب به ماشین مجازی تازه ایجاد شده اضافه میکند که سازنده ماشین مجازی را مشخص میکند.
تعیین ماشینهای مجازی تازه ایجاد شده توسط موتور محاسباتی
موتور محاسبه (Compute Engine) هنگام ایجاد یک ماشین مجازی، 2 گزارش حسابرسی (Audit Log) منتشر میکند.
اولی در ابتدای ایجاد ماشین مجازی منتشر میشود. دومی پس از ایجاد ماشین مجازی منتشر میشود.
در لاگهای حسابرسی، فیلدهای عملیات متفاوت هستند و شامل مقادیر first: true و last: true میباشند. دومین لاگ حسابرسی شامل تمام اطلاعاتی است که برای برچسبگذاری یک نمونه نیاز داریم، بنابراین از پرچم last: true برای تشخیص آن در توابع Cloud Run استفاده خواهیم کرد.
تنظیم کنید
برای استفاده از توابع گزارش حسابرسی ابری، باید گزارشهای حسابرسی را برای Eventarc فعال کنید. همچنین باید از یک حساب کاربری سرویس با نقش eventarc.eventReceiver استفاده کنید.
- انواع گزارشهای «خواندن مدیر» ، «خواندن داده» و «نوشتن داده» مربوط به گزارشهای حسابرسی ابری را برای رابط برنامهنویسی کاربردی موتور محاسبات (Compute Engine API) فعال کنید .
- به حساب سرویس پیشفرض Compute Engine، نقش
eventarc.eventReceiverIAM را اعطا کنید:
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
حالا تریگر را ایجاد کنید. توجه کنید که چگونه تابع با استفاده از فلگ --trigger-event-filters لاگهای حسابرسی (Audit Logs) را برای درجهای موتور محاسبات (Compute Engine) فیلتر میکند.
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
تست
متغیرهای env را تنظیم کنید:
# 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 اضافه شده را روی ماشین مجازی در کنسول ابری در بخش اطلاعات پایه یا با استفاده از دستور زیر مشاهده کنید:
gcloud compute instances describe $VM_NAME --zone=$ZONE
شما باید برچسب را در خروجی مانند مثال زیر ببینید:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
تمیز کردن
مطمئن شوید که نمونه ماشین مجازی را حذف کردهاید. در این آزمایش دیگر از آن استفاده نخواهد شد.
gcloud compute instances delete $VM_NAME --zone=$ZONE
۷. تقسیم ترافیک
توابع Cloud Run از چندین نسخه از توابع شما پشتیبانی میکنند، ترافیک را بین نسخههای مختلف تقسیم میکنند و تابع شما را به نسخه قبلی برمیگردانند.
در این مرحله، شما دو نسخه از یک تابع را مستقر میکنید و سپس ترافیک را بین آنها به صورت ۵۰-۵۰ تقسیم میکنید.
ایجاد کردن
یک پوشه برای برنامه ایجاد کنید و به پوشه بروید:
mkdir ../traffic-splitting cd ../traffic-splitting
یک فایل main.py با یک تابع پایتون ایجاد کنید که یک متغیر محیطی رنگ را میخواند و با رنگ پسزمینهی آن، عبارت 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
تست
با مراجعه به URL عمومی تابع، آن را آزمایش کنید. در نیمی از مواقع، باید نسخه نارنجی و در نیمی دیگر، نسخه زرد را ببینید:


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