1. 소개
개요
이 튜토리얼에서는 Cloud Run 작업자 풀 (컨슈머)을 배포하여 Pub/Sub 메시지를 처리하고 Cloud Run 외부 측정항목 자동 확장 (CREMA)을 사용하여 대기열 깊이에 따라 컨슈머 인스턴스를 자동으로 확장하는 방법을 보여줍니다.
학습할 내용
이 Codelab에서는 다음 작업을 해 봅니다.
- Pub/Sub 주제 및 구독을 만들고 해당 주제에 메시지를 푸시합니다.
- Pub/Sub에서 메시지를 소비하는 Cloud Run 작업자 풀 (소비자)을 배포합니다.
- GitHub에 CREMA 프로젝트를 Cloud Run 서비스로 배포하여 Pub/Sub 구독의 메시지 수를 기반으로 작업자 풀을 자동으로 확장합니다.
- 로컬에서 Python 스크립트를 실행하여 부하를 생성하여 자동 확장 구성을 테스트합니다.
2. 환경 변수 구성
이 Codelab에서는 많은 환경 변수를 사용하므로 다음을 실행하는 것이 좋습니다.
set -u
아직 설정되지 않은 환경 변수를 사용하려고 하면 경고가 표시됩니다. 이 설정을 되돌리려면 set +u을 실행하세요.
먼저 다음 변수를 프로젝트 ID로 변경합니다.
export PROJECT_ID=<YOUR_PROJECT_ID>
그런 다음 이 Codelab의 프로젝트로 설정합니다.
gcloud config set project $PROJECT_ID
그런 다음 이 Codelab에서 사용하는 환경 변수를 설정합니다.
export REGION=us-central1
export TOPIC_ID=crema-pubsub-topic
export SUBSCRIPTION_ID=crema-pubsub-sub
export CREMA_SA_NAME=crema-service-account
export CONSUMER_SA_NAME=consumer-service-account
export CONSUMER_WORKER_POOL_NAME=worker-pool-consumer
export CREMA_SERVICE_NAME=my-crema-service
이 Codelab의 디렉터리를 만듭니다.
mkdir crema-pubsub-codelab
cd crema-pubsub-codelab
API 사용 설정
gcloud services enable \
artifactregistry.googleapis.com \
cloudbuild.googleapis.com \
run.googleapis.com \
parametermanager.googleapis.com
마지막으로 gcloud가 최신 버전을 사용하고 있는지 확인합니다.
gcloud components update
3. Pub/Sub 설정
작업자 풀에서 처리할 주제와 풀 구독을 만듭니다. Bash
주제를 만듭니다.
gcloud pubsub topics create $TOPIC_ID
구독을 만듭니다.
gcloud pubsub subscriptions create $SUBSCRIPTION_ID --topic=$TOPIC_ID
4. IAM 및 서비스 계정
각 Cloud Run 리소스에 서비스 계정을 만드는 것이 좋습니다. 이 Codelab에서는 다음을 만듭니다.
- 컨슈머 SA: Pub/Sub 메시지를 처리하는 작업자 풀의 ID입니다.
- CREMA SA: CREMA 오토 스케일러 서비스의 ID입니다.
서비스 계정 만들기
작업자 풀 컨슈머 SA를 만듭니다.
gcloud iam service-accounts create $CONSUMER_SA_NAME \
--display-name="PubSub Consumer Service Account"
작업자 풀 CREMA 서비스 SA를 만듭니다.
gcloud iam service-accounts create $CREMA_SA_NAME \
--display-name="CREMA Autoscaler Service Account"
컨슈머 SA에 권한 부여
작업자 풀 소비자 SA에 구독에서 메시지를 가져올 권한을 부여합니다.
gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
--member="serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/pubsub.subscriber"
CREMA SA에 권한 부여
CREMA는 매개변수를 읽고, 작업자 풀을 확장하고, Pub/Sub 측정항목을 모니터링할 권한이 필요합니다.
- 액세스 Parameter Manager (구성 리더):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/parametermanager.parameterViewer"
- 작업자 풀 확장 (Cloud Run 개발자):
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/run.developer"
- Pub/Sub 모니터링:
모니터링 뷰어 역할을 부여합니다.
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/monitoring.viewer"
CREMA 서비스 SA의 구독에 정책을 추가하여 확인
gcloud pubsub subscriptions add-iam-policy-binding $SUBSCRIPTION_ID \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/pubsub.viewer"
CREMA SA에는 인스턴스 수를 변경하는 데 필요한 서비스 계정 사용자도 필요합니다.
gcloud iam service-accounts add-iam-policy-binding \
$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
--member="serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
5. SA 권한 확인
Codelab을 진행하기 전에 CREMA 서비스 SA에 올바른 프로젝트 수준 역할이 있는지 확인하세요.
gcloud projects get-iam-policy $PROJECT_ID \
--flatten="bindings[].members" \
--format="table(bindings.role)" \
--filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"
다음과 같은 결과가 표시됩니다.
roles/monitoring.viewer
roles/parametermanager.parameterViewer
roles/run.developer
Pub/Sub 구독에 CREMA 서비스 SA가 볼 수 있는 정책이 있는지 확인합니다.
gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--format="table(bindings.role)"
결과
roles/pubsub.viewer
CREMA SA에 서비스 계정 사용자 역할이 있는지 확인합니다.
gcloud iam service-accounts get-iam-policy \
$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com"
다음과 같은 결과가 표시됩니다.
bindings:
members: serviceAccount:crema-service-account@<PROJECT_ID>.iam.gserviceaccount.com
role: roles/iam.serviceAccountUser
작업자 풀 소비자 SA에 Pub/Sub 구독자 역할이 있습니다.
gcloud pubsub subscriptions get-iam-policy $SUBSCRIPTION_ID \
--flatten="bindings[].members" \
--filter="bindings.members:serviceAccount:$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--format="table(bindings.role)"
결과
ROLE
roles/pubsub.subscriber
6. 소비자 작업자 풀 빌드 및 배포
소비자 코드의 디렉터리를 만들고 입력합니다.
mkdir consumer
cd consumer
consumer.py파일 만들기
import os
import time
from google.cloud import pubsub_v1
from concurrent.futures import TimeoutError
# Configuration
PROJECT_ID = os.environ.get('PROJECT_ID')
SUBSCRIPTION_ID = os.environ.get('SUBSCRIPTION_ID')
subscription_path = f"projects/{PROJECT_ID}/subscriptions/{SUBSCRIPTION_ID}"
print(f"Worker Pool instance starting. Watching {subscription_path}...")
subscriber = pubsub_v1.SubscriberClient()
def callback(message):
try:
data = message.data.decode("utf-8")
print(f"Processing job: {data}")
time.sleep(5) # Simulate work
print(f"Done {data}")
message.ack()
except Exception as e:
print(f"Error processing message: {e}")
message.nack()
streaming_pull_future = subscriber.subscribe(subscription_path, callback=callback)
print(f"Listening for messages on {subscription_path}...")
# Wrap subscriber in a 'with' block to automatically call close() when done.
with subscriber:
try:
# When `timeout` is not set, result() will block indefinitely,
# unless an exception is encountered first.
streaming_pull_future.result()
except TimeoutError:
streaming_pull_future.cancel() # Trigger the shutdown.
streaming_pull_future.result() # Block until the shutdown is complete.
except Exception as e:
print(f"Streaming pull failed: {e}")
Dockerfile를 만드는 방법
FROM python:3.12-slim
RUN pip install google-cloud-pubsub
COPY consumer.py .
CMD ["python", "-u", "consumer.py"]
- 소비자 작업자 풀 배포
이 Codelab에서는 인스턴스가 0개인 작업자 풀을 먼저 배포하여 구독에서 Pub/Sub 메시지를 감지할 때 CREMA가 작업자 풀을 확장하는 것을 확인할 수 있도록 하는 것이 좋습니다.
gcloud beta run worker-pools deploy $CONSUMER_WORKER_POOL_NAME \
--source . \
--region $REGION \
--service-account="$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" \
--instances=0 \
--set-env-vars PROJECT_ID=$PROJECT_ID,SUBSCRIPTION_ID=$SUBSCRIPTION_ID
7. CREMA 구성
- 프로젝트의 루트 디렉터리로 다시 이동합니다.
cd ..
- 구성 파일 만들기
crema-config.yaml이라는 파일을 만듭니다.
apiVersion: crema/v1
kind: CremaConfig
spec:
pollingInterval: 30
triggerAuthentications:
- metadata:
name: adc-trigger-auth
spec:
podIdentity:
provider: gcp
scaledObjects:
- spec:
scaleTargetRef:
name: projects/PROJECT_ID_PLACEHOLDER/locations/REGION_PLACEHOLDER/workerpools/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER
triggers:
- type: gcp-pubsub
metadata:
subscriptionName: "SUBSCRIPTION_ID_PLACEHOLDER"
# Target number of undelivered messages per worker instance
value: "10"
mode: "SubscriptionSize"
authenticationRef:
name: adc-trigger-auth
- 변수 대체
sed -i "s/PROJECT_ID_PLACEHOLDER/$PROJECT_ID/g" crema-config.yaml
sed -i "s/REGION_PLACEHOLDER/$REGION/g" crema-config.yaml
sed -i "s/CONSUMER_WORKER_POOL_NAME_PLACEHOLDER/$CONSUMER_WORKER_POOL_NAME/g" crema-config.yaml
sed -i "s/SUBSCRIPTION_ID_PLACEHOLDER/$SUBSCRIPTION_ID/g" crema-config.yaml
crema-config.yaml이 올바른지 확인
if grep -q "_PLACEHOLDER" crema-config.yaml; then
echo "❌ ERROR: Validations failed. '_PLACEHOLDER' was found in crema-config.yaml."
echo "Please check your environment variables and run the 'sed' commands again."
else
echo "✅ Config check passed: No placeholders found."
fi
- Parameter Manager에 업로드
Parameter Manager의 추가 환경 변수 설정
export PARAMETER_ID=crema-config
export PARAMETER_REGION=global
export PARAMETER_VERSION=1
Parameter 리소스 만들기
gcloud parametermanager parameters create $PARAMETER_ID \
--location=$PARAMETER_REGION \
--parameter-format=YAML
파라미터 버전 1 만들기
gcloud parametermanager parameters versions create $PARAMETER_VERSION \
--parameter=crema-config \
--project=$PROJECT_ID \
--location=$PARAMETER_REGION \
--payload-data-from-file=crema-config.yaml
매개변수가 성공적으로 추가되었는지 확인합니다.
gcloud parametermanager parameters versions list \
--parameter=$PARAMETER_ID \
--location=$PARAMETER_REGION
다음과 같이 표시됩니다.
projects/<YOUR_PROJECT_ID>/locations/global/parameters/crema-config/versions/1
8. CREMA 서비스 배포
이 섹션에서는 CREMA 자동 확장 처리 서비스를 배포합니다. 공개적으로 제공되는 이미지를 사용합니다.
- CREMA에 필요한 환경 변수 설정
CREMA_CONFIG_PARAM_VERSION=projects/$PROJECT_ID/locations/$PARAMETER_REGION/parameters/$PARAMETER_ID/versions/$PARAMETER_VERSION
- 버전 이름 경로 확인
echo $CREMA_CONFIG_PARAM_VERSION
다음과 같이 표시됩니다.
projects/<YOUR_PROJECT>/locations/global/parameters/crema-config/versions/1
- CREMA 이미지의 환경 변수 설정
IMAGE=us-central1-docker.pkg.dev/cloud-run-oss-images/crema-v1/autoscaler:1.0
- CREMA 서비스 배포
기본 이미지는 필수 항목입니다.
gcloud beta run deploy $CREMA_SERVICE_NAME \
--image=$IMAGE \
--region=${REGION} \
--service-account="${CREMA_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
--no-allow-unauthenticated \
--no-cpu-throttling \
--labels=created-by=crema \
--base-image=us-central1-docker.pkg.dev/serverless-runtimes/google-24/runtimes/java25 \
--set-env-vars="CREMA_CONFIG=${CREMA_CONFIG_PARAM_VERSION},OUTPUT_SCALER_METRICS=True,ENABLE_CLOUD_LOGGING=True"
9. 부하 테스트
- Pub/Sub 주제에 메시지를 게시하는 스크립트 만들기
touch load-pubsub.sh
- 다음 코드를
load-pubsub.sh파일에 추가합니다.
#!/bin/bash
TOPIC_ID=${TOPIC_ID}
PROJECT_ID=${PROJECT_ID}
NUM_MESSAGES=100
echo "Publishing $NUM_MESSAGES messages to topic $TOPIC_ID..."
for i in $(seq 1 $NUM_MESSAGES); do
gcloud pubsub topics publish $TOPIC_ID --message="job-$i" --project=$PROJECT_ID &
if (( $i % 10 == 0 )); then
wait
echo "Published $i messages..."
fi
done
wait
echo "Done. All messages published."
- 부하 테스트 실행
chmod +x load-pubsub.sh
./load-pubsub.sh
- 확장 모니터링 3~4분 정도 기다립니다. CREMA 로그를 확인하여 새 authenticationRef 구성에 따라 인스턴스를 추천하는지 확인합니다.
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=$CREMA_SERVICE_NAME AND textPayload:SCALER" \
--limit=20 \
--format="value(textPayload)" \
--freshness=5m
- 모니터링 처리 뷰에서 소비자 로그를 확인하여 스핀업되는지 확인합니다.
gcloud beta run worker-pools logs tail $CONSUMER_WORKER_POOL_NAME --region=$REGION
다음과 같은 로그가 표시됩니다.
Done job-100
10. 문제 해결
먼저 문제가 CREMA 서비스 구성에 있는지 아니면 PubSub 소비자 구성에 있는지 확인해야 합니다.
PubSub 소비자 자동 확장 프로그램을 0 대신 1로 설정합니다. pubsub 메시지 처리를 즉시 시작하면 CREMA에 문제가 있는 것입니다. pubsub 메시지를 처리하지 않으면 pubsub 소비자에 문제가 있는 것입니다.
11. 축하합니다.
축하합니다. Codelab을 완료했습니다.
Cloud Run 문서를 검토하는 것이 좋습니다.
학습한 내용
- Pub/Sub 주제 및 구독을 만들고 해당 주제에 메시지를 푸시하는 방법
- Pub/Sub에서 메시지를 소비하는 Cloud Run 작업자 풀 (소비자)을 배포하는 방법
- GitHub의 CREMA 프로젝트를 Cloud Run 서비스로 배포하여 Pub/Sub 구독의 메시지 수를 기반으로 작업자 풀을 자동으로 확장하는 방법
- 로컬에서 Python 스크립트를 실행하여 부하를 생성하여 자동 확장 구성을 테스트하는 방법
12. 삭제
이 튜토리얼에서 사용한 리소스 비용이 Google Cloud 계정에 청구되지 않도록 하려면 이 Codelab에서 만든 리소스를 삭제하거나 전체 프로젝트를 삭제하면 됩니다.
이 Codelab에서 사용된 리소스 삭제
- Cloud Run CREMA 서비스 삭제
gcloud run services delete $CREMA_SERVICE_NAME --region=$REGION --quiet
- Cloud Run 작업자 풀 소비자 삭제
gcloud beta run worker-pools delete $CONSUMER_WORKER_POOL_NAME --region=$REGION --quiet
- Pub/Sub 구독 및 주제 삭제
gcloud pubsub subscriptions delete $SUBSCRIPTION_ID --quiet
gcloud pubsub topics delete $TOPIC_ID --quiet
- Parameter Manager 구성 삭제
파라미터 내의 버전 삭제
gcloud parametermanager parameters versions delete $PARAMETER_VERSION \
--parameter=$PARAMETER_ID \
--location=$PARAMETER_REGION \
--quiet
이제 빈 매개변수를 삭제합니다.
gcloud parametermanager parameters delete $PARAMETER_ID \
--location=$PARAMETER_REGION \
--quiet
- 서비스 계정 삭제
gcloud iam service-accounts delete "$CREMA_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet
gcloud iam service-accounts delete "$CONSUMER_SA_NAME@$PROJECT_ID.iam.gserviceaccount.com" --quiet
또는 전체 프로젝트를 삭제합니다.
전체 프로젝트를 삭제하려면 리소스 관리로 이동하여 2단계에서 만든 프로젝트를 선택하고 삭제를 선택합니다. 프로젝트를 삭제하면 Cloud SDK에서 프로젝트를 변경해야 합니다. gcloud projects list를 실행하여 사용 가능한 모든 프로젝트의 목록을 볼 수 있습니다.