1. Introducción
Descripción general
Cloud Run Functions es la oferta de funciones como servicio de Google Cloud potenciada por Cloud Run y Eventarc, lo que brinda un control más avanzado sobre el rendimiento y la escalabilidad, y mayor control sobre el entorno de ejecución de las funciones y los activadores de más de 90 fuentes de eventos.
En este codelab, se te guiará para crear Cloud Run Functions que respondan a llamadas HTTP y se activen con mensajes de Pub/Sub y Registros de auditoría de Cloud.
En este codelab, también se usan actualizaciones automáticas de imágenes base para las implementaciones de funciones. Para ello, se especifica una imagen base con la marca --base-image. Las actualizaciones automáticas de imágenes base para Cloud Run permiten que Google aplique parches de seguridad al sistema operativo y a los componentes del entorno de ejecución del lenguaje de la imagen base automáticamente. No es necesario volver a compilar o volver a implementar el servicio para que se actualice la imagen base. Para obtener más información, consulta las actualizaciones automáticas de imágenes base.
Si prefieres no usar las actualizaciones automáticas de imágenes base, puedes quitar la marca --base-image de los ejemplos que se muestran en este codelab.
Qué aprenderás
- Descripción general de Cloud Run Functions y cómo usar las actualizaciones automáticas de imágenes base.
- Cómo escribir una función que responda a llamadas HTTP
- Cómo escribir una función que responda a los mensajes de Pub/Sub
- Cómo escribir una función que responda a eventos de Cloud Storage
- Cómo dividir el tráfico entre dos revisiones
- Cómo eliminar los inicios en frío con instancias mínimas
2. Configuración y requisitos
Crea una carpeta raíz
Crea una carpeta raíz para todos los ejemplos.
mkdir crf-codelab cd crf-codelab
Configura variables de entorno
Configura las variables de entorno que se usarán en este codelab.
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
Habilita las APIs
Habilita todos los servicios necesarios con el siguiente comando:
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. Función de HTTP
Para la primera función, creemos una función de Node.js autenticada que responda a solicitudes HTTP. También usaremos un tiempo de espera de 10 minutos para mostrar cómo una función puede tener más tiempo para responder a solicitudes HTTP.
Crear
Crea una carpeta para la app y navega a ella:
mkdir hello-http cd hello-http
Crea un archivo index.js que responda a las solicitudes HTTP:
const functions = require('@google-cloud/functions-framework');
functions.http('helloWorld', (req, res) => {
res.status(200).send('HTTP with Node.js in Cloud Run functions!');
});
Crea un archivo package.json para especificar las dependencias:
{
"name": "nodejs-run-functions-codelab",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Implementar
Sigue estos pasos para implementar la función:
gcloud run deploy nodejs-run-function \
--source . \
--function helloWorld \
--base-image nodejs22 \
--region $REGION \
--timeout 600 \
--no-allow-unauthenticated
Este comando usa paquetes de compilación para transformar el código fuente de tu función en una imagen de contenedor lista para la producción.
Ten en cuenta lo siguiente:
- La marca
--sourcese usa para indicarle a Cloud Run que compile la función en un servicio basado en contenedores ejecutables. - La marca
--function(nueva) se usa para establecer el punto de entrada del servicio nuevo como la firma de la función que deseas invocar. - La marca
--base-image(nueva) especifica el entorno de la imagen base para tu función, comonodejs22,python312,go123,java21,dotnet8,ruby33ophp83. Para obtener más detalles sobre las imágenes base y los paquetes incluidos en cada imagen, consulta Imágenes base de los tiempos de ejecución. - (Opcional) La marca
--timeoutpermite que la función tenga un tiempo de espera más largo para responder a las solicitudes HTTP. En este ejemplo, se usan 600 segundos para demostrar un tiempo de respuesta de 10 minutos. - (Opcional) El
--no-allow-unauthenticatedpara evitar que se pueda invocar tu función públicamente
Prueba
Prueba la función con los siguientes comandos:
# get the Service URL SERVICE_URL="$(gcloud run services describe nodejs-run-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Deberías ver el mensaje HTTP with Node.js in Cloud Run functions! como respuesta.
4. Función de Pub/Sub
Para la segunda función, crearemos una función de Python que se active con un mensaje de Pub/Sub publicado en un tema específico.
Configura tokens de autenticación de Pub/Sub
Si habilitaste la cuenta de servicio de Pub/Sub el 8 de abril de 2021 o antes de esa fecha, otorga el rol iam.serviceAccountTokenCreator a la cuenta de servicio de Pub/Sub:
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)') gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \ --role roles/iam.serviceAccountTokenCreator
Crear
Crea un tema de Pub/Sub para usarlo en la muestra:
TOPIC=cloud-run-functions-pubsub-topic gcloud pubsub topics create $TOPIC
Crea una carpeta para la app y navega a ella:
mkdir ../hello-pubsub cd ../hello-pubsub
Crea un archivo main.py que registre un mensaje que contenga el ID de CloudEvent:
import functions_framework
@functions_framework.cloud_event
def hello_pubsub(cloud_event):
print('Pub/Sub with Python in Cloud Run functions! Id: ' + cloud_event['id'])
Crea un archivo requirements.txt con el siguiente contenido para especificar las dependencias:
functions-framework==3.*
Implementar
Sigue estos pasos para implementar la función:
gcloud run deploy python-pubsub-function \
--source . \
--function hello_pubsub \
--base-image python313 \
--region $REGION \
--no-allow-unauthenticated
Recupera el número de proyecto que se usará para la identidad de la cuenta de servicio.
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)')
Crea el activador
gcloud eventarc triggers create python-pubsub-function-trigger \
--location=$REGION \
--destination-run-service=python-pubsub-function \
--destination-run-region=$REGION \
--event-filters="type=google.cloud.pubsub.topic.v1.messagePublished" \
--transport-topic=projects/$PROJECT_ID/topics/$TOPIC \
--service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Prueba
Envía un mensaje al tema para probar la función:
gcloud pubsub topics publish $TOPIC --message="Hello World"
Debería ver el CloudEvent recibido en los registros:
gcloud run services logs read python-pubsub-function --region $REGION --limit=10
5. Función de Cloud Storage
Para la siguiente función, crearemos una función de Node.js que responda a eventos de un bucket de Cloud Storage.
Configurar
Para usar las funciones de Cloud Storage, otorga el rol de IAM pubsub.publisher a la cuenta de servicio de Cloud Storage:
SERVICE_ACCOUNT=$(gsutil kms serviceaccount -p $PROJECT_NUMBER) gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$SERVICE_ACCOUNT \ --role roles/pubsub.publisher
Crear
Crea una carpeta para la app y navega a ella:
mkdir ../hello-storage cd ../hello-storage
Crea un archivo index.js que simplemente responda a los eventos de Cloud Storage:
const functions = require('@google-cloud/functions-framework');
functions.cloudEvent('helloStorage', (cloudevent) => {
console.log('Cloud Storage event with Node.js in Cloud Run functions!');
console.log(cloudevent);
});
Crea un archivo package.json para especificar las dependencias:
{
"name": "nodejs-crf-cloud-storage",
"version": "0.0.1",
"main": "index.js",
"dependencies": {
"@google-cloud/functions-framework": "^2.0.0"
}
}
Implementar
Primero, crea un bucket de Cloud Storage (o usa uno existente que ya tengas):
export BUCKET_NAME="gcf-storage-$PROJECT_ID" export BUCKET="gs://gcf-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Sigue estos pasos para implementar la función:
gcloud run deploy nodejs-crf-cloud-storage \ --source . \ --base-image nodejs22 \ --function helloStorage \ --region $REGION \ --no-allow-unauthenticated
Una vez que se implementa la función, puedes verla en la sección Cloud Run de la consola de Cloud.
Ahora crea el activador de Eventarc.
BUCKET_REGION=$REGION gcloud eventarc triggers create nodejs-crf-cloud-storage-trigger \ --location=$BUCKET_REGION \ --destination-run-service=nodejs-crf-cloud-storage \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.storage.object.v1.finalized" \ --event-filters="bucket=$BUCKET_NAME" \ --service-account=$PROJECT_NUMBER-compute@developer.gserviceaccount.com
Prueba
Sube un archivo al bucket para probar la función:
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
Debería ver el CloudEvent recibido en los registros:
gcloud run services logs read nodejs-crf-cloud-storage --region $REGION --limit=10
6. Registros de auditoría de Cloud
Para la siguiente función, crearemos una función de Node.js que recibe un evento de Registros de auditoría de Cloud cuando se crea una instancia de VM de Compute Engine. En respuesta, agrega una etiqueta a la VM recién creada, en la que se especifica el creador de la VM.
Determinar las VMs de Compute Engine recién creadas
Compute Engine emite 2 registros de auditoría cuando se crea una VM.
El primero se emite al principio de la creación de la VM. El segundo se emite después de que se crea la VM.
En los registros de auditoría, los campos de operación son diferentes y contienen valores first: true y last: true. El segundo registro de auditoría contiene toda la información que necesitamos para etiquetar una instancia, por lo que usaremos la marca last: true para detectarla en las funciones de Cloud Run.
Configurar
Para usar las funciones de Registros de auditoría de Cloud, debes habilitar los registros de auditoría para Eventarc. También debes usar una cuenta de servicio con el rol eventarc.eventReceiver.
- Habilita los tipos de registros de Registros de auditoría de Cloud Lectura de administración, Lectura de datos y Escritura de datos para la API de Compute Engine.
- Otorga a la cuenta de servicio predeterminada de Compute Engine el rol de IAM
eventarc.eventReceiver:
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
Crea la función
En este codelab, se usa Node.js, pero puedes encontrar otros ejemplos en https://github.com/GoogleCloudPlatform/eventarc-samples.
Crea un archivo package.json
{
"dependencies": {
"googleapis": "^84.0.0"
}
}
Crea un archivo node.js
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const { google } = require("googleapis");
var compute = google.compute("v1");
exports.labelVmCreation = async (cloudevent) => {
const data = cloudevent.body;
// in case an event has >1 audit log
// make sure we respond to the last event
if (!data.operation || !data.operation.last) {
console.log("Operation is not last, skipping event");
return;
}
// projects/dogfood-gcf-saraford/zones/us-central1-a/instances/instance-1
var resourceName = data.protoPayload.resourceName;
var resourceParts = resourceName.split("/");
var project = resourceParts[1];
var zone = resourceParts[3];
var instanceName = resourceParts[5];
var username = data.protoPayload.authenticationInfo.principalEmail.split("@")[0];
console.log(`Setting label username: ${username} to instance ${instanceName} for zone ${zone}`);
var authClient = await google.auth.getClient({
scopes: ["https://www.googleapis.com/auth/cloud-platform"]
});
// per docs: When updating or adding labels in the API,
// you need to provide the latest labels fingerprint with your request,
// to prevent any conflicts with other requests.
var labelFingerprint = await getInstanceLabelFingerprint(authClient, project, zone, instanceName);
var responseStatus = await setVmLabel(
authClient,
labelFingerprint,
username,
project,
zone,
instanceName
);
// log results of setting VM label
console.log(JSON.stringify(responseStatus, null, 2));
};
async function getInstanceLabelFingerprint(authClient, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
auth: authClient
};
var response = await compute.instances.get(request);
var labelFingerprint = response.data.labelFingerprint;
return labelFingerprint;
}
async function setVmLabel(authClient, labelFingerprint, username, project, zone, instanceName) {
var request = {
project: project,
zone: zone,
instance: instanceName,
resource: {
labels: { "creator": username },
labelFingerprint: labelFingerprint
},
auth: authClient
};
var response = await compute.instances.setLabels(request);
return response.statusText;
}
Implementar
Sigue estos pasos para implementar la función:
gcloud run deploy gce-vm-labeler \ --source . \ --function labelVmCreation \ --region $REGION \ --no-allow-unauthenticated
Ahora, crea el activador. Observa cómo la función filtra los registros de auditoría para las inserciones de Compute Engine con la marca --trigger-event-filters.
gcloud eventarc triggers create gce-vm-labeler-trigger \ --location=$REGION \ --destination-run-service=gce-vm-labeler \ --destination-run-region=$REGION \ --event-filters="type=google.cloud.audit.log.v1.written,serviceName=compute.googleapis.com,methodName=v1.compute.instances.insert" \ --service-account=$ROJECT_NUMBER-compute@developer.gserviceaccount.com
Prueba
Establece las variables de entorno:
# if you're using europe-west1 as your region
ZONE=europe-west1-d
VM_NAME=codelab-crf-auditlog
Ejecuta el siguiente comando para crear una VM:
gcloud compute instances create $VM_NAME --zone=$ZONE --machine-type=e2-medium --image-family=debian-11 --image-project=debian-cloud
Una vez que se complete la creación de la VM, deberías ver la etiqueta creator agregada en la VM en la consola de Cloud en la sección Información básica o con el siguiente comando:
gcloud compute instances describe $VM_NAME --zone=$ZONE
Deberías ver la etiqueta en el resultado como en el siguiente ejemplo:
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
Limpia
Asegúrate de borrar la instancia de VM. No se volverá a usar en este lab.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. División del tráfico
Cloud Run Functions admite múltiples revisiones de tus funciones, lo que permite dividir el tráfico entre ellas o revertir funciones a una versión anterior.
En este paso, implementarás 2 revisiones de una función y, luego, dividirás el tráfico entre ellas en partes iguales.
Crear
Crea una carpeta para la app y navega a ella:
mkdir ../traffic-splitting cd ../traffic-splitting
Crea un archivo main.py con una función de Python que lea una variable de entorno de color y responda con Hello World en ese color de fondo:
import os
color = os.environ.get('COLOR')
def hello_world(request):
return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
Crea un archivo requirements.txt con el siguiente contenido para especificar las dependencias:
functions-framework==3.*
Implementar
Implementa la primera revisión de la función con un fondo naranja:
COLOR=orange gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
En este punto, si pruebas la función viendo el activador HTTP (el URI que se generó con el comando de implementación anterior) en tu navegador, deberías ver Hello World con un fondo naranja:

Implementa la segunda revisión con un fondo amarillo:
COLOR=yellow gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Como esta es la revisión más reciente, si pruebas la función, deberías ver Hello World con un fondo amarillo:

Divide el tráfico en partes iguales
Para dividir el tráfico entre las revisiones naranja y amarilla, debes encontrar los IDs de revisión de los servicios de Cloud Run. Este es el comando para ver los IDs de revisión:
gcloud run revisions list --service hello-world-colors \ --region $REGION --format 'value(REVISION)'
El resultado debería ser similar al siguiente ejemplo:
hello-world-colors-00001-man hello-world-colors-00002-wok
Ahora, divide el tráfico entre estas dos revisiones de la siguiente manera (actualiza X-XXX según los nombres de tus revisiones):
gcloud run services update-traffic hello-world-colors \ --region $REGION \ --to-revisions hello-world-colors-0000X-XXX=50,hello-world-colors-0000X-XXX=50
Prueba
Para probar la función, visita su URL pública. La mitad del tiempo, deberías ver la revisión naranja y, la otra mitad, la revisión amarilla:

Consulta Reversiones, lanzamientos graduales y migración de tráfico para obtener más información.
8. Cantidad mínima de instancias
En Cloud Run Functions, puedes especificar una cantidad mínima de instancias de función que se deben mantener en espera y listas para entregar solicitudes. Esto es útil para limitar la cantidad de inicios en frío.
En este paso, implementarás una función con una inicialización lenta. Observarás el problema de inicio en frío. Luego, implementarás la función con el valor de instancia mínimo establecido en 1 para deshacerte del inicio en frío.
Crear
Crea una carpeta para la app y navega a ella:
mkdir ../min-instances cd ../min-instances
Crea un archivo main.go. Este servicio de Go tiene una función init que duerme durante 10 segundos para simular una inicialización larga. También tiene una función HelloWorld que responde a las llamadas HTTP:
package p
import (
"fmt"
"net/http"
"time"
)
func init() {
time.Sleep(10 * time.Second)
}
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Slow HTTP Go in Cloud Run functions!")
}
Implementar
Implementa la primera revisión de la función con el valor de instancia mínimo predeterminado de cero:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated
Prueba la función con este comando:
# get the Service URL SERVICE_URL="$(gcloud run services describe go-slow-function --region $REGION --format 'value(status.url)')" # invoke the service curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Observarás un retraso de 10 segundos (arranque en frío) en la primera llamada y, luego, verás el mensaje. Las llamadas posteriores deberían devolverse de inmediato.
Establece la cantidad mínima de instancias
Para deshacerte del inicio en frío en la primera solicitud, vuelve a implementar la función con la marca --min-instances establecida en 1 de la siguiente manera:
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated \ --min-instances 1
Prueba
Vuelve a probar la función:
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Ya no deberías ver la demora de 10 segundos en la primera solicitud. El problema de inicio en frío para la primera invocación (después de mucho tiempo sin invocar) desapareció gracias a las instancias mínimas.
Consulta Usa una cantidad mínima de instancias para obtener más información.
9. ¡Felicitaciones!
¡Felicitaciones por completar el codelab!
Temas abordados
- Descripción general de Cloud Run Functions y cómo usar las actualizaciones automáticas de imágenes base.
- Cómo escribir una función que responda a llamadas HTTP
- Cómo escribir una función que responda a los mensajes de Pub/Sub
- Cómo escribir una función que responda a eventos de Cloud Storage
- Cómo dividir el tráfico entre dos revisiones
- Cómo eliminar los inicios en frío con instancias mínimas