1. 개요
'2일차'에 오신 것을 환영합니다. 앱을 빌드하고 '게시'를 누르는 것은 마법과 같지만 실제 트래픽은 실제 오류를 가져옵니다. YAML과 씨름하거나 로그를 뒤지는 대신 전문 에이전트의 스웜을 빌드하여 운영 배관을 관리할 수 있습니다. 이 Codelab에서는 Google Cloud의 통합 스택 (Eventarc, Cloud Run, Firestore, Cloud Build, BigQuery)을 사용하면 에이전트가 기본적으로 보안 비밀을 안전하게 가져오고, 로그를 스트리밍하고, 문제를 해결하는 것이 얼마나 쉬운지 보여줍니다.

이 Codelab에서는 Gemini 기반 공룡 어드벤처 게임인 DinoQuest를 처음부터 빌드하고 완전한 에이전트형 CI/CD 파이프라인에 연결합니다. 이 과정을 마치면 다음을 수행할 수 있습니다.
- Cloud Run에서 실행되는 DinoQuest 웹 앱 (서비스 이름:
dinoquest) - Cloud Run 로그를 BigQuery로 스트리밍하고 대화형 게임 통계 대시보드를 생성하는 로그 분석 파이프라인
- 수정 에이전트 (
remediation-agent) - Cloud Run 오류를 모니터링하고 자동으로 수정하는 ADK 수정 에이전트. Eventarc에 의해 트리거되는 자체 Cloud Run 서비스로 배포됩니다. - PR 차이를 읽고, 테스트 범위를 지능적으로 지정하고, Cloud Build를 통해 Docker 이미지를 빌드하고, 커밋 상태를 GitHub에 다시 게시하는 CI 에이전트 (
ci-agent) - 배포 위험을 평가하고, 트래픽을 분할하고, 측정항목을 모니터링하고, 자동으로 승격 또는 롤백하는 CD 에이전트
학습할 내용
- Cloud Run에 Vite + FastAPI 풀 스택 앱을 단일 컨테이너로 배포하는 방법
- React 앱용 Firebase 인증 및 Firestore를 구성하는 방법
- Eventarc를 통해 Pub/Sub 이벤트에 반응하는 ADK 에이전트를 빌드하고 배포하는 방법
- Cloud Run 로그를 BigQuery로 라우팅하고 게임 분석을 쿼리하는 방법
- CI 및 카나리아 배포를 위한 에이전트 기술 작성 방법
필요한 항목
- 결제가 사용 설정된 Google Cloud 프로젝트
- Firebase 프로젝트 (동일한 GCP 프로젝트일 수 있음)
- GitHub 계정 및 DinoQuest 저장소 포크
- Gemini (Google의 에이전트 러너)를 사용한 Antigravity 액세스
gcloudCLI 설치 및 인증됨(아래 설치 안내 참고)node≥ 18 및npmpython3≥ 3.11git및gh(GitHub CLI)
gcloud CLI 설치
macOS
brew install --cask google-cloud-sdk
또는 cloud.google.com/sdk/docs/install에서 설치 프로그램을 다운로드합니다.
Windows
winget install Google.CloudSDK
또는 cloud.google.com/sdk/docs/install에서 Windows 설치 프로그램 (.exe)을 다운로드하여 실행합니다.
설치 후 초기화하고 인증합니다.
gcloud init
gcloud auth login
gcloud auth application-default login
2. Firebase 설정하기
모든 에이전트에는 추론할 데이터가 필요합니다. DinoQuest는 Firestore와 Firebase Auth를 사용하여 에이전트가 나중에 자연어를 사용하여 검색, 탐색, 업데이트할 수 있는 프로덕션 준비 데이터 레이어를 제공합니다.
이 앱은 AI Studio를 통해 생성되었으므로 Firebase와 긴밀하게 통합되어 있습니다. Firebase를 사용하면 사전 보안 아키텍처와 기본 제공 관리 데이터 액세스 등 여러 이점이 있어 게임 상태를 처음부터 보호할 수 있습니다.
A. Firebase 프로젝트 만들기
- console.firebase.google.com으로 이동합니다.
- 프로젝트 추가를 클릭하고(새 프로젝트 만들기 옵션에 숨겨져 있음) → 기존 GCP 프로젝트를 선택하거나 새 프로젝트를 만듭니다.
- 메시지가 표시되면 Google 애널리틱스를 사용 중지하고 프로젝트 만들기를 클릭합니다. 기본 설정을 사용해도 됩니다.
B. Google 인증 사용 설정
- Firebase Console에서 보안 → 인증 (시작하기) → 로그인 방법으로 이동합니다.
- Google을 클릭하고 사용 설정을 전환한 다음 지원 이메일을 저장하고 저장을 클릭합니다.
C. localhost를 승인된 도메인으로 추가
- 인증에서 설정 탭을 클릭합니다.
- 승인된 도메인에서
localhost이 나열되어 있는지 확인합니다 (기본적으로 나열되어 있어야 함).
D. Firestore 데이터베이스 만들기
- 데이터베이스 및 스토리지 → Firestore 데이터베이스 → 데이터베이스 만들기로 이동합니다.
- Standard 버전 → 다음을 선택합니다.
- 리전
us-central1선택 (또는 Cloud Run 리전과 일치) - 프로덕션 모드에서 시작 → 만들기를 선택합니다.
생성되면 데이터베이스 ID를 기록해 둡니다. 이름을 지정하지 않은 경우 (default)와 같이 표시됩니다.
E. Firebase 보안 규칙 설정
Firestore 데이터베이스 → 규칙에서 기본 규칙을 다음으로 바꿉니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// ===============================================================
// Helper Functions
// ===============================================================
function isAuthenticated() {
return request.auth != null;
}
function isOwner(userId) {
return isAuthenticated() && request.auth.uid == userId;
}
function isValidUser(data) {
return data.keys().hasAll(['uid', 'email']) &&
data.uid is string && data.uid.size() > 0 &&
(data.email == null || (data.email is string && data.email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")));
}
function isValidDinosaur(data) {
return data.keys().hasAll(['userId', 'name', 'type']) &&
data.userId == request.auth.uid &&
data.name is string && data.name.size() > 0 && data.name.size() < 50 &&
data.type in ['Speedy', 'Tank', 'Balanced', 'Agile'];
}
function isValidGame(data) {
return data.keys().hasAll(['userId', 'score']) &&
data.userId == request.auth.uid &&
data.score is number && data.score >= 0;
}
match /users/{userId} {
allow read: if isOwner(userId);
allow create: if isOwner(userId) && isValidUser(request.resource.data);
allow update: if isOwner(userId) && isValidUser(request.resource.data);
match /dinosaurs/{dinoId} {
allow read: if isOwner(userId);
allow create: if isOwner(userId) && isValidDinosaur(request.resource.data);
allow update: if isOwner(userId) && isValidDinosaur(request.resource.data);
}
match /games/{gameId} {
allow read: if isOwner(userId);
allow create: if isOwner(userId) && isValidGame(request.resource.data);
}
match /seenAnnouncements/{announcementId} {
allow read, create: if isOwner(userId);
}
}
match /announcements/{announcementId} {
allow read: if isAuthenticated();
}
// Default deny
match /{document=**} {
allow read, write: if false;
}
match /scores/{scoreId} {
allow read: if true;
allow create: if isAuthenticated();
allow update: if false;
}
}
}
게시를 클릭합니다.
F. 웹 앱 추가 및 구성 가져오기
- 프로젝트 설정 (톱니바퀴 아이콘) → 일반 탭으로 이동합니다.
- 내 앱으로 스크롤 → 앱 추가 클릭 → 웹 아이콘 (
) 선택 - 이름을
dinoquest로 지정하고 앱 등록을 클릭합니다. - 표시된
firebaseConfig객체를 복사합니다. 잠시 후에 필요합니다.
3. 게임 실행
상담사 역할: 환경 에이전트가 작동하도록 설정하려면 에이전트가 관리할 세계가 필요합니다. 이 단계에서는 DinoQuest의 'Day One' 버전을 배포합니다. 이렇게 하면 스웜이 나중에 검색하고 관리할 라이브 서비스, 로그, 상태가 생성됩니다.

아래 두 가지 옵션 중 하나를 선택하세요. 이후 단계에서 동일하게 사용하는 GEMINI_API_KEY를 생성합니다. 다른 변경사항은 필요하지 않습니다.
A. Gemini API 키 설정
옵션 A: Vertex AI Gemini API 키 (GCP 프로젝트가 있는 경우 권장)
Vertex AI를 사용하면 별도의 AI Studio 계정 없이 프로젝트의 기본 서비스 계정을 사용하여 GCP 프로젝트에 직접 연결되고 청구되는 Gemini API 키를 만들 수 있습니다.
- GCP 프로젝트 ID를 내보냅니다.
export PROJECT_ID=<YOUR_PROJECT_ID> - 필요한 API를 사용 설정하고 Compute Engine 기본 서비스 계정에 필요한 권한을 부여합니다.
gcloud auth application-default set-quota-project $PROJECT_ID gcloud config set project $PROJECT_ID # Enable Vertex AI, Compute Engine, and Generative Language APIs gcloud services enable aiplatform.googleapis.com \ compute.googleapis.com \ generativelanguage.googleapis.com # Grant Vertex AI User role to the default compute service account PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)") gcloud projects add-iam-policy-binding $PROJECT_ID \ --member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \ --role="roles/aiplatform.user" \ --condition=None - Cloud 콘솔에서 Vertex AI API 키 페이지를 엽니다.
- 사용자 인증 정보 만들기를 클릭하고 API 키를 선택합니다.
- 생성 대화상자에서 다음을 수행합니다.
- 키 이름을
Dino_Key로 지정합니다. - 서비스 계정을 통해 API 호출 인증 체크박스를 선택합니다.
- 서비스 계정에서 기본 컴퓨팅 서비스 계정 (
PROJECT_NUMBER-compute@developer.gserviceaccount.com)을 선택합니다. - API 제한사항 선택으로 돌아가 GEMINI API를 선택합니다.
- 만들기를 클릭합니다.
- 키 이름을
- 생성된 키를 복사합니다.
옵션 B - AI Studio (로컬 개발에 가장 빠름)
- aistudio.google.com을 엽니다.
- 왼쪽 사이드바에서 Get API key(API 키 가져오기)를 클릭합니다.
- API 키 만들기를 클릭하고 GCP 프로젝트를 선택한 후 키를 복사합니다.
두 키 중 하나는 다음 단계에서 GEMINI_API_KEY로 설정됩니다. 백엔드에서는 두 키를 동일하게 취급합니다.
저장소 복제
과정 저장소는 https://github.com/gca-americas/dinoquest에 있습니다. 먼저 고유 GitHub 계정으로 포크하세요. 대신 상담사가 저장소를 처리하도록 하겠습니다.
포크한 후 포크한 DinoQuest 저장소의 main 브랜치를 클론하고 프로젝트 디렉터리를 입력합니다.
git clone https://github.com/YOUR_GITHUB_USERNAME/dinoquest.git
cd dinoquest
B. 환경 변수 설정
이 Codelab에서 여는 모든 새 bash 터미널에서 이러한 필수 환경 변수를 설정해야 합니다. 자리표시자 값을 실제 프로젝트 세부정보로 바꿉니다.
먼저 GitHub 저장소 URL을 내보냅니다.
export GITHUB_REPO_URL=https://github.com/YOUR_GITHUB_USERNAME/dinoquest
그런 다음 나머지 환경 변수를 내보냅니다.
export PROJECT_ID=your-project-id
export GOOGLE_CLOUD_PROJECT=$PROJECT_ID
export CLOUD_RUN_REGION=us-central1
export GOOGLE_GENAI_USE_VERTEXAI=True
export HARNESS_EVENTS_TOPIC=projects/$PROJECT_ID/topics/harness-events
export CLOUD_BUILD_REPO=<YOUR_GITHUB_USERNAME>-dinoquest
구조가 올바른지 확인합니다.
dinoquest/
├── backend/ # FastAPI backend (serves frontend + Gemini API calls)
├── frontend/ # React/Vite frontend
├── skills/ # Agentic CI/CD skill files
├── Dockerfile # Multi-stage build (React → Python)
├── start.sh # Local dev launcher
└── README.md
B. 백엔드 환경 파일 만들기
먼저 Gemini API 키를 내보냅니다.
export GEMINI_API_KEY=YOUR_GEMINI_API_KEY_FROM_STEP_2
그런 다음 .env 파일을 만듭니다.
cat > backend/.env <<EOF
GEMINI_API_KEY=$GEMINI_API_KEY
GOOGLE_GENAI_USE_VERTEXAI=False
GOOGLE_CLOUD_PROJECT=$PROJECT_ID
EOF
C. Firebase 앱 체크 / 서비스 계정 사용 설정 (Cloud Run용)
Cloud Run에서 실행할 때 백엔드는 애플리케이션 기본 사용자 인증 정보를 사용하여 Firebase와 통신하므로 서비스 계정 키 파일이 필요하지 않습니다. backend/main.py의 firebase_admin.initialize_app() 호출은 이를 자동으로 선택합니다.
로컬 개발의 경우 한 번 인증합니다.
gcloud auth application-default login
D. Firebase 앱 구성 파일 만들기
frontend/ 디렉터리에서 이전 단계의 구성으로 firebase-applet-config.json를 만듭니다.
{
"apiKey": "YOUR_API_KEY",
"authDomain": "YOUR_PROJECT_ID.firebaseapp.com",
"projectId": "YOUR_PROJECT_ID",
"storageBucket": "YOUR_PROJECT_ID.appspot.com",
"messagingSenderId": "YOUR_SENDER_ID",
"appId": "YOUR_APP_ID",
"firestoreDatabaseId": "(default)"
}
참고: firestoreDatabaseId은 이전 단계에서 만든 데이터베이스 ID와 일치해야 합니다. 기본값을 사용한 경우 "(default)"로 둡니다.
변경사항을 저장소에 다시 커밋합니다.
git add frontend/firebase-applet-config.json
git commit -m "chore: add firebase config"
git push origin main
C. DinoQuest를 로컬에서 실행
1. 필요한 API 사용 설정
gcloud services enable \
run.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
secretmanager.googleapis.com \
firestore.googleapis.com \
logging.googleapis.com \
pubsub.googleapis.com \
eventarc.googleapis.com \
aiplatform.googleapis.com \
bigquery.googleapis.com \
aiplatform.googleapis.com
2. DinoQuest 시작
start.sh 스크립트는 React 프런트엔드를 빌드하고 컴파일된 정적 파일을 제공하는 FastAPI 백엔드에 터미널을 전달합니다.
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt -q
cd ..
# Force-remove the Vertex AI flag from the current terminal session to avoid conflicts
unset GOOGLE_GENAI_USE_VERTEXAI
./start.sh
브라우저에서 http://localhost:8000을 엽니다. DinoQuest 제목 화면이 표시됩니다. Google 계정으로 로그인하고 첫 번째 공룡을 생성한 후 Firestore에 저장되는지 확인합니다.
문제 해결: 빈 페이지 또는 Firebase 인증 오류가 표시되면 frontend/firebase-applet-config.json에 올바른 값이 있고 localhost이 승인된 도메인 목록에 있는지 다시 확인합니다.
E. Cloud Run에 DinoQuest 배포
1. 프로젝트 설정
export PROJECT_ID=$(gcloud config get-value project)
3. Artifact Registry 저장소 만들기
gcloud artifacts repositories create dinoquest \
--repository-format=docker \
--location=$CLOUD_RUN_REGION \
--description="DinoQuest container images"
4. Secret Manager에 Gemini API 키 저장
echo -n $GEMINI_API_KEY | \
gcloud secrets create gemini-api-key --data-file=-
# Grant the default compute service account access to the secret
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
gcloud secrets add-iam-policy-binding gemini-api-key \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
5. Cloud Build로 컨테이너 이미지 빌드
gcloud builds submit \
--tag $CLOUD_RUN_REGION-docker.pkg.dev/$PROJECT_ID/dinoquest/app:latest .
이렇게 하면 다단계 Dockerfile이 실행됩니다. 먼저 React 앱을 빌드한 다음 출력을 FastAPI 이미지로 패키징합니다. 3~5분 정도 걸립니다.
6. Cloud Run에 배포
먼저 관리자 이메일을 내보냅니다.
export ADMIN_EMAIL=<YOUR_TEST_ACCOUNT_EMAIL>
그런 다음 서비스를 배포합니다.
gcloud run deploy dinoquest \
--image=$CLOUD_RUN_REGION-docker.pkg.dev/$PROJECT_ID/dinoquest/app:latest \
--region=$CLOUD_RUN_REGION \
--platform=managed \
--allow-unauthenticated \
--memory=128Mi \
--set-secrets="GEMINI_API_KEY=gemini-api-key:latest" \
--set-env-vars="ADMIN_EMAILS=$ADMIN_EMAIL" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=False" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=$PROJECT_ID"
명령어가 완료되면 Cloud Run에서 서비스 URL을 출력합니다. 이 URL을 복사하세요. Firebase에서 도메인을 승인하는 데 필요합니다.
7. Firebase에서 Cloud Run 도메인 승인
배포된 앱에서 사용자가 로그인할 수 있도록 하려면 Cloud Run URL을 Firebase의 승인된 도메인에 추가해야 합니다.
- Firebase Console → 인증 → 설정 → 승인된 도메인으로 돌아갑니다.
- 도메인 추가를 클릭합니다.
- Cloud Run 서비스 URL (예:
dinoquest-xxxxx.us-central1.run.app)을 붙여넣고https://접두사를 삭제합니다. - 저장을 클릭합니다.
8. 리더보드 데이터 시드
게임에 초기 '생명력'을 부여하고 에이전트가 데이터를 보유하도록 하려면 시작 점수로 리더보드를 시드하면 됩니다.
dinoquest루트 디렉터리에 있는지 확인합니다.cd ~/dinoquest- 가상 환경 만들기 및 활성화
python3 -m venv venv source venv/bin/activate - 필요한 Firestore 종속 항목을 설치합니다.
pip install google-cloud-firestore - 시딩 스크립트를 실행합니다.
python3 prep/seed_scores.py - 가상 환경을 비활성화합니다.
deactivate
이제 브라우저에서 서비스 URL을 열 수 있습니다. DinoQuest가 완전히 라이브 상태입니다.
4. 공룡 극장 설정
상담사 역할: 시각화 도구 자율 에이전트 팀은 어떻게 모니터링하나요? Dino Theater는 에이전트 스웜의 생각을 실시간으로 보여줍니다. 터미널 로그를 응시하는 대신 에이전트가 추론하고, 서로를 호출하고, 클라우드 전반에서 작업을 실행하는 모습을 라이브 시각적 대시보드에서 확인할 수 있습니다.

A. Cloud Run에 Dino Theater 배포
먼저 홈 디렉터리로 돌아가서 Dino Theater 코드를 클론합니다.
cd ~
git clone https://github.com/gca-americas/dinoquest-theater.git
cd dinoquest-theater
- 컨테이너 빌드 및 푸시:
gcloud builds submit --tag $CLOUD_RUN_REGION-docker.pkg.dev/$PROJECT_ID/dinoquest/dino-theater:latest . - 서비스 계정 및 권한 설정:
# Create the service account gcloud iam service-accounts create dino-theater # Create the Pub/Sub topic (if you haven't yet) gcloud pubsub topics create harness-events # Create the subscription gcloud pubsub subscriptions create harness-events-theater \ --topic=harness-events # Grant subscriber role gcloud pubsub subscriptions add-iam-policy-binding harness-events-theater \ --member="serviceAccount:dino-theater@${PROJECT_ID}.iam.gserviceaccount.com" \ --role="roles/pubsub.subscriber" - 애플리케이션 배포:
참고:gcloud run deploy dino-theater \ --image $CLOUD_RUN_REGION-docker.pkg.dev/$PROJECT_ID/dinoquest/dino-theater:latest \ --region=$CLOUD_RUN_REGION \ --service-account=dino-theater@${PROJECT_ID}.iam.gserviceaccount.com \ --set-env-vars="GOOGLE_CLOUD_PROJECT=$PROJECT_ID" \ --allow-unauthenticated \ --min-instances=1--min-instances=1는 이벤트 간에 SSE 연결을 활성 상태로 유지하는 데 권장됩니다. - 작동 확인: 브라우저에서 배포된 서비스 URL (예:
https://dino-theater-xxx-uc.a.run.app/demo)을 엽니다.
5. IDE의 에이전트형 DevOps
상담사 역할: 네이티브 무중력 IDE와 클라우드 간의 격차를 해소하기 위해 Antigravity를 Google Cloud의 관리형 MCP 서버에 연결합니다. 이렇게 하면 네이티브 에이전트가 프로젝트를 '볼' 수 있으므로 API 키를 관리하거나 콘솔로 컨텍스트를 전환하지 않아도 로그를 파싱하고, 측정항목을 확인하고, 인프라에 대해 추론할 수 있습니다.
스킬을 실행하기 전에 Google Cloud에 대한 Antigravity의 액세스를 구성하고 DinoQuest 스킬 플레이북을 로드해야 합니다.
A. Google 관리형 MCP 서비스 설치
Google의 관리형 MCP 서비스는 호스팅된 단일 엔드포인트를 통해 모든 Google Cloud API에 대한 액세스를 제공합니다.
애플리케이션 기본 사용자 인증 정보를 사용하여 인증:
gcloud auth application-default login
B. mcp_config.json 구성
Antigravity 구성 디렉터리 (일반적으로 ~/.gemini/antigravity/mcp_config.json) 또는 콘솔에서 mcp_config.json을 만들거나 업데이트합니다. 이를 통해 Antigravity는 다음과 같은 기술에 필요한 Google Cloud 및 GitHub 도구에 액세스할 수 있습니다.
{
"mcpServers": {
"google-developer-knowledge": {
"serverUrl": "https://developerknowledge.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-bigquery": {
"serverUrl": "https://bigquery.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-cloud-logging": {
"serverUrl": "https://logging.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-cloud-monitoring": {
"serverUrl": "https://monitoring.googleapis.com/mcp",
"authProviderType": "google_credentials",
"disabledTools": [
"get_dashboard",
"list_dashboards"
]
},
"google-cloud-run": {
"serverUrl": "https://run.googleapis.com/mcp",
"authProviderType": "google_credentials",
"disabledTools": [
"deploy_service_from_image",
"deploy_service_from_archive",
"deploy_service_from_file_contents"
]
},
"google-cloud-sql": {
"serverUrl": "https://sqladmin.googleapis.com/mcp",
"authProviderType": "google_credentials",
"disabled": true
},
"google-cloud-trace": {
"serverUrl": "https://cloudtrace.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-error-reporting": {
"serverUrl": "https://clouderrorreporting.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-firestore": {
"serverUrl": "https://firestore.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"google-resource-manager": {
"serverUrl": "https://cloudresourcemanager.googleapis.com/mcp",
"authProviderType": "google_credentials"
},
"gemini-cloud-assist": {
"serverUrl": "https://geminicloudassist.googleapis.com/mcp",
"authProviderType": "google_credentials"
}
}
}
C. Antigravity에 스킬 로드 (선택사항)
Antigravity는 특정 표준 디렉터리에서 기술을 검색합니다. 클론된 저장소에서 DinoQuest 스킬을 전역 Antigravity 스킬 폴더로 복사합니다.
# Create the standard skills directory if it doesn't exist
mkdir -p ~/.gemini/antigravity/skills
# Copy all DinoQuest skills into the global skills folder
cp -r skills/* ~/.gemini/antigravity/skills/
D. Antigravity 다시 시작(선택사항)
mcp_config.json 변경사항을 적용하고 새로 복사된 스킬을 로드하려면 Antigravity 애플리케이션을 다시 시작합니다.
다시 시작한 후:
- 설정에서 google 및 github MCP 서버가 녹색 '연결됨' 상태로 표시되는지 확인합니다.
- DinoQuest 스킬이 스킬 목록에 표시되는지 확인합니다.
참고: 각 스킬의 SKILL.md 상단에는 ## Configuration 표가 있습니다. 복사한 후에는 프로젝트와 일치하도록 ~/.gemini/antigravity/skills/의 값을 업데이트해야 합니다.
E. 로컬 IDE에서 클라우드 서비스 수정
- 오류 트리거: 브라우저에서 배포된 DinoQuest URL (마지막 단계)을 엽니다.
- 리더보드로 이동: 리더보드 버튼을 클릭합니다. 현재 리더보드 구현은 의도적으로 비효율적입니다. 대량의 데이터를 메모리에 로드하려고 시도하여 메모리 부족 (OOM) 오류를 트리거합니다.
- Antigravity Agent Manager (Agent HUB)에서 오류를 복구하고 근본 원인을 수정하도록 요청합니다.
- 프롬프트 1: dinoquest에 어떤 문제가 있는지 알아봐 줘.
- 프롬프트 2: Dinoquest 게임의 코드를 살펴보고 메모리 부족 오류의 원인을 수정해 줘.
6. BigQuery로 로그를 스트리밍하고 분석 생성
상담사 역할: 데이터 상담사 원시 로그를 실행 가능한 제품 전략으로 변환하는 데 몇 시간 동안 수동으로 데이터를 처리할 필요가 없습니다. 데이터 에이전트 키트와 BigQuery MCP를 사용하여 로그를 BigQuery로 직접 스트리밍하는 '제로 ETL' 파이프라인을 만들어 에이전트가 2분 이내에 프리미엄 분석 대시보드를 생성할 수 있습니다.
log-router-bq-report 기능은 DinoQuest의 Cloud Run 로그를 BigQuery로 지속적으로 스트리밍하는 Cloud Logging 싱크를 설정한 다음 데이터를 쿼리하여 트래픽 보고서와 게임 분석 통계를 생성합니다.

A. 스킬 변수 구성
DinoQuest 저장소에서 skills/log-router-bq-report/SKILL.md를 열고 상단의 Configuration 섹션을 업데이트합니다.
| Variable | Your Value |
|---------------|--------------------|
| SERVICE_NAME | dinoquest |
| BQ_DATASET | dinoquest_logs |
| LOG_SINK_NAME | dinoquest-bq-sink |
B. Antigravity에서 스킬 실행
DinoQuest 저장소를 컨텍스트로 사용하여 Antigravity를 열고 Gemini에 다음을 요청합니다.
Run the log-router-bq-report skill
이 스킬은 다음을 수행합니다.
- GCP 프로젝트 자동 해결
- BigQuery 싱크가 이미 있는지 확인합니다. 없으면 데이터 세트와 싱크가 생성됩니다.
- IAM 권한 부여: 싱크의
writerIdentity에 데이터 세트의 BigQuery 데이터 편집자 역할을 부여합니다.
참고: Eventarc 싱크와 마찬가지로 이 과정에서 gcloud로부터 'dataset에 serviceAccount:service-...에 BigQuery 데이터 편집자 역할을 부여하세요.'라는 경고가 표시될 수 있습니다. 기능에서 이 작업을 자동으로 처리합니다.
C. Antigravity를 사용하여 보고서 생성
Antigravity에 'BigQuery 로그 싱크를 설정하고 분석 보고서를 생성해 줘'라고 요청하기만 하면 됩니다. 상담사는 다음 작업을 수행합니다.
- 인프라 구성: BigQuery 데이터 세트와 Cloud Logging 싱크를 만듭니다.
- 권한 관리: 싱크의 작성자 ID에 필요한 IAM 역할을 자동으로 부여합니다.
- 통계 생성: 로그를 분석하고 게임 원격 분석 및 승률 분석이 포함된 프리미엄 대화형 HTML 대시보드를 생성합니다.
7. 자가 복구 해결 에이전트
상담사 역할: SRE 상담사 오전 2시에 프로덕션 서비스에 장애가 발생해도 잠에서 깨지 않아도 됩니다. 이 상담사는 초기 대응자 역할을 합니다. Eventarc를 통해 Cloud Run 오류 로그에 의해 트리거되며, 콘솔에 로그인하기도 전에 비정상 종료를 자동으로 분석하고 수정사항을 제안하며 수정 파이프라인을 시작합니다.
DinoAgent는 Eventarc를 통해 Cloud Run 오류 로그를 수신하고, 근본 원인을 진단하고, 메모리를 늘리거나, 트래픽을 롤백하거나, GitHub에 코드 수정 PR을 제출하여 자동으로 해결하는 ADK 에이전트입니다.

A. Remediation Agent 저장소 클론
cd ~
git clone https://github.com/gca-americas/dinoquest-reme-agent.git
cd dinoquest-reme-agent
프로젝트 구조는 다음과 같습니다.
dinoquest-reme-agent/
├── main.py # Service entrypoint — receives Eventarc HTTP POST, runs agent
├── runner.py # ADK Runner + session service
├── agent.py # LlmAgent definition, loads skill from file
├── tools.py # Cloud Run v2 API tools (list/get/rollback/update)
├── skills/
│ └── remediation/
│ ├── SKILL.md # Agent playbook — edit this to change behavior
│ └── scripts/ # Shell scripts for the code-fix track
│ ├── clone_repo.sh
│ ├── read_file.sh
│ ├── apply_fix.sh
│ ├── commit_branch.sh
│ ├── open_pr.sh
│ └── rollback_fix.sh
├── requirements.txt
└── Dockerfile
B. GitHub 액세스 설정 (코드 수정 트랙)
코드 수정 트랙은 DinoQuest 저장소를 클론하고, 소스 파일을 읽고, 패치를 적용하고, PR을 엽니다. repo 범위가 있는 GitHub 개인 액세스 토큰이 필요합니다.
- github.com/settings/tokens → Generate new token (classic)으로 이동합니다.
- 이름을 지정하고
repo범위 → 토큰 생성을 선택한 다음 복사합니다.
Secret Manager에 저장합니다.
먼저 GitHub 토큰을 내보냅니다.
export GH_TOKEN=ghp_YOUR_TOKEN_HERE
그런 다음 보안 비밀을 만듭니다.
echo -n $GH_TOKEN | \
gcloud secrets create github-token --data-file=-
C. Slack 알림 설정 (선택사항)
수정이 완료되면 DinoAgent가 Slack 채널에 요약을 게시합니다.
- api.slack.com/apps → 새 앱 만들기 → 처음부터로 이동합니다.
- 이름을
DinoAgent로 지정하고 작업공간을 선택한 후 앱 만들기를 선택합니다. - 기능 → 수신 웹훅 → 사용 설정
- Add New Webhook to Workspace(새로운 웹훅을 작업공간에 추가)를 클릭하고 채널을 선택한 다음 Allow(허용)를 클릭합니다.
- 웹훅 URL (
https://hooks.slack.com/services/...) 복사
Secret Manager에 저장합니다.
export SLACK_TOKEN=YOUR_SLACK_WEBHOOK
echo -n "https://hooks.slack.com/services/$SLACK_TOKEN" | \
gcloud secrets create slack-webhook --data-file=-
D. DinoAgent 서비스 계정 만들기
gcloud iam service-accounts create remediation-agent \
--display-name="Cloud Run Remediation Agent"
export SA="remediation-agent@${PROJECT_ID}.iam.gserviceaccount.com"
for ROLE in \
roles/run.admin \
roles/iam.serviceAccountUser \
roles/eventarc.eventReceiver \
roles/aiplatform.user \
roles/artifactregistry.reader \
roles/secretmanager.secretAccessor \
roles/pubsub.publisher \
roles/logging.viewer; do
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SA}" --role="$ROLE" \
--condition=None
done
보안 비밀에 대한 액세스 권한을 부여합니다.
for SECRET in github-token slack-webhook; do
gcloud secrets add-iam-policy-binding $SECRET \
--member="serviceAccount:${SA}" \
--role="roles/secretmanager.secretAccessor"
done
E. DinoAgent를 빌드하여 Cloud Run에 배포
# Get Project Number for the CIAgent URL
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export CIAGENT_URL=https://ci-agent-${PROJECT_NUMBER}.${CLOUD_RUN_REGION}.run.app
export SA="remediation-agent@${PROJECT_ID}.iam.gserviceaccount.com"
export GITHUB_REPO_URL=https://github.com/YOUR_REPO
HARNESS_EVENTS_TOPIC=projects/$PROJECT_ID/topics/harness-events
AGENT_IMAGE="$CLOUD_RUN_REGION-docker.pkg.dev/${PROJECT_ID}/dinoquest/remediation-agent:latest"
gcloud builds submit --tag $AGENT_IMAGE .
gcloud run deploy remediation-agent \
--image=$AGENT_IMAGE \
--region=$CLOUD_RUN_REGION \
--service-account=$SA \
--memory=2Gi \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID},GOOGLE_GENAI_USE_VERTEXAI=True" \
--set-env-vars="GITHUB_REPO_URL=${GITHUB_REPO_URL}" \
--set-secrets="SLACK_WEBHOOK_URL=slack-webhook:latest" \
--set-env-vars="HARNESS_EVENTS_TOPIC=${HARNESS_EVENTS_TOPIC}" \
--set-env-vars="CIAGENT_URL=${CIAGENT_URL}" \
--set-secrets="GITHUB_TOKEN=github-token:latest" \
--no-allow-unauthenticated \
--min-instances=1 \
--no-cpu-throttling \
--timeout=300
F. Eventarc 트리거 연결
Cloud Run 오류 로그를 수신할 Pub/Sub 주제를 만듭니다.
gcloud pubsub topics create cloud-run-errors
dinoquest 서비스의 오류 로그를 필터링하여 주제로 라우팅하는 Cloud Logging 싱크를 만듭니다.
export SERVICE_NAME=dinoquest
FILTER="resource.type=\"cloud_run_revision\" resource.labels.service_name=\"$SERVICE_NAME\" severity=ERROR NOT logName=~\"cloudaudit\" NOT httpRequest.requestUrl=~\"/_ah/health\""
gcloud logging sinks create cloud-run-errors-sink \
pubsub.googleapis.com/projects/${PROJECT_ID}/topics/cloud-run-errors \
--log-filter="$FILTER"
참고: 위의 명령어를 실행하면 gcloud에서 '주제에 serviceAccount:service-...에 Pub/Sub 게시자 역할을 부여하세요.'라는 정보 메시지를 출력합니다. 다음 단계에서 이를 처리합니다.
싱크의 작성자 ID (경고에 언급된 서비스 계정)에 게시 권한을 부여합니다.
SINK_SA=$(gcloud logging sinks describe cloud-run-errors-sink \
--format='value(writerIdentity)')
gcloud pubsub topics add-iam-policy-binding cloud-run-errors \
--member="${SINK_SA}" --role="roles/pubsub.publisher"
활성 상태인지 확인합니다.
gcloud eventarc triggers describe remediation-trigger --location=$CLOUD_RUN_REGION
수정 에이전트를 호출할 수 있는 Eventarc 권한을 부여합니다.
gcloud run services add-iam-policy-binding remediation-agent \
--region=$CLOUD_RUN_REGION \
--member="serviceAccount:${SA}" \
--role="roles/run.invoker"
Eventarc 트리거를 만듭니다.
gcloud eventarc triggers create remediation-trigger \
--location=$CLOUD_RUN_REGION \
--destination-run-service=remediation-agent \
--destination-run-region=$CLOUD_RUN_REGION \
--event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \
--transport-topic=projects/${PROJECT_ID}/topics/cloud-run-errors \
--service-account=${SA}
이제 수정이 완전히 자동화되었습니다. 인프라 확장뿐만 아니라 DinoAgent는 애플리케이션 코드에 대한 심층적인 근본 원인 분석을 실행하고, 시맨틱 패치를 적용하며, 에이전트 간 (A2A) 통신을 사용하여 검증 및 배포를 위해 CI 에이전트에게 수정사항을 전달합니다. reme-agent 코드베이스에서 구현 세부정보를 살펴볼 수 있습니다.
8. CI 에이전트 설정
에이전트 역할: CI 파이프라인 복잡한 YAML 파일과 수동 빌드 스크립트와 씨름하지 마세요. 이 에이전트는 PR의 운영 파이프라인을 관리합니다. 코드 변경사항을 읽고, 컨텍스트를 이해하고, 필요한 테스트의 범위를 지정하고, Cloud Build를 통해 Docker 이미지를 빌드하여 모든 커밋이 기본 브랜치에 도달하기 전에 '에이전트 승인'을 받도록 합니다.
ci-agent는 Cloud Run 서비스로 배포된 자율 CI 파이프라인 에이전트입니다. Docker 빌드를 Cloud Build에 제출하고, 완료 여부를 폴링하고, Artifact Registry에서 이미지를 확인하고, GitHub에 보고합니다.

CI 파이프라인에 에이전트를 사용하는 이유는 무엇인가요? 기존 정적 스크립트와 달리 에이전트형 CI 파이프라인은 다음을 제공합니다.
- 인지 범위 분류: 코드 변경사항의 의미론적 영향을 기반으로 필요한 테스트 깊이를 지능적으로 결정하여 유형 검사, 단위 테스트 또는 전체 통합 스위트 간에 전환합니다.
- 자율 PR 관리: 에이전트는 사람의 개입 없이 PR을 자동으로 생성하고, 변경사항에 대한 자세한 요약을 게시하며, 비밀 스캔 및 보안 감사를 관리할 수 있습니다.
- 실시간 실패 진단: 빌드가 실패하면 에이전트는 로그만 표시하는 것이 아니라 스택 트레이스를 분석하고, 가능성 있는 원인을 식별하고, 사람이 읽을 수 있는 진단을 PR에 직접 게시합니다.
A. CIAgent 저장소 클론
cd ~
git clone https://github.com/gca-americas/dinoquest-ci-agent.git
cd dinoquest-ci-agent
B. CIAgent 서비스 계정 만들기
gcloud iam service-accounts create ci-agent \
--display-name="CIAgent CI Pipeline"
export SA="ci-agent@${PROJECT_ID}.iam.gserviceaccount.com"
# Grant necessary roles to the service account
for ROLE in \
roles/cloudbuild.builds.editor \
roles/cloudbuild.builds.builder \
roles/artifactregistry.reader \
roles/artifactregistry.writer \
roles/aiplatform.user \
roles/secretmanager.secretAccessor \
roles/pubsub.publisher \
roles/developerconnect.admin; do
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SA}" --role="$ROLE" \
--condition=None
done
# ci-agent needs to act as itself when running build steps
gcloud iam service-accounts add-iam-policy-binding $SA \
--member="serviceAccount:${SA}" \
--role="roles/iam.serviceAccountUser"
C. GitHub 저장소를 Cloud Build에 연결
CIAgent는 repoSource를 통해 빌드를 제출하며, 이를 위해서는 GitHub 저장소가 Cloud Build Developer Connect에 연결되어 있어야 합니다.
- GCP Console → Cloud Build → Repositories로 이동합니다.
- 저장소 연결을 클릭합니다.
- GitHub (Cloud Build GitHub 앱)을 선택합니다.
YOUR_GITHUB_USERNAME/dinoquest저장소 승인 및 선택- 트리거를 만들라는 메시지가 표시되면 연결 및 건너뛰기를 클릭합니다.
- 연결 이름을 기록해 둡니다 (기본값은 일반적으로 GitHub 사용자 이름 또는 이와 유사한 이름임).
D. 보안 비밀에 대한 CIAgent 액세스 권한 부여
이전에 DinoAgent를 위해 만든 보안 비밀을 재사용합니다.
gcloud secrets add-iam-policy-binding github-token \
--member="serviceAccount:${SA}" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding slack-webhook-ci \
--member="serviceAccount:${SA}" \
--role="roles/secretmanager.secretAccessor"
E. CIAgent를 빌드하여 Cloud Run에 배포
# Set up required variables for orchestration
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
export CDAGENT_URL=https://cd-agent-${PROJECT_NUMBER}.${CLOUD_RUN_REGION}.run.app
export CI_AGENT_URL=ci-agent-${PROJECT_NUMBER}.${CLOUD_RUN_REGION}.run.app
export GITHUB_OWNER="YOUR_GITHUB_USERNAME"
export CLOUD_BUILD_CONNECTION="YOUR_CONNECTION_NAME" # Update this if your connection name is different
export CLOUD_BUILD_REPO="YOUR_GITHUB_USERNAME-dinoquest" # Update this if your connection name is different
export SLACK_TOKEN=YOUR_SLACK_WEBHOOK
echo -n "https://hooks.slack.com/services/$SLACK_TOKEN" | \
gcloud secrets create slack-webhook-ci --data-file=-
export SA="ci-agent@${PROJECT_ID}.iam.gserviceaccount.com"
AGENT_IMAGE="$CLOUD_RUN_REGION-docker.pkg.dev/${PROJECT_ID}/dinoquest/ci-agent:latest"
gcloud builds submit --tag $AGENT_IMAGE .
gcloud run deploy ci-agent \
--image=$AGENT_IMAGE \
--region=$CLOUD_RUN_REGION \
--service-account=$SA \
--memory=1Gi \
--timeout=600 \
--allow-unauthenticated \
--min-instances=1 \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID},GOOGLE_GENAI_USE_VERTEXAI=True" \
--set-env-vars="HARNESS_EVENTS_TOPIC=${HARNESS_EVENTS_TOPIC}" \
--set-env-vars="HOST=${CI_AGENT_URL},PROTOCOL=https" \
--set-secrets="SLACK_WEBHOOK_URL=slack-webhook-ci:latest" \
--set-env-vars="GITHUB_OWNER=${GITHUB_OWNER},GITHUB_REPO=dinoquest" \
--set-env-vars="CLOUD_BUILD_CONNECTION=${CLOUD_BUILD_CONNECTION},CLOUD_BUILD_REPO=${CLOUD_BUILD_REPO},CLOUD_BUILD_REGION=${CLOUD_RUN_REGION}" \
--set-env-vars="CDAGENT_URL=${CDAGENT_URL}" \
--set-secrets="GITHUB_TOKEN=github-token:latest" \
--min-instances=1
F. Slack 슬래시 명령어 설정
- api.slack.com/apps → 새 앱 만들기 → 처음부터로 이동합니다.
- 이름을
CIAgent로 지정하고 작업공간을 선택한 후 앱 만들기를 선택합니다. - 기능 → 슬래시 명령어 → 새 명령어 만들기
- 명령어:
/runci - 요청 URL: 위에 나온 CIAgent Cloud Run URL에
/slack가 추가됨 (예:https://ci-agent-xxx-.us-central1.run.app/slack) - 간단한 설명:
Trigger CI - 저장
- 설정 → 앱 설치에서 Workspace에 설치를 클릭하고 허용합니다.
CI 에이전트는 Cloud Build, Artifact Registry와 같은 강력한 Google Cloud 서비스 위에 있는 '브레인' 역할을 합니다. 빌드가 확인되면 A2A를 통해 CD 에이전트를 호출하여 최종 배포 단계를 트리거하므로 빌드와 출시 주기 간에 원활한 핸드오프가 보장됩니다.
9. 배포 설정
상담사 역할: CD 상담사 배포는 무모한 시도가 아니어야 합니다. 이 에이전트는 위험을 관리합니다. 배포 안전성을 평가하고, 카나리아 트래픽 분할을 관리하고, 실시간 측정항목을 모니터링하여 출시를 승격할지 아니면 롤백할지 결정합니다. 자율 에이전트 스웜의 최종 관문입니다.
cd-agent는 Cloud Run 서비스로 배포되는 자율 카나리아 배포 에이전트입니다. ci-agent에서 A2A 배포 요청을 수신하고, 위험 점수를 계산하고, 위험에 따라 조정된 카나리아 백분율을 설정하고, 측정항목을 모니터링하고, 자동으로 승격하거나 롤백합니다. 또한 Firestore를 사용한 이전 배포에서 학습합니다.

에이전트를 직접 연결하면 각 핸드오프가 의도와 컨텍스트의 풍부한 전송인 '인지 파이프라인'이 생성됩니다. 기존 웹훅과 달리 A2A 통신을 사용하면 다음이 가능합니다.
- 지능형 컨텍스트 공유: 에이전트가 전체 세션 메모리, PR 차이, 위험 점수를 전달하여 다음 에이전트가 작업을 시작하기 전에 전체 '이유'를 파악할 수 있습니다.
- 인지 핸드셰이크: 에이전트가 게이트를 협상할 수 있습니다. 예를 들어 CD 에이전트는 카나리아 출시 중에 CI 에이전트에게 특정 스모크 테스트를 요청하여 실시간으로 수정사항을 확인할 수 있습니다.
- 협업적 해결: 배포가 실패하면 CD 에이전트가 실패한 측정항목을 사용하여 해결 에이전트에게 사전 알림을 보내 사람이 호출되기 전에 자율적인 근본 원인 분석을 시작할 수 있습니다.
- 리소스 협상: 상담사가 인프라 요구사항을 협상할 수 있습니다. 예를 들어 CI 에이전트는 대규모 리팩터링을 감지하면 수정 에이전트에게 빌드 용량을 더 프로비저닝하도록 요청할 수 있고, CD 에이전트는 주요 출시 전에 프로덕션 클러스터의 확장을 제안할 수 있습니다.
- 멀티 에이전트 컨센서스: 위험도가 높은 변경사항의 경우 여러 에이전트 (예: 보안 에이전트 및 CD 에이전트)가 A2A를 통해 '공동 승인'을 실행하여 프로덕션에 도달하기 전에 코드가 빌드 및 배포될 뿐만 아니라 보안 정책을 준수하는지 확인할 수 있습니다.
A. CDAgent 저장소 클론
cd ~
git clone https://github.com/gca-americas/dinoquest-cd-agent.git
cd dinoquest-cd-agent
B. Firestore 데이터베이스 만들기
CDAgent는 배포 메모리 패턴을 Firestore에 저장합니다.
gcloud firestore databases create \
--region=$CLOUD_RUN_REGION \
--project=$PROJECT_ID
(이 프로젝트에 이미 데이터베이스를 만든 경우 이 단계를 건너뛸 수 있습니다.)
C. CDAgent 서비스 계정 만들기
gcloud iam service-accounts create cd-agent \
--display-name="CDAgent Canary Deployer"
export SA="cd-agent@${PROJECT_ID}.iam.gserviceaccount.com"
# Grant necessary roles
for ROLE in \
roles/run.developer \
roles/iam.serviceAccountUser \
roles/artifactregistry.reader \
roles/artifactregistry.writer \
roles/monitoring.viewer \
roles/datastore.user \
roles/aiplatform.user \
roles/run.admin \
roles/pubsub.publisher; do
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:${SA}" --role="$ROLE" \
--condition=None
done
D. 보안 비밀에 대한 CDAgent 액세스 권한 부여
이전에 사용한 GitHub 토큰과 Slack 웹훅을 재사용하고 배포된 앱이 사용할 수 있도록 Cloud Run 서비스 계정에 Gemini API 키에 대한 액세스 권한을 부여합니다.
gcloud secrets add-iam-policy-binding github-token \
--member="serviceAccount:${SA}" \
--role="roles/secretmanager.secretAccessor"
gcloud secrets add-iam-policy-binding slack-webhook-cd \
--member="serviceAccount:${SA}" \
--role="roles/secretmanager.secretAccessor"
# Grant the compute service account access to Gemini API key
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
gcloud secrets add-iam-policy-binding gemini-api-key \
--project=$PROJECT_ID \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
E. CDAgent를 빌드하여 Cloud Run에 배포
export GITHUB_OWNER="YOUR_GITHUB_USERNAME"
export CD_AGENT_URL=cd-agent-${PROJECT_NUMBER}.${CLOUD_RUN_REGION}.run.app
export SLACK_TOKEN=YOUR_SLACK_WEBHOOK
echo -n "https://hooks.slack.com/services/$SLACK_TOKEN" | \
gcloud secrets create slack-webhook-cd --data-file=-
AGENT_IMAGE="$CLOUD_RUN_REGION-docker.pkg.dev/${PROJECT_ID}/dinoquest/cd-agent:latest"
gcloud builds submit --tag $AGENT_IMAGE .
export SA="cd-agent@${PROJECT_ID}.iam.gserviceaccount.com"
gcloud run deploy cd-agent \
--image=$AGENT_IMAGE \
--region=$CLOUD_RUN_REGION \
--service-account=$SA \
--memory=1Gi \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=True" \
--set-env-vars="HOST=${CD_AGENT_URL},PROTOCOL=https" \
--set-env-vars="CD_TARGET_SERVICE=dinoquest" \
--set-env-vars="HARNESS_EVENTS_TOPIC=${HARNESS_EVENTS_TOPIC}" \
--set-env-vars="GITHUB_OWNER=${GITHUB_OWNER}" \
--set-env-vars="GITHUB_REPO=dinoquest" \
--set-env-vars="DEMO_MODE=true" \
--set-env-vars="LEADERBOARD_ENABLED=true" \
--set-secrets="SLACK_WEBHOOK_URL=slack-webhook-cd:latest" \
--set-secrets="GITHUB_TOKEN=github-token:latest" \
--allow-unauthenticated \
--min-instances=1 \
--no-cpu-throttling \
--timeout=300
참고: --min-instances=1 --no-cpu-throttling는 인스턴스를 활성 상태로 유지하여 Slack 및 A2A 명령어에 신속하게 응답할 수 있도록 합니다.
CD 에이전트는 프로덕션 환경의 최종 관리자입니다. 각 배포의 위험을 평가하고 위험 보정 카나리아를 실행하며 실시간 측정항목을 모니터링합니다. 이상치가 감지되면 자동 롤백이 시작됩니다.
10. 확장: 에이전트 스웜으로 레벨 2 잠금 해제
A. 전체 스웜 테스트
- 오류 트리거: 브라우저에서 배포된 DinoQuest URL (마지막 단계)을 엽니다.
- 리더보드로 이동: 리더보드 버튼을 클릭합니다. 현재 리더보드 구현은 의도적으로 비효율적입니다. 대량의 데이터를 메모리에 로드하려고 시도하여 메모리 부족 (OOM) 오류를 트리거합니다.
- 에이전트 대기: 약 60초 이내에
remediation-agent가 Eventarc를 통해 오류 이벤트를 수신하고 진단을 시작합니다. - Slack 확인: Slack 채널에 다음과 같은 알림이 표시됩니다.DinoAgent 수정 요약
- 서비스: dinoquest
- 실패한 버전: dinoquest-xxxx-xxxx
- 증거: '사용된 13xMiB로 메모리 제한 128MiB 초과'
- 이 수정사항이 잘못된 이유:
/api/leaderboard엔드포인트가 비효율적으로 xxxxx되어 OOM 오류가 발생했습니다. - 취한 조치: 서비스
dinoquest의 메모리를 xMi에서 yGi로 늘렸습니다. 새 버전이 생성되었습니다. - 근본 원인 PR: https://github.com/YOUR_USERNAME/DinoQuest/pull/x
- 수정사항 확인:
- GitHub: 저장소에서 새 브랜치와 풀 요청을 확인합니다. 에이전트가 기본 메모리 누수를 수정하기 위해 애플리케이션 코드를 패치했습니다.
- Cloud Run: GCP Console에 업데이트된 메모리 할당이 적용된
dinoquest서비스의 새 버전이 표시됩니다. - 리더보드: 리더보드를 다시 시도해 보세요. 메모리가 증가하고 결국 코드 수정이 이루어져 이제 리더보드가 제대로 로드될 것입니다.
B. 진화: 레벨 2 게임 로직 구현
레벨 2 (소행성 파괴자)라는 새로운 기능을 추가합니다. 이를 통해 최고 점수를 받은 공룡이 새로운 게임 모드로 진행할 수 있습니다.
- dinoquest 저장소로 돌아갑니다.
cd ~/dinoquest - 새 브랜치를 만들고 전환:
git checkout -b level_2 - 레벨 2 패치 적용: 제공된 스크립트를 실행하여 레벨 2 애셋, 구성요소, 게임 로직으로 로컬 코드베이스를 패치합니다.
bash level_2_backup/levelup.sh - 변경사항을 커밋하고 푸시합니다.
git add . git commit -m "feat: add Level 2" git push origin level_2
curl를 사용하여 에이전트를 수동으로 트리거하는 대신 이전에 구성한 Slack 슬래시 명령어를 사용합니다. 실제 시나리오에서 자율 CI 파이프라인과 상호작용하는 방법입니다.
- Slack을 열고
CIAgent앱이 설치된 채널로 이동합니다. - 다음 명령어를 입력하여 CI 빌드를 트리거합니다.
/runci run ci on branch level_2 - 진행 상황 모니터링:
- Slack: 에이전트가 명령을 확인하고 빌드가 진행됨에 따라 업데이트를 게시합니다.
- Dino Theater: 에이전트가 변경사항을 분류하고, Cloud Build 작업을 제출하고, CD 에이전트와 통신할 때 '생각 풍선'을 확인합니다.
- GitHub:
level_2PR을 확인합니다. 에이전트가 커밋 상태와 전체 CI 보고서 주석을 게시하는 것을 확인할 수 있습니다.
- 절차 확인:
- Dino Theater에서 CI 에이전트가 생각하고, 변경사항을 분류하고, 파이프라인을 실행하는지 확인합니다.
- GitHub PR을 확인하여 CI 에이전트가 커밋 상태와 최종 보고서를 게시하는지 확인합니다.
11. 결론
Google Cloud에서 완전한 에이전트 기반 DevOps 스택을 빌드했습니다.
구성요소 | 기능 |
DinoQuest (Cloud Run | Gemini 기반 게임 - React 프런트엔드 + FastAPI 백엔드 |
Firebase 인증 + Firestore | 사용자 인증 및 공룡 프로필 저장 |
수정 에이전트 (Cloud Run + Eventarc) | OOM 오류 및 코드 버그를 자동으로 수정하는 SRE 에이전트 |
log-router-bq-report | 로그를 BigQuery로 스트리밍하고 인사이트를 생성하는 데이터 에이전트 |
CIAgent (Cloud Run) | 테스트 범위를 지정하고, 이미지를 빌드하고, A2A를 통해 CD를 호출하는 CI 에이전트 |
CDAgent (Cloud Run) | 자동 롤백으로 위험 점수가 매겨진 카나리아 배포를 실행하는 CD 에이전트 |
모든 에이전트 동작은 skills/ 디렉터리에 마크다운 플레이북으로 저장됩니다. 코드가 아닌 기능을 수정하여 동작을 변경하세요. 스킬은 Antigravity with Gemini에서 실행되며, 에이전트에게 실행할 스킬을 알려주면 호출됩니다.