Cost Sentry

+

Arquitectura

Cost Sentry es un conjunto de secuencias de comandos y configuraciones que te permiten cerrar recursos cuando se superan los presupuestos de facturación de Google Cloud.

Esta secuencia de comandos consta de los siguientes componentes :

  • Eventos - Cola - Pub/Sub
  • Facturación - Controles de costes - Presupuestos
  • Eventos - Gestión de eventos - Cloud Functions
  • Compute - VMs - Compute Engine
  • Computación - Sin servidor - Cloud Run

Esta secuencia de comandos configurará un presupuesto, una cola de mensajes y una función de Cloud Functions para gestionar todo esto. A continuación, se inicia una VM de ejemplo y un servicio respaldado por un contenedor que gestiona el sistema.


Empezar

Haz clic en el siguiente enlace para acceder a una copia del código fuente en Cloud Shell. Una vez allí, con un solo comando se creará una copia de trabajo de la aplicación en tu proyecto.

Abrir en Cloud Shell

Ver el código fuente en GitHub


Componentes de Cost Sentry

La arquitectura de Cost Sentry utiliza varios productos. A continuación, se enumeran los componentes y se incluye más información sobre ellos, como enlaces a vídeos relacionados, documentación del producto y tutoriales interactivos.
Vídeo Documentos Guías
Google Cloud Pub/Sub Google Cloud Pub/Sub es un bus de mensajería que permite integrar aplicaciones de diferentes servicios en distintos componentes de la nube para crear un sistema integrado.
Presupuestos de facturación Los presupuestos de facturación te permiten recibir notificaciones y tomar medidas cuando tu facturación supere los umbrales que hayas definido.
Cloud Functions Cloud Functions es una plataforma de funciones como servicio que te permite detectar las subidas de archivos de Cloud Storage y ejecutar código para crear miniaturas de ellos.
Compute Engine Compute Engine es la tecnología virtual de Google Cloud. Con ella, puedes poner en marcha muchas configuraciones diferentes de máquinas virtuales para adaptarlas a tus necesidades de computación.
Cloud Run Cloud Run te permite ejecutar aplicaciones en un contenedor, pero de forma sin servidor, sin tener que configurar el número de instancias, procesadores o memoria. Sube un contenedor y obtén una URL.

Secuencias de comandos

La secuencia de comandos de instalación usa un ejecutable escrito en go y las herramientas de la CLI de Terraform para tomar un proyecto vacío e instalar la aplicación en él. El resultado debe ser una aplicación que funcione y una URL para la dirección IP de balanceo de carga.

./main.tf

Habilitar servicios

Los servicios de Google Cloud están inhabilitados en un proyecto de forma predeterminada. Para usar Cost Sentry, activa los siguientes servicios:

  • Presupuestos de facturación: monitoriza la facturación y gestiona las alertas de facturación.
  • Cloud Build: crea imágenes de contenedor y despliégalas en Cloud Run.
  • Compute Engine: implementa máquinas virtuales y servicios de redes, como el balanceo de carga.
  • Cloud Functions: responde a eventos de plataformas de servicios.
  • Cloud Run: aloja contenedores en un entorno sin servidor y proporciona URLs para acceder a la aplicación.
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
}

Crear canal Pub/Sub

Crea un canal de Pub/Sub para monitorizar eventos de presupuesto de facturación y responder con Cloud Functions

resource "google_pubsub_topic" "costsentry" {
    name = "${var.basename}-billing-channel"
    project    = var.project_number
}

Crear un servicio de Cloud Run para aplicar

Crea un servicio de Cloud Run de ejemplo en el que ejecutar la aplicación de la facturación.

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]
}

Crear instancia de VM

Crea una instancia de Compute Engine de ejemplo en la que ejecutar la medida.

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]
}

Crear un presupuesto

Crea un presupuesto para monitorizar el gasto de tus proyectos.

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
}

Crear una cuenta de servicio y definir permisos

Crea una cuenta de servicio para las llamadas de 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
}

Definir permisos

El siguiente comando define los roles y permisos de gestión de identidades y accesos que permiten a Cloud Build implementar los servicios necesarios.

La serie de comandos implementa lo siguiente: Concede permiso a la cuenta de servicio de Cloud Functions para gestionar Cloud Run. Concede permiso a la cuenta de servicio de Cloud Functions para detener instancias de Compute Engine. Concede permiso a la cuenta de servicio de Cloud Build para que actúe en nombre de la cuenta de servicio de 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]
}

Desplegar una función de Cloud

El siguiente comando despliega una función de Cloud Functions que desactiva los recursos cuando se activa una alerta.

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
    ]
}

Conclusión

Una vez que se haya ejecutado, deberías tener una solución de control de costes en tu proyecto. Además, debe tener todo el código para modificar o ampliar esta solución de forma que se adapte a su entorno.