1. 소개
개요
Cloud Run Functions는 Google Cloud에서 제공하는 Functions as a Service 제품으로, Cloud Run 및 Eventarc로 구동되므로 성능 및 확장성에 대한 고급 제어, 함수 런타임 및 90개 이상의 이벤트 소스 트리거에 대한 추가 제어를 사용할 수 있습니다.
이 Codelab에서는 HTTP 호출에 응답하고 Pub/Sub 메시지와 Cloud 감사 로그에 의해 트리거되는 Cloud Run 함수를 만드는 방법을 안내합니다.
이 Codelab에서는 --base-image 플래그를 사용하여 기본 이미지를 지정하여 함수 배포에 자동 기본 이미지 업데이트도 사용합니다. Cloud Run에서 기본 이미지에 대한 자동 업데이트를 사용 설정하면 Google이 기본 이미지의 운영체제 및 언어 런타임 구성요소에 보안 패치를 자동으로 적용할 수 있습니다. 기본 이미지가 업데이트되도록 서비스를 다시 빌드하거나 다시 배포할 필요가 없습니다. 자세한 내용은 기본 이미지 자동 업데이트를 참고하세요.
자동 기본 이미지 업데이트를 사용하지 않으려면 이 Codelab에 표시된 예에서 --base-image 플래그를 삭제하면 됩니다.
학습할 내용
- Cloud Run Functions 개요 및 자동 기본 이미지 업데이트 사용 방법
- HTTP 호출에 응답하는 함수를 작성하는 방법
- Pub/Sub 메시지에 응답하는 함수를 작성하는 방법
- Cloud Storage 이벤트에 응답하는 함수를 작성하는 방법
- 두 버전 간에 트래픽을 분할하는 방법
- 최소 인스턴스로 콜드 스타트를 제거하는 방법
2. 설정 및 요구사항
루트 폴더 만들기
모든 예제의 루트 폴더를 만듭니다.
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
3. HTTP 함수
첫 번째 함수에서는 HTTP 요청에 응답하는 인증된 Node.js 함수를 만들어 보겠습니다. 또한 10분 제한 시간을 사용하여 함수가 HTTP 요청에 응답하는 시간을 늘리는 방법을 보여줍니다.
만들기
앱의 폴더를 만들고 해당 폴더로 이동합니다.
mkdir hello-http cd hello-http
HTTP 요청에 응답하는 index.js 파일을 만듭니다.
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
이 명령어는 빌드팩을 사용하여 함수 소스 코드를 프로덕션에 즉시 사용 가능한 컨테이너 이미지로 변환합니다.
다음 사항을 참고하세요.
--source플래그는 Cloud Run에 함수를 실행 가능한 컨테이너 기반 서비스로 빌드하도록 지시하는 데 사용됩니다.--function플래그 (신규)는 호출하려는 함수 서명이 되도록 새 서비스의 진입점을 설정하는 데 사용됩니다.--base-image플래그 (신규)는nodejs22,python312,go123,java21,dotnet8,ruby33,php83과 같은 함수의 기본 이미지 환경을 지정합니다. 기본 이미지 및 각 이미지에 포함된 패키지에 대한 자세한 내용은 런타임 기본 이미지를 참고하세요.- (선택사항)
--timeout플래그를 사용하면 함수가 HTTP 요청에 응답할 수 있는 시간이 늘어납니다. 이 예시에서는 10분 응답 시간을 보여주기 위해 600초가 사용됩니다. - (선택사항) 함수가 공개적으로 호출되지 않도록 하는
--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. Pub/Sub 함수
두 번째 함수의 경우 특정 주제에 게시된 Pub/Sub 메시지에 의해 트리거되는 Python 함수를 만들어 보겠습니다.
Pub/Sub 인증 토큰 설정
2021년 4월 8일 이전에 Pub/Sub 서비스 계정을 사용 설정한 경우 Pub/Sub 서비스 계정에 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
CloudEvent ID가 포함된 메시지를 로깅하는 main.py 파일을 만듭니다.
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
서비스 계정 ID에 사용할 프로젝트 번호를 가져옵니다.
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. Cloud Storage 함수
다음 함수에서는 Cloud Storage 버킷의 이벤트에 응답하는 Node.js 함수를 만들어 보겠습니다.
설정
Cloud Storage 함수를 사용하려면 Cloud Storage 서비스 계정에 pubsub.publisher IAM 역할을 부여하세요.
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
Cloud 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"
}
}
배포
먼저 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 Console의 Cloud Run 섹션에 함수가 표시됩니다.
이제 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. Cloud 감사 로그
다음 함수에서는 Compute Engine VM 인스턴스가 생성될 때 Cloud 감사 로그 이벤트를 수신하는 Node.js 함수를 만들어 보겠습니다. 이렇게 하면 새로 생성된 VM에 VM 생성자를 지정하는 라벨이 추가됩니다.
새로 생성된 Compute Engine VM 확인
VM이 생성되면 Compute Engine은 감사 로그 2개를 내보냅니다.
첫 번째 감사 로그는 VM 생성을 시작할 때 내보내집니다. 두 번째 감사 로그는 VM이 생성된 후에 내보내집니다.
감사 로그에서 작업 필드는 first: true 및 last: true 값을 포함하여 서로 다릅니다. 두 번째 감사 로그에는 인스턴스에 라벨을 지정하는 데 필요한 모든 정보가 포함되어 있으므로 last: true 플래그를 사용하여 Cloud Run Functions에서 감지합니다.
설정
Cloud 감사 로그 함수를 사용하려면 Eventarc 감사 로그를 사용 설정해야 합니다. eventarc.eventReceiver 역할이 있는 서비스 계정도 사용해야 합니다.
- Compute Engine API에 대해 Cloud 감사 로그 관리자 읽기, 데이터 읽기, 데이터 쓰기 로그 유형을 사용 설정합니다.
- 기본 Compute Engine 서비스 계정에
eventarc.eventReceiverIAM 역할을 부여합니다.
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
이제 트리거를 만듭니다. 함수가 --trigger-event-filters 플래그를 사용하여 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
테스트
환경 변수를 설정합니다.
# 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 생성이 완료되면 Cloud 콘솔의 VM에 추가된 creator 라벨이 기본 정보 섹션에 표시되거나 다음 명령어를 사용하여 표시됩니다.
gcloud compute instances describe $VM_NAME --zone=$ZONE
다음 예시와 비슷한 출력에 라벨이 표시됩니다.
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
삭제
VM 인스턴스를 삭제해야 합니다. 이 실습에서는 다시 사용되지 않습니다.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. 트래픽 분할
Cloud Run Functions는 다양한 함수 버전과 여러 버전 간 트래픽 분할 및 이전 버전으로의 함수 롤백을 지원합니다.
이 단계에서는 함수의 두 버전을 배포한 다음 두 버전 간에 트래픽을 50대 50으로 분할합니다.
만들기
앱의 폴더를 만들고 해당 폴더로 이동합니다.
mkdir ../traffic-splitting cd ../traffic-splitting
색상 환경 변수를 읽고 해당 배경색으로 Hello World를 응답하는 Python 함수를 사용하여 main.py 파일을 만듭니다.
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 서비스의 버전 ID를 찾아야 합니다. 버전 ID를 확인하는 명령어는 다음과 같습니다.
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 Functions에서는 요청 처리를 위해 웜 상태 및 준비 상태로 유지할 최소 함수 인스턴스 수를 지정할 수 있습니다. 콜드 스타트 수를 제한하는 데 유용한 기능입니다.
이 단계에서는 초기화가 느린 함수를 배포합니다. 콜드 스타트 문제가 나타납니다. 그런 다음 최소 인스턴스 값을 1로 설정하여 콜드 스타트를 없애고 함수를 배포합니다.
만들기
앱의 폴더를 만들고 해당 폴더로 이동합니다.
mkdir ../min-instances cd ../min-instances
main.go 파일을 만듭니다. 이 Go 서비스에는 긴 초기화를 시뮬레이션하기 위해 10초 동안 절전 모드로 전환되는 init 함수가 있습니다. HTTP 호출에 응답하는 HelloWorld 함수도 있습니다.
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!")
}
배포
최소 인스턴스의 기본값이 0인 첫 번째 함수 버전을 배포합니다.
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. 축하합니다.
축하합니다. Codelab을 완료했습니다.
학습한 내용
- Cloud Run Functions 개요 및 자동 기본 이미지 업데이트 사용 방법
- HTTP 호출에 응답하는 함수를 작성하는 방법
- Pub/Sub 메시지에 응답하는 함수를 작성하는 방법
- Cloud Storage 이벤트에 응답하는 함수를 작성하는 방법
- 두 버전 간에 트래픽을 분할하는 방법
- 최소 인스턴스로 콜드 스타트를 제거하는 방법