Développement de fonctions locales

Les fonctions Cloud Run sont compatibles avec plusieurs méthodes d'exécution des fonctions en dehors de l'environnement de déploiement cible. Cela est particulièrement utile pour le développement itératif et dans les cas où vous souhaitez tester votre fonction avant le déploiement.

La possibilité d'exécuter vos fonctions sans les déployer peut simplifier les tests locaux, la conformité avec les restrictions de localité des données et les déploiements multicloud:

  • Restrictions de localité des données: testez votre fonction en local sans accéder aux données de production pour éviter de ne pas respecter les règles de localité des données de votre organisation.

  • Déploiements multiclouds: les déploiements de fonctions multiclouds sont un modèle établi permettant de limiter le risque de temps d'arrêt dans les environnements critiques. Le déploiement de fonctions dans des environnements autres que les fonctions Cloud Run réduit le risque que votre application subisse un temps d'arrêt non planifié.

Développer des fonctions localement à l'aide du framework des fonctions

Vous pouvez développer et tester des fonctions localement à l'aide du framework des fonctions. Développer une fonction localement peut vous aider à tester votre code sans avoir à reconstruire votre conteneur de fonction. Cela peut vous faire gagner du temps et faciliter le test de votre fonction.

Cloud Run utilise les bibliothèques Open Source Framework de fonctions pour encapsuler vos fonctions déployées dans une application HTTP persistante.

Le framework des fonctions peut également s'exécuter sur n'importe quelle plate-forme compatible avec le langage en question, y compris votre machine locale, vos serveurs sur site et Compute Engine.

Installer des dépendances

Dans le répertoire de votre fonction, installez la bibliothèque du framework des fonctions pour votre langage:

Node.js

npm install --save-dev @google-cloud/functions-framework

Python

pip3 install functions-framework

Go

go install github.com/GoogleCloudPlatform/functions-framework-go/funcframework

Java

Maven

Si vous utilisez Maven, ajoutez les lignes suivantes à votre fichier pom.xml :

<dependency>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>functions-framework-api</artifactId>
  <version>1.1.0</version>
  <scope>provided</scope>
</dependency>

Gradle

Si vous utilisez Gradle, ajoutez les lignes suivantes à votre fichier build.gradle :

dependencies {
  // Every function needs this dependency to get the Functions Framework API.
  compileOnly 'com.google.cloud.functions:functions-framework-api:1.1.0'

  // To run function locally using Functions Framework's local invoker
  invoker 'com.google.cloud.functions.invoker:java-function-invoker:1.3.1'
}

Pour en savoir plus, consultez la bibliothèque Java Functions Framework.

C#

Les commandes suivantes exploitent des modèles .NET pour créer un codebase de fonction .NET avec la bibliothèque du framework des fonctions.NET en tant que dépendance:

# HTTP functions
dotnet new gcf-http

# CloudEvent functions
dotnet new gcf-event

Ruby

Dans Ruby, le framework Functions doit être ajouté aux dépendances de votre fonction afin de pouvoir le déployer dans Cloud Run:

bundle add functions_framework

PHP

composer require google/cloud-functions-framework

Configurer le framework des fonctions

Avant d'exécuter une fonction à l'aide du framework des fonctions, vous devez d'abord spécifier le type et le nom de la fonction concernée. Ces attributs peuvent être spécifiés en tant qu'options d'interface de ligne de commande (CLI) ou en tant que variables d'environnement.

Types de fonctions compatibles

Le framework Functions est compatible avec les deux types de fonctions pris en charge par les fonctions Cloud Run. Tous les environnements d'exécution de langage sont compatibles avec les types de signature http et cloudevent.

Type de fonction Type de signature Description Environnements d'exécution acceptés
Fonctions déclenchées par HTTP http Fonctions qui reçoivent des requêtes HTTP et y répondent. Tous les environnements d'exécution
Fonctions CloudEvent cloudevent Format d'événement standard dans l'industrie. Tous les environnements d'exécution

Spécifier la fonction à exécuter

Avant d'exécuter une fonction avec le framework des fonctions, vous devez d'abord spécifier quelle fonction dans votre code doit être exécutée. Dans la plupart des langages, vous pouvez pour cela spécifier le nom de la méthode de la fonction cible, comme indiqué dans les tableaux suivants. Notez qu'il existe des exceptions à cette règle pour les environnements d'exécution Java et .NET.

Instructions pour chaque langage

Pour connaître la liste des options de configuration compatibles avec chaque langage, reportez-vous au tableau suivant.

Node.js

Argument CLI Variable d'environnement Description
--port PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)
--target FUNCTION_TARGET Nom de la fonction exportée (export) à appeler. (Par défaut : function)
--signature-type FUNCTION_SIGNATURE_TYPE Type de signature utilisé par votre fonction. Peut être http (par défaut), ou cloudevent.

Python

Argument CLI Variable d'environnement Description
--port PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)
--target FUNCTION_TARGET Nom de la fonction exportée (export) à appeler. (Par défaut : function)
--signature-type FUNCTION_SIGNATURE_TYPE Type de signature utilisé par votre fonction. Peut être http (par défaut), ou cloudevent.

Go

Variable d'environnement Description
PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)

Java

Nom de l'argument Variable d'environnement Description
run.port PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)
run.functionTarget FUNCTION_TARGET Nom de la fonction exportée (export) à appeler. (Par défaut : function)

C#

Argument CLI Variable d'environnement Description
--port PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)
--target (ou argument seul) FUNCTION_TARGET Nom de classe de la fonction à appeler. (Par défaut : function)

Ruby

Argument CLI Variable d'environnement Description
--port PORT Port sur lequel écouter les requêtes. (Par défaut : 8080)
--target FUNCTION_TARGET Nom de la fonction exportée (export) à appeler. (Par défaut : function)

PHP

Variable d'environnement Description
FUNCTION_TARGET Nom de la fonction à appeler. (Par défaut : function)
FUNCTION_SIGNATURE_TYPE Type de signature utilisé par votre fonction. Peut être http (par défaut), ou cloudevent.

Suivez ces instructions pour configurer et exécuter le framework des fonctions:

Node.js

Le framework des fonctions Node.js vous permet de spécifier le nom et le type de signature de votre fonction en tant qu'arguments de ligne de commande ou en tant que variables d'environnement.

Vous pouvez également spécifier ces valeurs dans le fichier de build package.json en ajoutant un script start avec les arguments CLI requis, comme illustré dans l'exemple ci-dessous.

"scripts": {
"start": "npx functions-framework --target=YOUR_FUNCTION_NAME [--signature-type=YOUR_SIGNATURE_TYPE]"
}

Vous pouvez également procéder de la même manière à l'aide de variables d'environnement:

"scripts": {
"start": "FUNCTION_TARGET=YOUR_FUNCTION_NAME FUNCTION_SIGNATURE_TYPE=YOUR_SIGNATURE_TYPE npx functions-framework"
}

Remplacez YOUR_FUNCTION_NAME par le nom de la méthode de votre fonction et YOUR_SIGNATURE_TYPE (le cas échéant) par le type de signature de votre fonction, comme indiqué dans la section Types de fonctions compatibles.

Python

Le framework des fonctions Python vous permet de spécifier le nom et le type de signature de votre fonction en tant qu'arguments de ligne de commande ou en tant que variables d'environnement. Les arguments de ligne de commande doivent être spécifiés lorsque vous exécutez le framework.

Go

Le framework des fonctions Go utilise funcframework.RegisterHTTPFunctionContext pour spécifier le type de signature et la cible de la fonction.

Java

Le framework des fonctions Java accepte des données de configuration provenant de trois sources différentes, dans l'ordre de priorité suivant (du plus spécifique au moins spécifique) :

  • Arguments de ligne de commande
  • Fichiers de build
  • Variables d'environnement

Arguments de ligne de commande

Maven

Vous pouvez spécifier la fonction à exécuter en ajoutant l'option d'interface de ligne de commande (CLI) suivante à vos commandes mvn :

-Drun.functionTarget=YOUR_FUNCTION_NAME

Vous pouvez également spécifier le port cible en ajoutant l'option CLI suivante de la même manière :

-Drun.port=12345

Gradle

Les options CLI de Gradle sont presque identiques à celles de Maven. La seule différence est que Gradle remplace l'élément -D initial de chaque option par -P, comme le montre l'exemple suivant:

# Maven version

-Drun.functionTarget=...

# Gradle version

-Prun.functionTarget=...

Fichiers de build

Vous pouvez également spécifier la fonction à exécuter dans le fichier de build de votre projet. Bien que Maven et Gradle présentent des options CLI similaires, leurs clauses de fichier de build sont sensiblement différentes.

Maven

Les fichiers de build Maven sont nommés pom.xml. Ajoutez la clause suivante à ce fichier pour spécifier une fonction cible :

<plugin>
  <groupId>com.google.cloud.functions</groupId>
  <artifactId>function-maven-plugin</artifactId>
  <version>0.11.0</version>
  <configuration>
    <functionTarget>functions.HelloWorld</functionTarget>
  </configuration>
</plugin>

Remplacez <functionTarget> par le nom de classe de votre fonction. Par exemple, une fonction du package functions avec le nom de classe HelloCloudFunctions possède le nom de classe functions.HelloCloudFunctions. Il s'agit d'une valeur relative au fichier de compilation parent (pom.xml ou build.gradle).

Gradle

Les fichiers de build Gradle sont nommés build.gradle. Ajoutez la clause suivante à ce fichier pour spécifier une fonction cible :

// Register a "runFunction" task to run the function locally
tasks.register("runFunction", JavaExec) {
  main = 'com.google.cloud.functions.invoker.runner.Invoker'
  classpath(configurations.invoker)
  inputs.files(configurations.runtimeClasspath, sourceSets.main.output)
  args(
    '--target', project.findProperty('run.functionTarget') ?: '',
    '--port', project.findProperty('run.port') ?: 8080
  )
  doFirst {
    args('--classpath', files(configurations.runtimeClasspath, sourceSets.main.output).asPath)
  }
}

C#

Si vous créez votre projet à l'aide de dotnet new et de l'un des modèles spécifiés précédemment, le framework des fonctions .NET détecte automatiquement votre fonction.

Si votre projet contient plusieurs fonctions, consultez la section Exécuter le framework pour en savoir plus sur l'exécution d'une fonction spécifique.

Ruby

Le framework des fonctions Ruby vous permet de spécifier le nom et le type de signature de votre fonction en tant qu'arguments de ligne de commande ou en tant que variables d'environnement. Les arguments de ligne de commande doivent être spécifiés lorsque vous exécutez le framework.

PHP

Le framework des fonctions PHP vous permet de spécifier des variables d'environnement en tant qu'arguments de ligne de commande.

Vous pouvez également spécifier ces valeurs dans le fichier de compilation composer.json en ajoutant un script start, comme illustré dans l'exemple ci-dessous.

"scripts": {
 "start": [
     "Composer\\Config::disableProcessTimeout",
     "FUNCTION_TARGET=YOUR_FUNCTION_NAME php -S localhost:${PORT:-8080} vendor/bin/router.php"
].
}

Remplacez YOUR_FUNCTION_NAME par le nom de votre fonction et YOUR_SIGNATURE_TYPE (le cas échéant, il n'est pas inclus dans l'exemple présenté ici).

Exécuter votre fonction

Utilisez la commande ci-dessous pour exécuter votre fonction avec le framework des fonctions. Par défaut, votre fonction est accessible à l'adresse localhost:8080, sauf si vous spécifiez explicitement une valeur PORT.

Node.js

npm start

Python

Utiliser des arguments de ligne de commande:

functions-framework --target=YOUR_FUNCTION_NAME

Utiliser des variables d'environnement:

FUNCTION_TARGET=YOUR_FUNCTION_NAME functions-framework

Remplacez YOUR_FUNCTION_NAME par le nom de la méthode de votre fonction.

Go

Créez d'abord un fichier cmd/main.go comme décrit sur le site du framework des fonctions pour Go.

cd cmd
go build
./cmd

Utiliser des variables d'environnement:

cd cmd
go build
PORT=8080 ./cmd

Java

Maven

Utilisez la commande suivante pour exécuter une fonction spécifiée dans pom.xml :

mvn function:run

Utilisez la commande suivante pour exécuter une fonction spécifiée dans un argument de ligne de commande :

mvn function:run -Drun.functionTarget=YOUR_FUNCTION_NAME

Utilisez la commande suivante pour exécuter une fonction spécifiée en tant que variable d'environnement:

FUNCTION_TARGET=YOUR_FUNCTION_NAME mvn function:run

Remplacez YOUR_FUNCTION_NAME par le nom de classe de votre fonction.

Gradle

Utilisez la commande suivante pour exécuter une fonction spécifiée dans build.gradle :

./gradlew runFunction

Utilisez la commande suivante pour exécuter une fonction spécifiée dans un argument de ligne de commande :

./gradlew runFunction -Prun.functionTarget=YOUR_FUNCTION_NAME

Utilisez la commande suivante pour exécuter une fonction spécifiée en tant que variable d'environnement:

FUNCTION_TARGET=YOUR_FUNCTION_NAME ./gradlew runFunction

Remplacez YOUR_FUNCTION_NAME par le nom de classe de votre fonction.

C#

Utilisez la commande suivante pour exécuter votre fonction lorsqu'une seule fonction est présente dans le projet .NET actuel. Notez qu'il s'agit de la structure par défaut pour les projets créés à l'aide d'un modèle.

dotnet run

Si votre projet .NET contient plusieurs fonctions, utilisez la commande suivante pour exécuter une fonction spécifique. Remplacez YOUR_FUNCTION_CLASSNAME par le nom de classe de votre fonction, en incluant l'espace de noms.

dotnet run YOUR_FUNCTION_CLASSNAME

Si vous souhaitez exécuter plusieurs fonctions simultanément, vous devez exécuter plusieurs instances du framework des fonctions. Pour éviter les conflits entre les instances du framework en cours d'exécution, chaque instance doit utiliser une valeur PORT différente. La commande suivante montre comment exécuter une fonction avec une valeur PORT définie sur 8080.

Utiliser des arguments de ligne de commande:

dotnet run --target YOUR_FUNCTION_CLASSNAME --port 8080

Utiliser des variables d'environnement:

FUNCTION_TARGET=YOUR_FUNCTION_CLASSNAME PORT=8080 dotnet run

Ruby

Utiliser des arguments de ligne de commande:

bundle exec functions-framework-ruby --target YOUR_FUNCTION_NAME

Utiliser des variables d'environnement:

FUNCTION_TARGET=YOUR_FUNCTION_NAME bundle exec functions-framework-ruby

Remplacez YOUR_FUNCTION_NAME par le nom de la méthode de votre fonction.

PHP

export FUNCTION_TARGET=YOUR_FUNCTION_NAME
php -S localhost:8080 vendor/bin/router.php

Remplacez YOUR_FUNCTION_NAME par le nom de votre fonction.

Appeler votre fonction exécutée localement

Les exercices de cette section partent du principe que vous avez configuré une fonction exécutée localement sur localhost à l'aide du framework des fonctions.

Vous pouvez déclencher des fonctions exécutées localement en leur envoyant des requêtes HTTP acheminées à l'aide d'un processus de diffusion local.

Fonctions HTTP

Lorsque vous testez votre fonction HTTP à partir de votre environnement de développement, elle écoute normalement les requêtes sur localhost:8080. Cette interface n'est accessible qu'à partir de la machine ou de la VM sur laquelle votre fonction est exécutée. Les requêtes envoyées depuis un autre système ne peuvent pas l'atteindre. Pour cette raison, vous devez envoyer la requête HTTP à partir du même système sur lequel votre fonction s'exécute. Dans les exemples suivants, si votre fonction écoute sur un port autre que 8080, remplacez 8080 dans l'exemple par le numéro de port de votre fonction.

Tester les fonctions HTTP avec Cloud Shell

Si vous utilisez Cloud Shell pour créer et tester votre fonction, démarrez-la localement dans la fenêtre du terminal Cloud Shell, puis envoyez la requête de déclencheur HTTP à partir d'un navigateur ou d'une instance curl comme suit:

Navigateur

Cliquez sur l'icône Bouton &quot;Aperçu sur le Web&quot; dans la barre d'outils Cloud Shell et choisissez le port 8080 ou l'option Modifier le port pour choisir un autre port. Cela ouvre une fenêtre de navigateur sur le système approprié et envoie une requête GET au port indiqué.

Curl

Pour contrôler le format de votre requête HTTP ou pour afficher la réponse non formatée, utilisez curl:

  1. Cliquez sur l'icône + dans la barre de menu de Cloud Shell pour ouvrir une nouvelle fenêtre de terminal sur le même système que celui sur lequel votre fonction est exécutée.
  2. Dans cette fenêtre, exécutez la commande curl pour déclencher votre fonction. Exemple :

    curl localhost:8080
    

Tester les fonctions HTTP sur votre serveur d'ordinateur

Si vous créez et exécutez votre fonction sur votre système local de bureau, commencez par la démarrer en local, puis envoyez la requête de déclencheur HTTP à partir d'un navigateur ou d'une instance curl comme suit:

Navigateur

Ouvrez une nouvelle fenêtre ou un nouvel onglet de navigateur, puis saisissez http://localhost:8080 dans la barre d'adresse du navigateur. Une fenêtre de navigateur s'ouvre sur localhost:8080 sur votre serveur pour ordinateur afin de déclencher votre fonction.

Curl

Ouvrez une nouvelle fenêtre de terminal sur votre bureau local, puis exécutez la commande curl dans cette fenêtre pour déclencher votre fonction. Exemple :

 curl localhost:8080

La commande curl spécifiée s'exécute pour déclencher votre fonction et afficher la réponse non formatée.

Fonctions CloudEvent

Vous pouvez envoyer des exemples d'événements aux fonctions CloudEvent à l'aide de curl. Les requêtes curl suivantes montrent comment envoyer des exemples d'événements Pub/Sub et Cloud Storage à une fonction CloudEvent exécutée à l'adresse localhost:8080.

Pub/Sub

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.pubsub.topic.v1.messagePublished" \
  -H "ce-source: //pubsub.googleapis.com/projects/MY-PROJECT/topics/MY-TOPIC" \
  -d '{
        "message": {
          "data": "d29ybGQ=",
          "attributes": {
             "attr1":"attr1-value"
          }
        },
        "subscription": "projects/MY-PROJECT/subscriptions/MY-SUB"
      }'
    

Cloud Storage

curl localhost:8080 \
  -X POST \
  -H "Content-Type: application/json" \
  -H "ce-id: 123451234512345" \
  -H "ce-specversion: 1.0" \
  -H "ce-time: 2020-01-02T12:34:56.789Z" \
  -H "ce-type: google.cloud.storage.object.v1.finalized" \
  -H "ce-source: //storage.googleapis.com/projects/_/buckets/MY-BUCKET-NAME" \
  -H "ce-subject: objects/MY_FILE.txt" \
  -d '{
        "bucket": "MY_BUCKET",
        "contentType": "text/plain",
        "kind": "storage#object",
        "md5Hash": "...",
        "metageneration": "1",
        "name": "MY_FILE.txt",
        "size": "352",
        "storageClass": "MULTI_REGIONAL",
        "timeCreated": "2020-04-23T07:38:57.230Z",
        "timeStorageClassUpdated": "2020-04-23T07:38:57.230Z",
        "updated": "2020-04-23T07:38:57.230Z"
      }'