API Resource Manager: Quy trình tự động hóa và tính nhất quán
Vì sao Resource Manager API quan trọng
Khi quy mô các triển khai GCP lên đến hàng trăm projects, quản lý thủ công qua Google Cloud Console trở nên không thể mở rộng. Resource Manager API là giao diện lập trình để:
- Tạo/xóa projects
- Di chuyển projects giữa các folders
- Liệt kê resources theo phân cấp
- Truy vấn trạng thái resource
- Áp dụng IAM policies theo phân cấp
- Quản lý labels của project bằng chương trình
Thực tế trong production: Mọi tổ chức GCP cấp enterprise đều dùng Infrastructure as Code (Terraform, Pulumi, các công cụ tương đương CloudFormation) để tự động hóa việc tạo resource. Resource Manager API là xương sống của toàn bộ các công cụ này.
Các lỗi thường gặp:
- Script tự động hóa không tính đến độ trễ lan truyền → trạng thái không nhất quán
- Truy vấn API trước khi resources được lan truyền đầy đủ → lỗi 404, race condition
- Giả định thao tác đồng bộ trong khi thực tế là bất đồng bộ → lỗi một phần không được phát hiện
- Không triển khai retry logic đúng cách → lỗi âm thầm trong pipeline CI/CD
Kiến trúc Resource Manager API
Resource Manager API được chia thành ba thành phần chính:
1. Resource API (Control Plane)
Xử lý các thao tác CRUD cho project/folder:
# Tạo project
curl -X POST https://cloudresourcemanager.googleapis.com/v3/projects \
-H "Authorization: Bearer $TOKEN" \
-d '{
"projectId": "my-new-project",
"displayName": "My New Project",
"parent": "folders/1234567890"
}'
# Response trả về một Operation object (bất đồng bộ)
{
"name": "operations/cp.123456789",
"done": false,
"createTime": "2026-06-01T10:00:00Z"
}Quan trọng: Tất cả thao tác tạo project đều là bất đồng bộ. API trả về Operation object với done: false, không phải resource project trực tiếp.
2. Metadata API (Propagation Layer)
Sau khi project được tạo, metadata phải lan truyền tới tất cả GCP services:
- Metadata cho bật API
- Cache IAM policy
- Hệ thống quota
- Hệ thống billing
- Metadata đặc thù của từng service
Mốc thời gian lan truyền (điển hình):
T+0s: Project được tạo ở control plane
T+0.5-2s: Project hiển thị trong GCP Console
T+2-5s: IAM policies bắt đầu lan truyền
T+5-10s: Phần lớn GCP services đã thấy project
T+10-30s: Tất cả services nhất quán hoàn toàn (eventual consistency)
T+30s+: Hoàn tất caching/lan truyền3. Query API (Cloud Asset Inventory)
Truy vấn phân cấp tài nguyên bằng chương trình:
# Tìm kiếm tất cả resources trong organization
gcloud asset search-all-resources \
--scope=organizations/123456789 \
--asset-types=compute.googleapis.com/Instance,storage.googleapis.com/BucketĐằng sau, Cloud Asset Inventory duy trì view đã được index của toàn bộ resources — cho phép truy vấn hiệu quả. Nhưng các truy vấn vẫn bị ảnh hưởng bởi eventual consistency.
Mô hình eventual consistency
GCP không đảm bảo strong consistency cho các thao tác trên phân cấp tài nguyên. Thay vào đó:
- Control plane: Strong consistency (tạo project hiển thị ngay trong API)
- Data plane: Eventual consistency (services thấy thay đổi sau 5-30 giây)
- Client libraries: Có thể cache kết quả (gây thêm độ trễ)
Tại sao? Strong consistency sẽ đòi hỏi:
- Đồng bộ trạng thái tới tất cả regions
- Chặn trên mọi service phụ thuộc
- Độ trễ cao hơn nhiều (có thể tới hàng trăm mili giây)
Thay vào đó, GCP chọn độ sẵn sàng cao + eventual consistency, đây là đánh đổi phù hợp cho phần lớn workload.
Hệ quả thực tế
Kịch bản 1: Tạo project + bật API
from google.cloud import resourcemanager
from google.cloud import resource_manager
# Tạo project
rm_client = resourcemanager.Client()
project = rm_client.project(project_id)
project.create()
print(f"Created project {project_id}")
# ❌ VẤN ĐỀ: Bật API ngay lập tức
serviceusage_client = service_usage.ServiceUsageClient()
request = service_usage.BatchEnableServicesRequest(
parent=f"projects/{project_id}",
service_names=["compute.googleapis.com"]
)
response = serviceusage_client.batch_enable_services(request)
# Có thể thất bại với lỗi "project not found" nếu propagation chưa hoàn tất
# ✅ TỐT HƠN: Retry với backoff
import time
from google.api_core import retry
@retry.Retry(deadline=60)
def enable_api_with_retry(project_id, api_name):
try:
request = service_usage.BatchEnableServicesRequest(
parent=f"projects/{project_id}",
service_names=[api_name]
)
return serviceusage_client.batch_enable_services(request)
except google.api_core.exceptions.NotFound:
# Project chưa hiển thị với Service Usage API
time.sleep(2)
raise # Retry sẽ xử lý
enable_api_with_retry(project_id, "compute.googleapis.com")Kịch bản 2: Di chuyển project + networking
# Di chuyển project tới folder khác
move_request = ResourceManager::MoveProjectRequest(
project_name=f"projects/{project_number}",
folder_name=f"folders/{new_folder_id}"
)
response = resource_manager_stub.MoveProject(move_request)
# ❌ VẤN ĐỀ: Giả định project đã được di chuyển ngay
print(f"Project moved to folder {new_folder_id}")
# Tại thời điểm này:
# - Metadata project đã hiển thị folder mới (strong consistency)
# - NHƯNG: VPC peering relationships, firewall rules, có thể chưa được cập nhật
# - Các API networking có thể vẫn thấy project ở vị trí cũ (cache cũ)
# ✅ TỐT HƠN: Xác minh qua nhiều bước
import time
def verify_project_moved(project_id, expected_folder_id, max_retries=30):
for attempt in range(max_retries):
project = resource_manager_client.get_project(project_id)
parent_id = project.parent.id
if parent_id == expected_folder_id:
print(f"✓ Metadata đã được cập nhật (lần thử {attempt})")
break
time.sleep(1)
# Kiểm tra bổ sung: xác minh qua propagation của IAM policy
# Nếu IAM policy đã thấy thay đổi, khả năng cao việc di chuyển đã hoàn tất
for attempt in range(max_retries):
try:
policy = iam_client.get_iam_policy(project_id)
# Nếu lấy được policy, nhiều khả năng đã propagated
break
except Exception:
time.sleep(1)
verify_project_moved(project_id, expected_folder_id)Quota & giới hạn tốc độ
Resource Manager API có global rate limits:
| Thao tác | Giới hạn |
|---|---|
| Projects tạo mỗi phút | 5 |
| Projects tạo mỗi ngày | 500 (mỗi organization) |
| Folder operations mỗi phút | 60 |
| IAM policy updates mỗi phút | 10 mỗi resource |
Hệ quả trong production: Nếu automation tạo 100 projects, không thể spawn song song toàn bộ — phải chia batch với độ trễ.
# ❌ Quá nhanh - sẽ chạm rate limit
for i in range(100):
create_project(f"project-{i}")
# ✅ Tốt hơn - chia batch với độ trễ
import concurrent.futures
from time import sleep
def create_projects_with_rate_limit(project_ids, batch_size=5, delay=15):
"""Tạo projects tuân thủ rate limit"""
for batch in [project_ids[i:i+batch_size] for i in range(0, len(project_ids), batch_size)]:
futures = []
with concurrent.futures.ThreadPoolExecutor(max_workers=batch_size) as executor:
for project_id in batch:
future = executor.submit(create_project, project_id)
futures.append(future)
# Chờ batch hoàn tất
for future in concurrent.futures.as_completed(futures):
try:
future.result()
except Exception as e:
print(f"Error creating project: {e}")
# Chờ giữa các batch
sleep(delay)
create_projects_with_rate_limit([f"proj-{i}" for i in range(100)])Truy vấn phân cấp
Cách 1: Resource Manager API (cũ)
# Liệt kê projects trong folder
gcloud resource-manager projects list \
--filter="parent.id:FOLDER_ID"Vấn đề:
- Chỉ liệt kê projects, không liệt kê folders
- Không có thông tin depth/nesting
- Không mở rộng tốt cho cấu trúc phân cấp sâu
Cách 2: Cloud Asset Inventory (khuyến nghị)
# Truy vấn resources theo phân cấp
gcloud asset search-all-resources \
--scope=organizations/ORG_ID \
--asset-types=cloudresourcemanager.googleapis.com/Project \
--format="table(name,displayName,parent)"
# Lọc theo parent
gcloud asset search-all-resources \
--scope=organizations/ORG_ID \
--asset-types=cloudresourcemanager.googleapis.com/Project \
--query="parent.display_name:'Engineering'" \
--format="csv(name,displayName,parent.displayName)"Ưu điểm:
- Có thể truy vấn theo depth
- Hỗ trợ filtering, regex, biểu thức tùy chỉnh
- Mở rộng tốt (dùng backend đã index)
- Có thể truy vấn toàn organization ở quy mô lớn
Chênh lệch giữa API và Console
Đôi khi GCP Console hiển thị resources, nhưng API query thì không — do cache của Console so với tính nhất quán của API.
# Console thấy project, nhưng:
gcloud projects describe my-project
# Error: Project 'my-project' not found
# Giải pháp: Project đã tồn tại, nhưng chưa lan truyền tới Resource Manager API
# Chờ và thử lạiXử lý lỗi & race condition
Tính idempotency & xóa project
Xóa project có hành vi đặc biệt:
T+0: gcloud projects delete my-project
→ Project được đánh dấu DELETE_REQUESTED
→ Vẫn có thể khôi phục
T+0 đến T+30 ngày: Project ở trạng thái "soft delete"
→ Vẫn tính vào quota
→ IAM policies vẫn tồn tại
→ Billing dừng
T+30 ngày: Project bị xóa vĩnh viễnHệ quả trong production: Nếu automation tạo project, xóa, rồi tạo lại ngay bằng cùng ID — sẽ thất bại vì project ID vẫn bị giữ trong cửa sổ soft-delete.
# ❌ Cách này sẽ thất bại
project = create_project("my-project")
delete_project("my-project")
project = create_project("my-project") # Thất bại! Project ID còn bị giữ
# ✅ Giải pháp 1: Chờ xóa vĩnh viễn (30 ngày)
# ✅ Giải pháp 2: Dùng project ID khác
# ✅ Giải pháp 3: Kiểm tra trạng thái xóa trước
def safe_create_project(project_id, timeout=30):
try:
response = create_project(project_id)
return response
except google.api_core.exceptions.AlreadyExists:
# Project có thể đang ở trạng thái soft-delete
project = get_project(project_id)
if project.lifecycle_state == "DELETE_REQUESTED":
print(f"Project {project_id} đang soft-delete. Không thể tạo lại trong 30 ngày.")
raise
else:
raiseNhất quán giữa các API
Khi có resources liên project (ví dụ: Shared VPC), thao tác Resource Manager có thể gây ra nhất quán tạm thời:
T+0: Di chuyển project X sang folder Y (host project)
→ Metadata project được cập nhật
→ Nhưng: firewall rules, routes vẫn còn cache ở data plane
T+5: User cố tạo VM ở project X → enforcement của firewall có thể không nhất quán
→ Việc tạo VM có thể thành công, nhưng lọc lưu lượng có thể sai
T+30: Tất cả services thấy trạng thái nhất quánGiảm thiểu:
- Sau khi di chuyển project, chờ 30-60 giây trước khi tạo resources phụ thuộc
- Kiểm tra chức năng liên project sau khi di chuyển
Giám sát sức khỏe API
# Kiểm tra quota sử dụng của Resource Manager API
gcloud compute project-info describe --project=PROJECT_ID \
--format='value(quotas[name=PROJECTS].usage)'
# Theo dõi lỗi rate limit trong logs
gcloud logging read \
'severity=ERROR AND resource.type="api" AND protoPayload.serviceName="cloudresourcemanager.googleapis.com"' \
--limit=50Terraform với Resource Manager
# Terraform xử lý eventual consistency tự động
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
provider "google" {
project = "my-terraform-project"
region = "us-central1"
}
resource "google_project" "prod" {
name = "Production Project"
project_id = "my-prod-project"
folder_id = google_folder.prod.id
billing_account = var.billing_account_id
}
resource "google_project_service" "compute" {
project = google_project.prod.project_id
service = "compute.googleapis.com"
# Terraform tự động chờ project lan truyền
depends_on = [google_project.prod]
}
# Terraform xử lý retry một cách minh bạchQuan trọng: Terraform provider tự retry nội bộ các vấn đề eventual consistency, nhưng bạn vẫn có thể gặp edge case:
# Các resource này có thể đua nhau nếu không cẩn thận
resource "google_project" "my_project" {
# ...
}
resource "google_compute_network" "default" {
project = google_project.my_project.project_id
name = "default"
# Phải chờ project được lan truyền đầy đủ
depends_on = [google_project.my_project]
}Best practices
Luôn retry với exponential backoff khi tạo resources:
python@retry.Retry(initial=1, maximum=60, multiplier=2) def create_with_retry(project_id): return create_project(project_id)Không bao giờ giả định thao tác là đồng bộ:
- Tạo project → bất đồng bộ
- Lan truyền IAM policy → bất đồng bộ
- Bật service → bất đồng bộ
Truy vấn qua kênh nhất quán hơn:
- Cloud Asset Inventory > Resource Manager API
- Asset Inventory có indexing và độ nhất quán tốt hơn
Triển khai giám sát đầy đủ:
- Ghi log mọi thao tác Resource Manager
- Cảnh báo khi chạm rate limit
- Theo dõi độ trễ lan truyền
Kiểm thử automation kỹ lưỡng:
- Test tạo project + dùng API ngay sau đó
- Test di chuyển project + thao tác trên resources phụ thuộc
- Test trên nhiều regions