Cost Sentry est un ensemble de scripts et de configurations qui vous permettent d'arrêter des ressources lorsque les budgets de facturation Google Cloud sont dépassés.
Ce script se compose des composants suivants :
- Événements - File d'attente - Pub/Sub
- Facturation - Contrôle des coûts - Budgets
- Événements – Gestion des événements – Cloud Functions
- Calcul - VM - Compute Engine
- Calcul : sans serveur : Cloud Run
Ce script configurera un budget, une file d'attente de messages et une fonction Cloud pour gérer tout cela. Il lance ensuite un exemple de VM et un service basé sur des conteneurs géré par le système.
Premiers pas
Cliquez sur le lien suivant pour obtenir une copie du code source dans Cloud Shell. Une seule commande permet de démarrer une copie fonctionnelle de l'application dans votre projet.
Afficher le code source sur GitHub
Composants de Cost Sentry
L'architecture de Cost Sentry utilise plusieurs produits. Vous trouverez ci-dessous la liste des composants, ainsi que des informations supplémentaires à leur sujet, y compris des liens vers des vidéos, des documentations produit et des tutoriels interactifs associés.Scripts
Le script d'installation utilise un exécutable écrit en go
et des outils de la CLI Terraform pour prendre un projet vide et y installer l'application. La sortie doit être une application fonctionnelle et une URL pour l'adresse IP d'équilibrage de charge.
./main.tf
Activer les services
Les services Google Cloud sont désactivés par défaut dans un projet. Pour utiliser Cost Sentry, activez les services suivants:
- Budgets de facturation : suivez la facturation et gérez les alertes de facturation.
- Cloud Build : créez des images de conteneur et déployez-les dans Cloud Run.
- Compute Engine : implémentez des machines virtuelles et des services réseau, comme l'équilibrage de charge.
- Cloud Functions : répond aux événements de la plate-forme de services.
- Cloud Run : hébergez des conteneurs dans un environnement sans serveur et fournissez des URL pour accéder à l'application.
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
}
Créer un canal Pub/Sub
Crée un canal Pub/Sub pour écouter les événements de budget de facturation et y répondre avec des fonctions Cloud
resource "google_pubsub_topic" "costsentry" {
name = "${var.basename}-billing-channel"
project = var.project_number
}
Créer un service Cloud Run pour l'appliquer
Créez un exemple de service Cloud Run sur lequel exécuter l'application de la facturation.
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]
}
Créer une instance de VM
Créez un exemple d'instance Compute Engine sur laquelle exécuter l'application des règles.
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]
}
Créer un budget
Crée un budget pour surveiller les dépenses liées à vos projets.
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
}
Créer un compte de service et définir des autorisations
Crée un compte de service pour les appels de fonction Cloud.
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
}
Définir des autorisations
La commande suivante définit les rôles et les autorisations IAM qui permettent à Cloud Build de déployer les services requis.
La série de commandes implémente les éléments suivants : Accorde au compte de service Cloud Functions l'autorisation de gérer Cloud Run. Accorde au compte de service Cloud Functions l'autorisation d'arrêter les instances Compute Engine. Accorde au compte de service Cloud Build l'autorisation d'agir au nom du compte de service 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]
}
Déployer une fonction Cloud
La commande suivante déploie une fonction Cloud qui désactive les ressources lorsqu'une alerte est déclenchée.
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
]
}
Conclusion
Une fois l'exécution terminée, une solution de contrôle des coûts devrait s'exécuter dans votre projet. De plus, vous devez disposer de tout le code nécessaire pour modifier ou étendre cette solution en fonction de votre environnement.