1. Introduction
Présentation
Cloud Run Functions est l'offre Functions as a Service de Google Cloud, optimisée par Cloud Run et Eventarc. Elle vous offre un contrôle plus avancé des performances et de l'évolutivité, ainsi qu'un contrôle accru sur l'environnement d'exécution des fonctions et les déclencheurs associés à plus de 90 sources d'événements.
Cet atelier de programmation vous guidera dans la création de fonctions Cloud Run qui répondent aux appels HTTP et qui sont déclenchées par les messages Pub/Sub et les journaux d'audit Cloud.
Cet atelier de programmation utilise également les mises à jour automatiques des images de base pour les déploiements de fonctions en spécifiant une image de base à l'aide de l'indicateur --base-image
. Les mises à jour automatiques des images de base pour Cloud Run permettent à Google d'appliquer automatiquement des correctifs de sécurité au système d'exploitation et aux composants d'exécution du langage de l'image de base. Vous n'avez pas besoin de recompiler ni de redéployer votre service pour que l'image de base soit mise à jour. Pour en savoir plus, consultez la section Mises à jour automatiques des images de base.
Si vous préférez ne pas utiliser les mises à jour automatiques des images de base, vous pouvez supprimer l'option --base-image
des exemples présentés dans cet atelier de programmation.
Points abordés
- Présentation de Cloud Run Functions et de l'utilisation des mises à jour automatiques des images de base.
- Écrire une fonction qui répond aux appels HTTP
- Comment écrire une fonction qui répond aux messages Pub/Sub
- Écrire une fonction qui répond aux événements Cloud Storage
- Découvrez comment répartir le trafic entre deux révisions.
- Découvrez comment éliminer les démarrages à froid grâce au nombre minimal d'instances.
2. Préparation
Créer un dossier racine
Créez un dossier racine pour tous les exemples.
mkdir crf-codelab cd crf-codelab
Configurer des variables d'environnement
Définissez les variables d'environnement qui seront utilisées tout au long de cet atelier de programmation.
gcloud config set project <YOUR-PROJECT-ID> REGION=<YOUR_REGION> PROJECT_ID=$(gcloud config get-value project)
Activer les API
Activez tous les services nécessaires :
gcloud services enable \ artifactregistry.googleapis.com \ cloudbuild.googleapis.com \ eventarc.googleapis.com \ run.googleapis.com \ logging.googleapis.com \ pubsub.googleapis.com
3. Fonction HTTP
Pour la première fonction, créons une fonction Node.js authentifiée qui répond aux requêtes HTTP. Utilisons également un délai avant expiration de 10 minutes pour montrer comment une fonction peut disposer de plus de temps pour répondre aux requêtes HTTP.
Créer
Créez un dossier pour l'application et accédez-y :
mkdir hello-http cd hello-http
Créez un fichier index.js
qui répond aux requêtes 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!'); });
Créez un fichier package.json
pour spécifier les dépendances :
{ "name": "nodejs-run-functions-codelab", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Déployer
Déployez la fonction :
gcloud run deploy nodejs-run-function \ --source . \ --function helloWorld \ --base-image nodejs22 \ --region $REGION \ --timeout 600 \ --no-allow-unauthenticated
Cette commande utilise des buildpacks pour transformer le code source de votre fonction en image de conteneur prête pour la production.
Remarques :
- L'indicateur
--source
est utilisé pour indiquer à Cloud Run de compiler la fonction dans un service basé sur un conteneur exécutable. - L'indicateur
--function
(nouveau) est utilisé pour définir le point d'entrée du nouveau service sur la signature de fonction que vous souhaitez appeler. - Le flag
--base-image
(nouveau) spécifie l'environnement d'image de base de votre fonction, commenodejs22
,python312
,go123
,java21
,dotnet8
,ruby33
ouphp83
. Pour en savoir plus sur les images de base et les packages inclus dans chaque image, consultez Images de base des environnements d'exécution. - (facultatif) L'option
--timeout
permet à la fonction de disposer d'un délai d'attente plus long pour répondre aux requêtes HTTP. Dans cet exemple, 600 secondes sont utilisées pour illustrer un délai de réponse de 10 minutes. - (facultatif)
--no-allow-unauthenticated
pour empêcher l'appel public de votre fonction
Tester
Testez la fonction à l'aide des commandes suivantes :
# 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
Le message HTTP with Node.js in Cloud Run functions!
doit s'afficher en réponse.
4. Fonction Pub/Sub
Pour la deuxième fonction, créons une fonction Python déclenchée par un message Pub/Sub publié dans un sujet spécifique.
Configurer des jetons d'authentification Pub/Sub
Si vous avez activé le compte de service Pub/Sub le 8 avril 2021 ou avant cette date, attribuez le rôle iam.serviceAccountTokenCreator
au compte de service 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
Créer
Créez un sujet Pub/Sub à utiliser pour l'exemple :
TOPIC=cloud-run-functions-pubsub-topic gcloud pubsub topics create $TOPIC
Créez un dossier pour l'application et accédez-y :
mkdir ../hello-pubsub cd ../hello-pubsub
Créez un fichier main.py
qui enregistre un message contenant l'ID 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'])
Créez un fichier requirements.txt
avec le contenu suivant pour spécifier les dépendances :
functions-framework==3.*
Déployer
Déployez la fonction :
gcloud run deploy python-pubsub-function \ --source . \ --function hello_pubsub \ --base-image python313 \ --region $REGION \ --no-allow-unauthenticated
Récupérez le numéro de projet à utiliser pour l'identité du compte de service.
PROJECT_NUMBER=$(gcloud projects list --filter="project_id:$PROJECT_ID" --format='value(project_number)')
Créer le déclencheur
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
Tester
Testez la fonction en envoyant un message au sujet :
gcloud pubsub topics publish $TOPIC --message="Hello World"
L'événement CloudEvent reçu doit apparaître dans les journaux :
gcloud run services logs read python-pubsub-function --region $REGION --limit=10
5. Fonction Cloud Storage
Pour la prochaine fonction, créons une fonction Node.js qui répond aux événements d'un bucket Cloud Storage.
Configurer
Pour utiliser les fonctions Cloud Storage, attribuez le rôle IAM pubsub.publisher
au compte de service 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
Créer
Créez un dossier pour l'application et accédez-y :
mkdir ../hello-storage cd ../hello-storage
Créez un fichier index.js
qui répond simplement aux événements 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); });
Créez un fichier package.json
pour spécifier les dépendances :
{ "name": "nodejs-crf-cloud-storage", "version": "0.0.1", "main": "index.js", "dependencies": { "@google-cloud/functions-framework": "^2.0.0" } }
Déployer
Commencez par créer un bucket Cloud Storage (ou utilisez un bucket existant) :
export BUCKET_NAME="gcf-storage-$PROJECT_ID" export BUCKET="gs://gcf-storage-$PROJECT_ID" gsutil mb -l $REGION $BUCKET
Déployez la fonction :
gcloud run deploy nodejs-crf-cloud-storage \ --source . \ --base-image nodejs22 \ --function helloStorage \ --region $REGION \ --no-allow-unauthenticated
Une fois la fonction déployée, vous pouvez la voir dans la section Cloud Run de la console Cloud.
Créez maintenant le déclencheur 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
Tester
Testez la fonction en important un fichier dans le bucket :
echo "Hello World" > random.txt gsutil cp random.txt $BUCKET/random.txt
L'événement CloudEvent reçu doit apparaître dans les journaux :
gcloud run services logs read nodejs-crf-cloud-storage --region $REGION --limit=10
6. Cloud Audit Logs
Pour la fonction suivante, créons une fonction Node.js qui reçoit un événement Cloud Audit Logs lorsqu'une instance de VM Compute Engine est créée. En réponse, il ajoute un libellé à la VM nouvellement créée, en spécifiant le créateur de la VM.
Identifier les VM Compute Engine nouvellement créées
Compute Engine émet deux journaux d'audit lorsqu'une VM est créée.
La première est émise au début de la création de la VM. Le deuxième est émis après la création de la VM.
Dans les journaux d'audit, les champs d'opération sont différents et contiennent les valeurs first: true
et last: true
. Le deuxième journal d'audit contient toutes les informations dont nous avons besoin pour étiqueter une instance. Nous utiliserons donc l'indicateur last: true
pour le détecter dans les fonctions Cloud Run.
Configurer
Pour utiliser les fonctions Cloud Audit Logs, vous devez activer les journaux d'audit pour Eventarc. Vous devez également utiliser un compte de service avec le rôle eventarc.eventReceiver
.
- Activez les journaux d'audit Cloud de type Lecture administrateur, Lecture de données et Écriture de données pour l'API Compute Engine.
- Attribuez le rôle IAM
eventarc.eventReceiver
au compte de service Compute Engine par défaut :
gcloud projects add-iam-policy-binding $PROJECT_ID \ --member serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \ --role roles/eventarc.eventReceiver
Créer la fonction
Cet atelier de programmation utilise Node.js, mais vous trouverez d'autres exemples sur https://github.com/GoogleCloudPlatform/eventarc-samples.
Créez un fichier package.json
.
{
"dependencies": {
"googleapis": "^84.0.0"
}
}
Créez un fichier 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;
}
Déployer
Déployez la fonction :
gcloud run deploy gce-vm-labeler \ --source . \ --function labelVmCreation \ --region $REGION \ --no-allow-unauthenticated
Créez maintenant le déclencheur. Notez que la fonction filtre les journaux d'audit pour les insertions Compute Engine avec l'indicateur --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
Tester
Définissez les variables d'environnement :
# if you're using europe-west1 as your region
ZONE=europe-west1-d
VM_NAME=codelab-crf-auditlog
Exécutez la commande suivante pour créer une VM :
gcloud compute instances create $VM_NAME --zone=$ZONE --machine-type=e2-medium --image-family=debian-11 --image-project=debian-cloud
Une fois la VM créée, vous devriez voir le libellé creator
ajouté à la VM dans la section Informations de base de la console Cloud ou à l'aide de la commande suivante :
gcloud compute instances describe $VM_NAME --zone=$ZONE
Vous devriez voir le libellé dans le résultat, comme dans l'exemple suivant :
... labelFingerprint: ULU6pAy2C7s= labels: creator: atameldev ...
Effectuer un nettoyage
Veillez à supprimer l'instance de VM. Vous ne l'utiliserez plus dans cet atelier.
gcloud compute instances delete $VM_NAME --zone=$ZONE
7. Répartition du trafic
Cloud Run Functions est compatible avec plusieurs révisions de vos fonctions, ce qui vous permet de répartir le trafic entre différentes révisions et d'effectuer un rollback de votre fonction vers une version précédente.
Dans cette étape, vous allez déployer deux révisions d'une fonction, puis répartir le trafic entre elles à 50/50.
Créer
Créez un dossier pour l'application et accédez-y :
mkdir ../traffic-splitting cd ../traffic-splitting
Créez un fichier main.py
avec une fonction Python qui lit une variable d'environnement de couleur et répond avec Hello World
dans cette couleur d'arrière-plan :
import os color = os.environ.get('COLOR') def hello_world(request): return f'<body style="background-color:{color}"><h1>Hello World!</h1></body>'
Créez un fichier requirements.txt
avec le contenu suivant pour spécifier les dépendances :
functions-framework==3.*
Déployer
Déployez la première révision de la fonction avec un arrière-plan orange :
COLOR=orange gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
À ce stade, si vous testez la fonction en affichant le déclencheur HTTP (l'URI généré par la commande de déploiement ci-dessus) dans votre navigateur, vous devriez voir Hello World
avec un arrière-plan orange :
Déployez la deuxième révision avec un arrière-plan jaune :
COLOR=yellow gcloud run deploy hello-world-colors \ --source . \ --base-image python313 \ --function hello_world \ --region $REGION \ --allow-unauthenticated \ --update-env-vars COLOR=$COLOR
Comme il s'agit de la dernière révision, si vous testez la fonction, vous devriez voir Hello World
avec un arrière-plan jaune :
Répartir le trafic à 50/50
Pour répartir le trafic entre les révisions orange et jaune, vous devez trouver les ID de révision des services Cloud Run. Voici la commande permettant d'afficher les ID de révision :
gcloud run revisions list --service hello-world-colors \ --region $REGION --format 'value(REVISION)'
La sortie devrait ressembler à ce qui suit :
hello-world-colors-00001-man hello-world-colors-00002-wok
Répartissez maintenant le trafic entre ces deux révisions comme suit (mettez à jour le fichier X-XXX
en fonction des noms de vos révisions) :
gcloud run services update-traffic hello-world-colors \ --region $REGION \ --to-revisions hello-world-colors-0000X-XXX=50,hello-world-colors-0000X-XXX=50
Tester
Testez la fonction en accédant à son URL publique. La moitié du temps, vous devriez voir la révision orange et l'autre moitié, la révision jaune :
Pour en savoir plus, consultez Rollbacks, déploiements progressifs et migration du trafic.
8. Nombre minimal d'instances
Dans Cloud Run Functions, vous pouvez spécifier un nombre minimal d'instances de fonction à garder en attente et prêtes à diffuser des requêtes. Cela permet de limiter le nombre de démarrages à froid.
Dans cette étape, vous allez déployer une fonction avec une initialisation lente. Vous observerez le problème de démarrage à froid. Vous allez ensuite déployer la fonction avec la valeur minimale d'instance définie sur 1 pour éliminer le démarrage à froid.
Créer
Créez un dossier pour l'application et accédez-y :
mkdir ../min-instances cd ../min-instances
Créez un fichier main.go
. Ce service Go comporte une fonction init
qui met en veille pendant 10 secondes pour simuler une longue initialisation. Il dispose également d'une fonction HelloWorld
qui répond aux appels 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!") }
Déployer
Déployez la première révision de la fonction avec la valeur minimale par défaut d'instance (zéro) :
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated
Testez la fonction avec cette commande :
# 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
Vous constaterez un délai de 10 secondes (démarrage à froid) lors du premier appel, puis vous verrez le message. Les appels suivants doivent être renvoyés immédiatement.
Définir un nombre minimal d'instances
Pour éviter le démarrage à froid lors de la première requête, redéployez la fonction en définissant l'indicateur --min-instances
sur 1, comme suit :
gcloud run deploy go-slow-function \ --source . \ --base-image go123 \ --function HelloWorld \ --region $REGION \ --no-allow-unauthenticated \ --min-instances 1
Tester
Testez à nouveau la fonction :
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" -X GET $SERVICE_URL
Vous ne devriez plus voir le délai de 10 secondes dans la première requête. Le problème de démarrage à froid pour la première invocation (après une longue période d'inactivité) a disparu grâce aux instances minimales.
Pour en savoir plus, consultez Utiliser un nombre minimal d'instances.
9. Félicitations !
Bravo ! Vous avez terminé cet atelier de programmation.
Points abordés
- Présentation de Cloud Run Functions et de l'utilisation des mises à jour automatiques des images de base.
- Écrire une fonction qui répond aux appels HTTP
- Comment écrire une fonction qui répond aux messages Pub/Sub
- Écrire une fonction qui répond aux événements Cloud Storage
- Découvrez comment répartir le trafic entre deux révisions.
- Découvrez comment éliminer les démarrages à froid grâce au nombre minimal d'instances.