Cost Sentry besteht aus einer Reihe von Skripts und Konfigurationen, mit denen Sie Ressourcen herunterfahren können, wenn die Google Cloud Billing-Budgets überschritten sind.
Dieses Skript besteht aus den folgenden Komponenten :
- Ereignisse – Warteschlange – Pub/Sub
- Abrechnung – Kostenkontrolle – Budgets
- Ereignisse – Ereignisverarbeitung – Cloud Functions
- Computing – VMs – Compute Engine
- Computing – Serverlos – Cloud Run
Dieses Skript richtet ein Budget, eine Nachrichtenwarteschlange und eine Cloud Functions-Funktion ein, um all dies zu verwalten. Anschließend werden eine Beispiel-VM und ein containergestützter Dienst gestartet, der vom System verwaltet wird.
Jetzt starten
Klicken Sie auf den folgenden Link, um den Quellcode in Cloud Shell zu kopieren. Dort wird mit einem einzigen Befehl eine funktionierende Kopie der Anwendung in Ihrem Projekt erstellt.
Kosten-Sentry-Komponenten
Die Cost Sentry-Architektur nutzt mehrere Produkte. Im Folgenden finden Sie eine Liste der Komponenten sowie weitere Informationen zu den Komponenten, einschließlich Links zu ähnlichen Videos, Produktdokumentationen und interaktiven Schritt-für-Schritt-Anleitungen.Skripts
Das Installationsskript verwendet eine ausführbare Datei, die in go
und Terraform-Befehlszeilentools geschrieben ist, um ein leeres Projekt zu erstellen und die Anwendung darin zu installieren. Die Ausgabe sollte eine funktionierende Anwendung und eine URL für die Load-Balancing-IP-Adresse sein.
./main.tf
Dienste aktivieren
Google Cloud-Dienste sind in einem Projekt standardmäßig deaktiviert. Aktivieren Sie die folgenden Dienste, um Cost Sentry verwenden zu können:
- Abrechnungsbudgets: Hier können Sie die Abrechnung verfolgen und Abrechnungsbenachrichtigungen verwalten.
- Cloud Build – Container-Images erstellen und in Cloud Run bereitstellen
- Compute Engine – für die Implementierung virtueller Maschinen und Netzwerkdienste wie Load-Balancing
- Cloud Functions – Reagieren auf Dienstplattformereignisse
- Cloud Run – Container in einer serverlosen Umgebung hosten und URLs für den Zugriff auf die Anwendung bereitstellen.
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-Kanal erstellen
Erstellt einen Pub/Sub-Kanal, um auf Abrechnungsbudgetereignisse zu warten und mit Cloud Functions zu antworten
resource "google_pubsub_topic" "costsentry" {
name = "${var.basename}-billing-channel"
project = var.project_number
}
Zu erzwingenden Cloud Run-Dienst erstellen
Erstellen Sie einen Cloud Run-Beispieldienst, für den die Abrechnung erzwungen werden soll.
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-Instanz erstellen
Erstellen Sie eine Compute Engine-Beispielinstanz, auf der die Erzwingung ausgeführt werden soll.
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]
}
Budget erstellen
Erstellt ein Budget, um die Ausgaben in Ihren Projekten zu überwachen.
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
}
Dienstkonto erstellen und Berechtigungen festlegen
Erstellt ein Dienstkonto für die Aufrufe der Cloud Functions-Funktion.
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
}
Berechtigungen festlegen
Mit dem folgenden Befehl werden IAM-Rollen und -Berechtigungen festgelegt, mit denen Cloud Build die erforderlichen Dienste bereitstellen kann.
Mit der Reihe von Befehlen wird Folgendes implementiert: Gewährt dem Cloud Functions-Dienstkonto die Berechtigung zum Verwalten von Cloud Run. Gewährt dem Cloud Functions-Dienstkonto die Berechtigung zum Beenden von Compute Engine-Instanzen. Gewährt dem Cloud Build-Dienstkonto die Berechtigung, im Namen des Compute-Dienstkontos zu handeln.
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 Functions-Funktion bereitstellen
Mit dem folgenden Befehl wird eine Cloud Functions-Funktion bereitgestellt, die Ressourcen deaktiviert, wenn eine Benachrichtigung ausgelöst wird.
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
]
}
Fazit
Nach der Ausführung sollte in Ihrem Projekt eine Lösung zur Kostenkontrolle ausgeführt werden. Außerdem sollten Sie über den gesamten Code zum Ändern oder Erweitern dieser Lösung an Ihre Umgebung verfügen.