Cost Sentry 是一組指令碼和設定,可讓您在超過 Google Cloud 帳單預算時關閉資源。
這個指令碼由下列元件組成:
- 事件 - 佇列 - Pub/Sub
- 帳單 - 費用控管 - 預算
- 事件 - 事件處理 - Cloud Functions
- 運算 - VM - Compute Engine
- 運算 - 無伺服器 - Cloud Run
這個指令碼會設定預算、訊息佇列和 Cloud 函式,用來管理所有這些項目。然後啟動範例 VM 和由系統管理的容器支援服務。
開始使用
按一下以下連結,前往 Cloud Shell 中的原始碼副本。完成後,您只需執行單一指令,即可在專案中啟動應用程式的可用副本。
Cost Sentry 元件
Cost Sentry 架構會使用多項產品。以下列出這些元件,並提供相關資訊,包括相關影片、產品說明文件和互動式操作說明的連結。指令碼
安裝指令碼會使用以 go
和 Terraform CLI 工具編寫的可執行檔,取得空白專案並在其中安裝應用程式。輸出內容應為可運作的應用程式,以及負載平衡 IP 位址的網址。
./main.tf
啟用服務
根據預設,Google Cloud 服務會在專案中停用。如要使用「費用監控」功能,請啟用下列服務:
- 帳單預算:追蹤帳單並管理帳單快訊。
- Cloud Build:建立容器映像檔並部署至 Cloud Run。
- Compute Engine:實作虛擬機器和網路服務,例如負載平衡。
- Cloud Functions - 回應服務平台事件。
- Cloud Run:在無伺服器環境中代管容器,並提供可存取應用程式的網址。
variable "gcp_service_list" {
description = "The list of apis necessary for the project"
type = list(string)
default = [
"cloudresourcemanager.googleapis.com",
"cloudbilling.googleapis.com",
"billingbudgets.googleapis.com",
"cloudbuild.googleapis.com",
"compute.googleapis.com",
"cloudfunctions.googleapis.com",
"storage.googleapis.com",
"run.googleapis.com"
]
}
resource "google_project_service" "all" {
for_each = toset(var.gcp_service_list)
project = var.project_number
service = each.key
disable_on_destroy = false
}
建立 Pub/Sub 管道
建立 Pub/Sub 管道,以便監聽帳單預算事件,並透過 Cloud Functions 回應
resource "google_pubsub_topic" "costsentry" {
name = "${var.basename}-billing-channel"
project = var.project_number
}
建立 Cloud Run 服務以強制執行
建立範例 Cloud Run 服務,用於執行計費強制執行機制。
resource "google_cloud_run_service" "app" {
name = "${var.basename}-run-service"
location = var.region
project = var.project_id
metadata {
labels = {"${var.label}"=true}
}
template {
spec {
containers {
image = "us-docker.pkg.dev/cloudrun/container/hello"
}
}
metadata {
annotations = {
"autoscaling.knative.dev/maxScale" = "1000"
"run.googleapis.com/client-name" = "terraform"
}
}
}
autogenerate_revision_name = true
depends_on = [google_project_service.all]
}
建立 VM 執行個體
建立可執行強制執行的 Compute Engine 執行個體範例。
resource "google_compute_instance" "example" {
name = "${var.basename}-example"
machine_type = "n1-standard-1"
zone = var.zone
project = var.project_id
tags = ["http-server"]
labels = {"${var.label}"=true}
boot_disk {
auto_delete = true
device_name = "${var.basename}-example"
initialize_params {
image = "family/debian-10"
size = 200
type = "pd-standard"
}
}
network_interface {
network = "default"
access_config {
// Ephemeral public IP
}
}
depends_on = [google_project_service.all]
}
設定預算
建立預算來監控專案支出。
provisioner "local-exec" {
command = <<-EOT
gcloud beta billing budgets create --display-name ${var.basename}-budget \
--billing-account ${var.billing_account} --budget-amount ${var.budgetamount} \
--all-updates-rule-pubsub-topic=projects/${var.project_id}/topics/${var.basename}-billing-channel
EOT
}
建立服務帳戶並設定權限
為 Cloud Functions 呼叫建立服務帳戶。
resource "google_service_account" "functions_accounts" {
account_id = local.safunctionuser
description = "Service Account for the costsentry to run as"
display_name = local.safunction
project = var.project_number
}
設定權限
下列指令會設定 IAM 角色和權限,讓 Cloud Build 部署必要的服務。
這一系列指令會實作以下功能: 授予 Cloud Function 服務帳戶管理 Cloud Run 的權限。授予 Cloud Functions 服務帳戶權限,以便停止 Compute Engine 執行個體。授予 Cloud Build 服務帳戶權限,代表 Compute 服務帳戶執行操作。
variable "build_roles_list" {
description = "The list of roles that fucntions needs for"
type = list(string)
default = [
"roles/run.admin",
"roles/compute.instanceAdmin",
"roles/iam.serviceAccountUser"
]
}
resource "google_project_iam_member" "allbuild" {
for_each = toset(var.build_roles_list)
project = var.project_number
role = each.key
member = "serviceAccount:${google_service_account.functions_accounts.email}"
depends_on = [google_project_service.all,google_service_account.functions_accounts]
}
部署 Cloud 函式
下列指令會部署 Cloud 函式,在快訊觸發時停用資源。
resource "google_storage_bucket" "function_bucket" {
name = "${var.project_id}-function-deployer"
project = var.project_number
location = var.location
}
resource "null_resource" "cloudbuild_function" {
provisioner "local-exec" {
command = <<-EOT
cp code/function/function.go .
cp code/function/go.mod .
zip index.zip function.go
zip index.zip go.mod
rm go.mod
rm function.go
EOT
}
depends_on = [
google_project_service.all
]
}
resource "google_storage_bucket_object" "archive" {
name = "index.zip"
bucket = google_storage_bucket.function_bucket.name
source = "index.zip"
depends_on = [
google_project_service.all,
google_storage_bucket.function_bucket,
null_resource.cloudbuild_function
]
}
resource "google_cloudfunctions_function" "function" {
name = var.basename
project = var.project_id
region = var.region
runtime = "go116"
service_account_email = google_service_account.functions_accounts.email
available_memory_mb = 128
source_archive_bucket = google_storage_bucket.function_bucket.name
source_archive_object = google_storage_bucket_object.archive.name
entry_point = "LimitUsage"
event_trigger {
event_type = "google.pubsub.topic.publish"
resource = google_pubsub_topic.costsentry.name
}
environment_variables = {
GOOGLE_CLOUD_PROJECT = var.project_id
LABEL= var.label
}
depends_on = [
google_storage_bucket.function_bucket,
google_storage_bucket_object.archive,
google_project_service.all
]
}
結論
執行後,專案中應會開始執行成本控管解決方案。此外,您應該擁有所有程式碼,以便修改或擴充這個解決方案,以符合您的環境。