Costo Sentry è un insieme di script e configurazioni che consentono di arrestare le risorse quando vengono superati i budget di fatturazione di Google Cloud.
Questo script è costituito dai seguenti componenti :
- Eventi - Coda - Pub/Sub
- Fatturazione - Controlli dei costi - Budget
- Eventi - Gestione eventi - Cloud Functions
- Computing - VM - Compute Engine
- Computing - Serverless - Cloud Run
Questo script imposterà un budget, una coda di messaggi e una Cloud Function per gestire tutto questo. Quindi avvia una VM di esempio e un servizio supportato da container gestito dal sistema.
Inizia
Fai clic sul link seguente a una copia del codice sorgente in Cloud Shell. Da lì, un singolo comando avvierà una copia funzionante dell'applicazione nel tuo progetto.
Visualizza il codice sorgente su GitHub
Componenti di Sentry costi
L'architettura di Cost Sentry utilizza diversi prodotti. Di seguito sono elencati i componenti, insieme a ulteriori informazioni sui componenti, tra cui link a video correlati, documentazione del prodotto e procedure dettagliate interattive.Script
Lo script di installazione utilizza un eseguibile scritto in go
e negli strumenti dell'interfaccia a riga di comando di Terraform per acquisire un progetto vuoto e installare l'applicazione al suo interno. L'output deve essere un'applicazione funzionante e un URL per l'indirizzo IP di bilanciamento del carico.
./main.tf
Attiva i servizi
I servizi Google Cloud sono disabilitati in un progetto per impostazione predefinita. Per utilizzare Cost Sentry, attiva i seguenti servizi:
- Budget di fatturazione: monitora la fatturazione e gestisci gli avvisi di fatturazione.
- Cloud Build: crea immagini container ed esegui il deployment in Cloud Run.
- Compute Engine: implementa macchine virtuali e servizi di networking, come il bilanciamento del carico.
- Cloud Functions: risposta agli eventi della piattaforma di servizio.
- Cloud Run: ospita i container in un ambiente serverless e fornisce gli URL per accedere all'applicazione.
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
}
Crea canale Pub/Sub
Crea un canale Pub/Sub per rimanere in ascolto degli eventi relativi al budget di fatturazione e rispondere con Cloud Functions
resource "google_pubsub_topic" "costsentry" {
name = "${var.basename}-billing-channel"
project = var.project_number
}
Crea il servizio Cloud Run per l'applicazione forzata
Crea un servizio Cloud Run di esempio su cui eseguire l'applicazione forzata della fatturazione.
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]
}
Crea istanza VM
Crea un'istanza Compute Engine di esempio su cui eseguire l'applicazione forzata.
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]
}
Crea un budget
Crea un budget per monitorare la spesa relativa ai progetti.
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
}
Crea un account di servizio e imposta le autorizzazioni
Crea un account di servizio per le chiamate alla Cloud Function.
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
}
Imposta autorizzazioni
Il seguente comando imposta i ruoli e le autorizzazioni IAM che consentono a Cloud Build di eseguire il deployment dei servizi richiesti.
La serie di comandi implementa quanto segue: Concede all'account di servizio Cloud Functions l'autorizzazione per gestire Cloud Run. Concede all'account di servizio della funzione Cloud l'autorizzazione per arrestare le istanze di Compute Engine. Concede all'account di servizio Cloud Build l'autorizzazione ad agire per conto dell'account di servizio 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]
}
Esegui il deployment di una funzione Cloud Functions
Il seguente comando esegue il deployment di una Cloud Function che disattiva le risorse quando viene attivato un avviso.
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
]
}
Conclusione
Una volta eseguita, dovresti avere una soluzione di controllo dei costi in esecuzione nel tuo progetto. Inoltre, dovresti disporre di tutto il codice per modificare o estendere questa soluzione in modo che si adatti al tuo ambiente.