Déclencher à partir de la fonctionnalité push de Pub/Sub

Cette page décrit comment utiliser Pub/Sub pour envoyer des messages au point de terminaison de votre service Cloud Run, où ils sont ensuite diffusés aux conteneurs en tant que requêtes HTTP. Cette page explique comment permettre à votre service de traiter de manière sécurisée les messages envoyés depuis un abonnement Pub/Sub dans le même projet Google Cloud.

Grâce aux comptes de service et aux autorisations IAM, vous pouvez utiliser Pub/Sub avec Cloud Run de manière sécurisée et privée, sans avoir à exposer publiquement votre service Cloud Run. Seul l'abonnement Pub/Sub que vous avez configuré peut appeler votre service.

Délais de confirmation pour Cloud Run

Assurez-vous de définir le délai de confirmation d'abonnement Pub/Sub (ackDeadlineSeconds) sur le maximum autorisé de 600 secondes. Votre service Cloud Run doit confirmer le message Pub/Sub en renvoyant une réponse dans un délai de 600 secondes. Sinon, Pub/Sub redistribue le message, ce qui entraîne un déclenchement en double de votre service Cloud Run.

Cas d'utilisation

Exemples d'utilisation possible :

Présentation de l'intégration

Pour intégrer votre service dans Pub/Sub, procédez comme suit :

  • Créer un sujet Pub/Sub
  • Ajoutez du code dans votre service Cloud Run pour répondre aux messages Pub/Sub envoyés au sujet que vous avez créé.
  • Créez un compte de service doté des autorisations requises.
  • Créez un abonnement Pub/Sub et associez-le au compte de service. Cet abonnement enverra à votre service tout message publié sur le sujet.

Avant de commencer

  • Si ce n'est pas déjà fait, configurez votre environnement comme décrit sur la page de configuration de Cloud Run.
  • Ce guide part du principe que vous disposez déjà d'un service Cloud Run et que vous souhaitez ajouter du code qui l'intègre à Pub/Sub. Si vous ne disposez pas d'un tel service, envisagez d'utiliser le tutoriel Cloud Run pour Pub/Sub plutôt que de suivre la présente page.

Ajouter du code pour gérer les messages de Pub/Sub

Modifiez le code de service existant pour ajouter le code nécessaire à la compatibilité avec Pub/Sub. Votre service doit extraire le message de la requête et renvoyer un code de réussite attendu. Les extraits suivants pour les langages sélectionnés (vous pouvez utiliser n'importe quel langage) montrent comment procéder pour un message Hello World simple :

Node.js

app.post('/', (req, res) => {
  if (!req.body) {
    const msg = 'no Pub/Sub message received';
    console.error(`error: ${msg}`);
    res.status(400).send(`Bad Request: ${msg}`);
    return;
  }
  if (!req.body.message) {
    const msg = 'invalid Pub/Sub message format';
    console.error(`error: ${msg}`);
    res.status(400).send(`Bad Request: ${msg}`);
    return;
  }

  const pubSubMessage = req.body.message;
  const name = pubSubMessage.data
    ? Buffer.from(pubSubMessage.data, 'base64').toString().trim()
    : 'World';

  console.log(`Hello ${name}!`);
  res.status(204).send();
});

Python

@app.route("/", methods=["POST"])
def index():
    """Receive and parse Pub/Sub messages."""
    envelope = request.get_json()
    if not envelope:
        msg = "no Pub/Sub message received"
        print(f"error: {msg}")
        return f"Bad Request: {msg}", 400

    if not isinstance(envelope, dict) or "message" not in envelope:
        msg = "invalid Pub/Sub message format"
        print(f"error: {msg}")
        return f"Bad Request: {msg}", 400

    pubsub_message = envelope["message"]

    name = "World"
    if isinstance(pubsub_message, dict) and "data" in pubsub_message:
        name = base64.b64decode(pubsub_message["data"]).decode("utf-8").strip()

    print(f"Hello {name}!")

    return ("", 204)

Go


// PubSubMessage is the payload of a Pub/Sub event.
// See the documentation for more details:
// https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage
type PubSubMessage struct {
	Message struct {
		Data []byte `json:"data,omitempty"`
		ID   string `json:"id"`
	} `json:"message"`
	Subscription string `json:"subscription"`
}

// HelloPubSub receives and processes a Pub/Sub push message.
func HelloPubSub(w http.ResponseWriter, r *http.Request) {
	var m PubSubMessage
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Printf("ioutil.ReadAll: %v", err)
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}
	// byte slice unmarshalling handles base64 decoding.
	if err := json.Unmarshal(body, &m); err != nil {
		log.Printf("json.Unmarshal: %v", err)
		http.Error(w, "Bad Request", http.StatusBadRequest)
		return
	}

	name := string(m.Message.Data)
	if name == "" {
		name = "World"
	}
	log.Printf("Hello %s!", name)
}

Java

import com.example.cloudrun.Body;
import java.util.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

// PubsubController consumes a Pub/Sub message.
@RestController
public class PubSubController {
  @RequestMapping(value = "/", method = RequestMethod.POST)
  public ResponseEntity<String> receiveMessage(@RequestBody Body body) {
    // Get PubSub message from request body.
    Body.Message message = body.getMessage();
    if (message == null) {
      String msg = "Bad Request: invalid Pub/Sub message format";
      System.out.println(msg);
      return new ResponseEntity<>(msg, HttpStatus.BAD_REQUEST);
    }

    String data = message.getData();
    String target =
        !StringUtils.isEmpty(data) ? new String(Base64.getDecoder().decode(data)) : "World";
    String msg = "Hello " + target + "!";

    System.out.println(msg);
    return new ResponseEntity<>(msg, HttpStatus.OK);
  }
}

Vous devez coder le service pour renvoyer un code de réponse HTTP précis. Les codes de réussite, tels que HTTP 200 ou 204, confirment le traitement complet du message Pub/Sub. Les codes d'erreur, tels que HTTP 400 ou 500, indiquent qu'une nouvelle tentative d'envoi sera effectuée, comme décrit dans la section Recevoir des messages en mode push.

Créez puis déployez votre service Cloud Run après l'avoir mis à jour avec le code Pub/Sub ci-dessus.

Créer un compte de service pour l'abonnement

Vous devez créer un compte de service à associer à votre abonnement Pub/Sub et lui donner l'autorisation d'appeler votre service Cloud Run. Les messages Pub/Sub envoyés vers votre service Cloud Run portent l'identité de ce compte de service.

Vous pouvez utiliser un compte de service existant pour représenter l'identité de l'abonnement Pub/Sub, ou en créer un autre.

Pour créer un compte de service et lui donner l'autorisation d'appeler le service Cloud Run, procédez comme suit :

Console

  1. Dans la console Google Cloud, accédez à la page Comptes de service.

    Accéder à la page "Comptes de service"

  2. Sélectionnez un projet.

  3. Saisissez le nom du compte de service à afficher dans la console Google Cloud.

    La console Google Cloud génère un ID de compte de service basé sur ce nom. Modifiez l'ID si nécessaire. Vous ne pourrez pas le modifier par la suite.

  4. Facultatif : saisissez la description du compte de service.

  5. Cliquez sur Créer et continuer.

  6. Facultatif : cliquez sur le champ Sélectionner un rôle.

  7. Sélectionnez Cloud Run > Demandeur Cloud Run.

  8. Cliquez sur OK.

Ligne de commande

  1. Créez le compte de service :

    gcloud iam service-accounts create SERVICE_ACCOUNT_NAME \
       --display-name "DISPLAYED_SERVICE_ACCOUNT_NAME"

    Remplacez

    • SERVICE_ACCOUNT_NAME par un nom écrit en minuscules unique dans votre projet Google Cloud, par exemple my-invoker-service-account-name ;
    • DISPLAYED_SERVICE_ACCOUNT_NAME par le nom que vous souhaitez afficher pour ce compte de service, par exemple dans la console : My Invoker Service Account.
  2. Pour Cloud Run, autorisez votre compte de service à appeler votre service :

    gcloud run services add-iam-policy-binding SERVICE \
       --member=serviceAccount:SERVICE_ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com \
       --role=roles/run.invoker

    Remplacer

    • SERVICE par le nom du service que vous souhaitez que Pub/Sub appelle ;
    • SERVICE_ACCOUNT_NAME par le nom du compte de service ;
    • PROJECT_ID par l'ID de votre projet Google Cloud
  3. Accordez à votre compte de service l'accès au projet afin qu'il soit autorisé à effectuer des actions spécifiques sur les ressources de votre projet :

    gcloud projects add-iam-policy-binding RESOURCE_ID \
       --member=PRINCIPAL --role=roles/run.invoker

    Remplacer

    • RESOURCE_ID : ID de votre projet Google Cloud.

    • PRINCIPAL : l'identifiant du compte principal, qui se présente généralement sous la forme suivante : PRINCIPAL_TYPE:ID. Exemple : user:my-user@example.com. Pour obtenir la liste complète des valeurs possibles pour PRINCIPAL, consultez la documentation de référence sur les liaisons de stratégie.

Terraform

Pour savoir comment appliquer ou supprimer une configuration Terraform, consultez la page Commandes Terraform de base.

  1. Pour créer le compte de service, ajoutez les éléments suivants à votre fichier .tf existant :

    resource "google_service_account" "sa" {
      account_id   = "cloud-run-pubsub-invoker"
      display_name = "Cloud Run Pub/Sub Invoker"
    }
  2. Pour autoriser votre compte de service à appeler votre service, ajoutez ce qui suit à votre fichier .tf existant :

    resource "google_cloud_run_service_iam_binding" "binding" {
      location = google_cloud_run_v2_service.default.location
      service  = google_cloud_run_v2_service.default.name
      role     = "roles/run.invoker"
      members  = ["serviceAccount:${google_service_account.sa.email}"]
    }

Créer un sujet Pub/Sub

Étant donné que les requêtes adressées à votre service sont déclenchées par des messages publiés dans un sujet Pub/Sub, vous devez créer un sujet :

Console

  1. Accédez à la page des sujets Pub/Sub dans Google Cloud Console.

    Page des sujets Pub/Sub

  2. Cliquez sur Créer un sujet.

  3. Saisissez un nom unique pour votre sujet (par exemple : MyTopic).

Command line

gcloud pubsub topics create TOPIC-NAME

Remplacez TOPIC-NAME par un nom de sujet unique dans votre projet Google Cloud.

Terraform

Pour savoir comment appliquer ou supprimer une configuration Terraform, consultez la page Commandes Terraform de base.

Cette section explique comment utiliser Terraform pour définir votre service dans une configuration Terraform à l'aide de la ressource google_pubsub_topic du fournisseur Google Cloud Platform.

Ajoutez le contenu suivant à votre fichier .tf :

resource "google_pubsub_topic" "default" {
  name = "pubsub_topic"
}

Créer un abonnement push et l'associer au compte de service

Une fois que vous avez créé le sujet Pub/Sub, vous devez abonner votre service pour recevoir les messages envoyés à un sujet, et vous devez associer l'abonnement au compte de service que vous avez créé pour votre service. Vous pouvez utiliser Google Cloud Console ou la ligne de commande gcloud :

Console

  1. Accédez à la page des sujets Pub/Sub.

    Page des sujets Pub/Sub

  2. Cliquez sur le sujet auquel vous souhaitez vous abonner.

  3. Cliquez sur Create Subscription (Créer un abonnement) pour afficher le formulaire d'abonnement :

    formulaire d'abonnement

    Dans le formulaire,

    1. Spécifiez le type de distribution push.
    2. Dans le champ "Endpoint URL" (URL du point de terminaison), spécifiez l'URL de votre service, qui s'affiche sur la page d'informations du service.
    3. Dans la liste déroulante Service Account (Compte de service), sélectionnez le compte de service créé avec les autorisations requises.
    4. Définissez l'expiration de l'abonnement et un délai de confirmation de 600 secondes.
    5. Cliquez sur Create (Créer).
  4. L'abonnement est terminé. Les messages publiés sur le sujet seront désormais envoyés vers votre service.

Command line

  1. Autorisez Pub/Sub à créer des jetons d'authentification dans votre projet :

    gcloud projects add-iam-policy-binding PROJECT-ID \
         --member=serviceAccount:service-PROJECT-NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com \
         --role=roles/iam.serviceAccountTokenCreator

    Remplacer

    • PROJECT-ID par l'ID de votre projet Google Cloud
    • PROJECT-NUMBER par le numéro de votre projet Google Cloud

      L'ID et le numéro du projet sont répertoriés dans le panneau Informations sur le projet de Google Cloud Console pour votre projet.

  2. Créez un abonnement Pub/Sub avec le compte de service que vous avez créé avec les autorisations requises :

    gcloud pubsub subscriptions create SUBSCRIPTION-ID --topic TOPIC-NAME \
       --ack-deadline=600 \
       --push-endpoint=SERVICE-URL/ \
       --push-auth-service-account=SERVICE-ACCOUNT-NAME@PROJECT-ID.iam.gserviceaccount.com

    Remplacer

    • TOPIC-NAME par le sujet que vous avez créé précédemment
    • SERVICE-URL par l'URL HTTPS fournie lors du déploiement du service. Pour l'obtenir, utilisez la commande gcloud run services describe en spécifiant le nom de votre service : recherchez la ligne de retour commençant par domain.
    • PROJECT-ID par l'ID de votre projet Google Cloud

    L'option --push-auth-service-account active la fonctionnalité push de Pub/Sub pour l'authentification et l'autorisation.

    Notez que le délai de confirmation est défini sur 600 secondes au maximum.

  3. L'abonnement est terminé. Les messages publiés sur le sujet seront désormais envoyés vers votre service. Vous pouvez envoyer un message de test au sujet à l'aide de la commande suivante :

    gcloud pubsub topics publish TOPIC --message "hello"

    Remplacez TOPIC par le nom du sujet que vous avez créé.

Terraform

Pour savoir comment appliquer ou supprimer une configuration Terraform, consultez la page Commandes Terraform de base.

  1. Autorisez Pub/Sub à créer des jetons d'authentification dans votre projet. Ajoutez le code ci-dessous à votre fichier .tf :

    resource "google_project_service_identity" "pubsub_agent" {
      provider = google-beta
      project  = data.google_project.project.project_id
      service  = "pubsub.googleapis.com"
    }
    
    resource "google_project_iam_binding" "project_token_creator" {
      project = data.google_project.project.project_id
      role    = "roles/iam.serviceAccountTokenCreator"
      members = ["serviceAccount:${google_project_service_identity.pubsub_agent.email}"]
    }
  2. Créez un abonnement Pub/Sub avec le compte de service que vous avez créé avec les autorisations requises. Ajoutez le code ci-dessous à votre fichier .tf :

    resource "google_pubsub_subscription" "subscription" {
      name  = "pubsub_subscription"
      topic = google_pubsub_topic.default.name
      push_config {
        push_endpoint = google_cloud_run_v2_service.default.uri
        oidc_token {
          service_account_email = google_service_account.sa.email
        }
        attributes = {
          x-goog-version = "v1"
        }
      }
      depends_on = [google_cloud_run_v2_service.default]
    }
  3. L'abonnement est terminé. Les messages publiés sur le sujet seront désormais envoyés vers votre service. Vous pouvez envoyer un message de test au sujet à l'aide de la commande suivante :

    gcloud pubsub topics publish TOPIC --message "hello"

    Remplacez TOPIC par le nom du sujet que vous avez créé.

Étape suivante