Aplicación de función de eventos de almacenamiento

+

Arquitectura

Storage Event Function App es un directorio de imágenes y un creador de miniaturas. Se compone de los siguientes elementos:

  • Una aplicación cliente en la que los usuarios pueden subir imágenes.
    • API alojada en contenedor y sitio estático - Golang - Cloud Run
    • Almacenamiento - Almacenamiento de archivos - Cloud Storage
  • Un procesador de imágenes que crea miniaturas de las imágenes.
    • Funciones como servicio (FaaS) - Go - Cloud Functions
  • Un flujo de procesamiento de despliegue.
    • Despliegue - Cloud Build

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 la aplicación de funciones de eventos de almacenamiento

La arquitectura de la aplicación de funciones de eventos de almacenamiento 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
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.
Cloud Storage Cloud Storage ofrece almacenamiento de archivos y servicio público de imágenes a través de http(s).
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.
Cloud Build Cloud Build es la herramienta que empaqueta los contenedores y los despliega para que estén disponibles como servicios de Cloud Run.

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

Activación de servicios

Los servicios de Google Cloud están inhabilitados en un proyecto de forma predeterminada. Para usar cualquiera de las soluciones que se indican a continuación, debemos activar lo siguiente:

  • Cloud Build: crea imágenes de contenedor y las despliega en Cloud Run
  • Cloud Storage: aloja archivos estáticos.
  • Cloud Functions: plataforma de funciones como servicio
  • Cloud Run: la herramienta sin servidor que alojará el contenedor y proporcionará URLs desde las que acceder a la aplicación.
  • Artifact Registry: almacena las imágenes de Docker para usarlas con Cloud Build.
variable "gcp_service_list" {
    description = "The list of apis necessary for the project"
    type        = list(string)
    default = [
        "cloudbuild.googleapis.com",
        "storage.googleapis.com",
        "cloudfunctions.googleapis.com",
        "run.googleapis.com",
        "artifactregistry.googleapis.com",
    ]
}

resource "google_project_service" "all" {
    for_each                   = toset(var.gcp_service_list)
    project                    = var.project_number
    service                    = each.key
    disable_dependent_services = false
    disable_on_destroy         = false
}

Definir permisos

Define los roles y permisos de gestión de identidades y accesos que permiten a Cloud Build desplegar todos los servicios.

  • Habilitar la cuenta de servicio de Cloud Build para desplegar en Cloud Run
  • Habilitar la cuenta de servicio de Cloud Build para realizar actividades de cuentas de servicio
  • Habilitar la cuenta de servicio de Cloud Build para publicar en Cloud Run
  • Habilitar la cuenta de servicio de Cloud Build para almacenar contenedores en Artifact Registry
variable "build_roles_list" {
    description = "The list of roles that build needs for"
    type        = list(string)
    default = [
        "roles/run.developer",
        "roles/iam.serviceAccountUser",
        "roles/run.admin",
        "roles/cloudfunctions.admin",
        "roles/artifactregistry.admin",
    ]
}

resource "google_project_iam_member" "allbuild" {
    for_each   = toset(var.build_roles_list)
    project    = var.project_number
    role       = each.key
    member     = "serviceAccount:${local.sabuild}"
    depends_on = [google_project_service.all]
}

Crear segmentos de Storage

Crea la ubicación de almacenamiento de las imágenes y miniaturas subidas, y proporciona una ubicación de almacenamiento temporal para la subida de Cloud Functions.

resource "google_storage_bucket" "target_bucket" {
    name     = var.bucket
    project  = var.project_number
    location = var.location
}

resource "google_storage_bucket" "function_bucket" {
    name     = "${var.project_id}-function-deployer"
    project  = var.project_number
    location = var.location
}

Crear un repositorio de Artifact Registry

En el siguiente código se describen los parámetros del repositorio de Artifact Registry en el que se almacenan los contenedores.

resource "google_artifact_registry_repository" "app" {
    provider      = google-beta
    format        = "DOCKER"
    location      = var.region
    project       = var.project_id
    repository_id = "${var.basename}-app"
    depends_on    = [google_project_service.all]
}

Compilar un contenedor para una aplicación de Cloud Run

Con el siguiente comando se compila una imagen y se sube a Artifact Registry para usarla con Cloud Build.

resource "null_resource" "cloudbuild_app" {
    provisioner "local-exec" {
        working_dir = "${path.module}/code/app"
        command     = "gcloud builds submit . --substitutions=_REGION=${var.region},_BASENAME=${var.basename}"
    }

    depends_on = [
        google_artifact_registry_repository.app,
        google_project_service.all
    ]
}

Desplegar en Cloud Run

En el siguiente ejemplo se usa Cloud Build para desplegar la aplicación web cliente en Cloud Run.

resource "google_cloud_run_service" "app" {
    name     = "${var.basename}-app"
    location = var.region
    project  = var.project_id

    template {
        spec {
            containers {
                image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.basename}-app/prod"
                env {
                name  = "BUCKET"
                value = var.bucket
                }
            }
        }

        metadata {
            annotations = {
                "autoscaling.knative.dev/maxScale" = "1000"
                "run.googleapis.com/client-name"   = "terraform"
            }
        }
    }
    autogenerate_revision_name = true
    depends_on = [
        null_resource.cloudbuild_app,
    ]
}

data "google_iam_policy" "noauth" {
    binding {
        role = "roles/run.invoker"
        members = [
        "allUsers",
        ]
    }
}

resource "google_cloud_run_service_iam_policy" "noauth_app" {
    location    = google_cloud_run_service.app.location
    project     = google_cloud_run_service.app.project
    service     = google_cloud_run_service.app.name
    policy_data = data.google_iam_policy.noauth.policy_data
}

Desplegar código de función en Cloud Functions

Enviar directamente a las funciones y activarlas.

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"

    available_memory_mb   = 128
    source_archive_bucket = google_storage_bucket.function_bucket.name
    source_archive_object = google_storage_bucket_object.archive.name
    entry_point           = "OnFileUpload"
    event_trigger {
        event_type = "google.storage.object.finalize"
        resource   = google_storage_bucket.target_bucket.name
    }

    depends_on = [
        google_storage_bucket.function_bucket,
        google_storage_bucket.target_bucket,
        google_storage_bucket_object.archive,
        google_project_service.all
    ]
}

./code/app/cloudbuild.yaml

Crear un contenedor de APIs

A continuación, se crea una imagen Docker para la aplicación web.

- name: "gcr.io/cloud-builders/docker"
  args: [ "build", "-t", "$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/prod", ".", ]

Enviar el contenedor de la API a Artifact Registry

Al enviar el contenedor a Artifact Registry, Cloud Run puede obtener la imagen y servirla.

- name: "gcr.io/cloud-builders/docker"
  args: ["push", "$_REGION-docker.pkg.dev/$PROJECT_ID/$_BASENAME-app/prod"]

Sustituciones

Crea una variable con un valor predeterminado para que estos valores se puedan cambiar en el momento de la implementación.

substitutions:
  _REGION: us-central1
  _BASENAME: scaler

Conclusión

Ahora tienes una solución para crear miniaturas que se ejecuta en tu proyecto y usa Cloud Functions para responder a los cambios en un segmento de Storage. También tienes todo el código para modificar o ampliar esta solución.