Trigger dal push di Pub/Sub

In questa pagina viene descritto l'utilizzo di Pub/Sub per il push dei messaggi all'endpoint del tuo servizio Cloud Run, dove i messaggi vengono successivamente consegnati ai container come richieste HTTP. Questa pagina mostra come consentire al servizio di elaborare in modo sicuro i messaggi inviati da una sottoscrizione Pub/Sub nello stesso progetto Google Cloud.

Grazie agli account di servizio e alle autorizzazioni IAM, puoi utilizzare Pub/Sub in modo sicuro e privato con Cloud Run, senza dover esporre pubblicamente il servizio Cloud Run. Solo la sottoscrizione Pub/Sub che hai configurato è in grado di richiamare il tuo servizio.

Scadenza accettazione per Cloud Run

Assicurati di impostare la scadenza di conferma della sottoscrizione per Pub/Sub (ackDeadlineSeconds) sul valore massimo consentito di 600 secondi. Il tuo servizio Cloud Run deve confermare il messaggio Pub/Sub restituendo una risposta entro 600 secondi, altrimenti Pub/Sub recapita nuovamente il messaggio, causando un duplicato dell'attivazione del servizio Cloud Run.

Casi d'uso

I possibili casi d'uso includono:

Panoramica sull'integrazione

Per integrare il tuo servizio con Pub/Sub,

  • Crea un argomento Pub/Sub.
  • Aggiungi codice nel tuo servizio Cloud Run per rispondere ai messaggi Pub/Sub inviati all'argomento che hai creato.
  • Crea un account di servizio con le autorizzazioni richieste.
  • Crea una sottoscrizione Pub/Sub e associala all'account di servizio. Questa sottoscrizione invierà al tuo servizio qualsiasi messaggio pubblicato nell'argomento.

Prima di iniziare

  • Se non lo hai già fatto, configura il tuo ambiente come descritto nella pagina di configurazione di Cloud Run.
  • Questa guida presuppone che tu abbia già un servizio Cloud Run e voglia aggiungere codice che lo integra con Pub/Sub. Se non disponi di questo servizio, potresti usare il tutorial di Cloud Run per Pub/Sub anziché seguire questa pagina.

Aggiungi codice per gestire i messaggi da Pub/Sub

Modifica il codice di servizio esistente per aggiungere il codice necessario per supportare Pub/Sub. Il servizio deve estrarre il messaggio dalla richiesta e restituire un codice di operazione prevista. I seguenti snippet per le lingue selezionate (puoi utilizzare qualsiasi lingua) mostrano come eseguire questa operazione per un semplice messaggio Hello World:

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():
    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)

Vai


// 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
	}
	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 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);
  }
}

Devi programmare il servizio in modo che restituisca un codice di risposta HTTP preciso. I codici di operazione riuscita, come 200 o 204, confermano l'elaborazione completa del messaggio Pub/Sub I codici di errore, come HTTP 400 o 500, indicano che il messaggio verrà ripetuto, come descritto in Ricezione di messaggi tramite Push.

Crea e poi esegui il deployment del tuo servizio Cloud Run dopo averlo aggiornato con il codice Pub/Sub riportato sopra.

Crea un account di servizio per l'abbonamento

Devi creare un account di servizio da associare al tuo abbonamento Pub/Sub e autorizzarlo a richiamare il tuo servizio Cloud Run. I messaggi Pub/Sub di cui è stato eseguito il push al servizio Cloud Run avranno l'identità di questo account di servizio.

Puoi utilizzare un account di servizio esistente per rappresentare l'identità dell'abbonamento Pub/Sub oppure crearne uno nuovo.

Per creare un nuovo account di servizio e concedergli l'autorizzazione per richiamare il servizio Cloud Run:

console

  1. In Google Cloud Console, vai alla pagina Account di servizio.

    Vai ad Account di servizio

  2. Seleziona un progetto.

  3. Inserisci il nome di un account di servizio da visualizzare in Google Cloud Console.

    Google Cloud Console genera un ID account di servizio basato su questo nome. Se necessario, modifica l'ID. Non potrai modificare l'ID in un secondo momento.

  4. (Facoltativo) Inserisci una descrizione dell'account di servizio.

  5. Fai clic su Crea.

  6. Fai clic sul campo Seleziona un ruolo.

  7. In Tutti i ruoli, seleziona Cloud Run > Invoker di Cloud Run.

  8. Fai clic su Fine.

Riga di comando

  1. Crea l'account di servizio:

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

    Sostituisci

    • SERVICE_ACCOUNT_NAME con un nome in lettere minuscole univoco all'interno del tuo progetto Google Cloud, ad esempio my-invoker-service-account-name.
    • DISPLAYED_SERVICE_ACCOUNT_NAME con il nome da visualizzare per questo account di servizio, ad esempio nella console, ad esempio My Invoker Service Account.
  2. Per Cloud Run, autorizza l'account di servizio a richiamare il tuo servizio:

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

    Sostituisci

    • SERVICE con il nome del servizio in cui vuoi richiamare.
    • SERVICE_ACCOUNT_NAME con il nome dell'account di servizio.
    • PROJECT_ID con il tuo ID progetto Google Cloud.

Terraform

Questa sezione mostra come utilizzare Terraform per definire il servizio in una configurazione Terraform utilizzando le seguenti risorse del provider di Google Cloud Platform:

Aggiungi quanto segue al tuo file main.tf esistente per creare l'account di servizio:

resource "google_service_account" "sa" {
  account_id   = "cloud-run-pubsub-invoker"
  display_name = "Cloud Run Pub/Sub Invoker"
}

Concedi all'account di servizio l'autorizzazione per richiamare il servizio Cloud Run:

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

Crea un argomento Pub/Sub

Le richieste al tuo servizio vengono attivate dai messaggi pubblicati in un argomento Pub/Sub, quindi dovrai creare un argomento:

console

  1. Visita la pagina Argomenti Pub/Sub in Google Cloud Console.

    Pagina degli argomenti Pub/Sub

  2. Fai clic su Crea un argomento.

  3. Inserisci un Nome univoco per l'argomento, ad esempio MyTopic.

Riga di comando

gcloud pubsub topics create TOPIC-NAME

Sostituisci TOPIC-NAME con un nome di argomento unico nel progetto Google Cloud.

Terraform

Questa sezione mostra come utilizzare Terraform per definire il servizio in una configurazione Terraform utilizzando la risorsa google_pubsub_topic del provider di Google Cloud Platform.

Aggiungi i seguenti contenuti al file main.tf esistente:

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

Creare un abbonamento push e associarlo all'account di servizio

Dopo aver creato l'argomento Pub/Sub, devi sottoscrivere il servizio per ricevere i messaggi inviati a un argomento e associare la sottoscrizione all'account di servizio che hai creato per il servizio. Puoi utilizzare Google Cloud Console o la riga di comando gcloud:

console

  1. Vai alla pagina degli argomenti Pub/Sub.

    Pagina degli argomenti Pub/Sub

  2. Fai clic sull'argomento a cui vuoi iscriverti.

  3. Fai clic su Crea abbonamento per visualizzare il modulo di abbonamento:

    modulo di abbonamento

    Nel modulo

    1. Specifica il tipo di pubblicazione push.
    2. Per l'URL endpoint, specifica l'URL del servizio, che viene visualizzato nella pagina dei dettagli del servizio.
    3. Nel menu a discesa Account di servizio, seleziona l'account di servizio che hai creato con le autorizzazioni richieste.
    4. Imposta una scadenza dell'abbonamento e una scadenza per la conferma di 600 secondi.
    5. Fai clic su Crea.
  4. L'abbonamento è completo. I messaggi pubblicati sull'argomento verranno inseriti automaticamente nel tuo servizio.

Riga di comando

  1. Consenti a Pub/Sub di creare token di autenticazione nel tuo progetto:

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

    Sostituisci

    • PROJECT-ID con il tuo ID progetto Google Cloud.
    • PROJECT-NUMBER con il numero di progetto Google Cloud.

      L'ID e il numero del progetto sono elencati nel riquadro Informazioni sul progetto in Google Cloud Console relativo al tuo progetto.

  2. Crea una sottoscrizione Pub/Sub con l'account di servizio che hai creato con le autorizzazioni richieste:

    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

    Sostituisci

    • TOPIC-NAME con l'argomento creato in precedenza.
    • SERVICE-URL con l'URL HTTPS fornito al momento del deployment del servizio. Puoi trovarlo utilizzando il comando gcloud run services describe, specificando il nome del tuo servizio: cerca la riga di ritorno che inizia con domain.
    • PROJECT-ID con il tuo ID progetto Google Cloud.

    Il flag --push-auth-service-account attiva la funzionalità push di Pub/Sub per Autenticazione e autorizzazione

    Tieni presente che la scadenza per la conferma è impostata su un massimo di 600 secondi.

  3. L'abbonamento è completo. I messaggi pubblicati sull'argomento verranno inseriti automaticamente nel tuo servizio. Puoi eseguire il push di un messaggio di prova all'argomento utilizzando il comando:

    gcloud pubsub topics publish TOPIC --message "hello"

    Sostituisci TOPIC con il nome dell'argomento che hai creato.

Terraform

Utilizza le seguenti risorse del provider di Google Cloud Platform:

Consenti a Pub/Sub di creare token di autenticazione nel tuo progetto. Aggiungi quanto segue al tuo file main.tf:

resource "google_project_iam_binding" "project" {
  role    = "roles/iam.serviceAccountTokenCreator"
  members = ["serviceAccount:${google_service_account.sa.email}"]
}

Crea una sottoscrizione Pub/Sub con l'account di servizio che hai creato con le autorizzazioni richieste. Aggiungi quanto segue al tuo file main.tf:

resource "google_pubsub_subscription" "subscription" {
  name  = "pubsub_subscription"
  topic = google_pubsub_topic.topic.name
  push_config {
    push_endpoint = google_cloud_run_service.default.status[0].url
    oidc_token {
      service_account_email = google_service_account.sa.email
    }
    attributes = {
      x-goog-version = "v1"
    }
  }
}

Per applicare queste risorse al tuo progetto, procedi nel seguente modo:

  1. Inizializza Terraform:

    terraform init
  2. Visualizza la configurazione Terraform che verrà applicata al tuo progetto:

    terraform plan
  3. Applicare la configurazione Terraform:

    terraform apply

    Conferma di voler applicare le azioni descritte inserendo yes. Apri il tuo progetto Google Cloud per vedere se le risorse indicate sopra sono state applicate.

  4. Per rimuovere le risorse applicate con Terraform:

    terraform destroy

    Anche in questo caso, conferma di voler applicare le azioni descritte inserendo yes.

Passaggi successivi