Activa desde un envío de Pub/Sub

En esta página, se describe el uso de Pub/Sub para enviar mensajes al extremo del servicio de Cloud Run, en el que, luego, se entregan los mensajes a los contenedores como solicitudes HTTP. En esta página, se muestra cómo habilitar el servicio para procesar de manera segura los mensajes enviados desde una suscripción de Pub/Sub en el mismo proyecto de Google Cloud.

Si aprovechas las cuentas de servicio y los permisos de IAM, puedes usar Pub/Sub de manera segura y privada con Cloud Run sin tener que exponer el servicio de Cloud Run de forma pública. Solo la suscripción de Pub/Sub que configuraste puede invocar el servicio.

Plazos de confirmación para Cloud Run

Asegúrate de establecer el plazo de confirmación de suscripción (ackDeadlineSeconds) de Pub/Sub al máximo permitido de 600 segundos. Tu servicio de Cloud Run debe confirmar el mensaje de Pub/Sub mediante una respuesta dentro de los 600 segundos siguientes, de lo contrario, Pub/Sub volverá a enviar el mensaje y generará una activación duplicada del servicio de Cloud Run.

Casos de uso

Entre los casos prácticos se incluyen los siguientes:

Descripción general de la integración

Para integrar el servicio a Pub/Sub, realiza las siguientes acciones:

  • Crea un tema de Pub/Sub.
  • Agrega código en el servicio de Cloud Run para responder a los mensajes de Pub/Sub que se enviaron al tema que creaste.
  • Crea una cuenta de servicio con los permisos necesarios.
  • Crea una suscripción de Pub/Sub y asóciala con la cuenta de servicio. Esta suscripción enviará al servicio cualquier mensaje que se publique en el tema.

Antes de comenzar

Agrega código para administrar mensajes de Pub/Sub

Edita el código del servicio existente para agregar el código necesario a fin de admitir Pub/Sub. El servicio debe extraer el mensaje de la solicitud y mostrar un código de éxito esperado. En los siguientes fragmentos para los lenguajes seleccionados (puedes usar cualquier lenguaje), se muestra cómo hacerlo para un mensaje simple de 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():
    """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)

Comienza a usarlo


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

Debes codificar el servicio para mostrar un código de respuesta HTTP preciso. Los códigos de éxito, como HTTP 200204, confirman la recepción del procesamiento completo del mensaje de Pub/Sub. Los códigos de error, como HTTP 400500, indican que se volverá a intentar con el mensaje, como se describe en Recibe mensajes mediante suscripciones de envío.

Compila y, luego, implementa el servicio de Cloud Run después de actualizarlo con el código de Pub/Sub anterior.

Crea una cuenta de servicio para la suscripción

Debes crear una cuenta de servicio para asociarla con la suscripción de Pub/Sub y darle permiso a fin de invocar el servicio de Cloud Run. Los mensajes de Pub/Sub enviados al servicio de Cloud Run llevarán la identidad de esta cuenta de servicio.

Puedes usar una cuenta de servicio existente para representar la identidad de la suscripción de Pub/Sub o crear una nueva.

A fin de crear una cuenta de servicio nueva y darle permiso para invocar el servicio de Cloud Run, sigue estos pasos:

Console

  1. En la consola de Google Cloud, ve a la página Cuentas de servicio.

    Ir a Cuentas de servicio

  2. Selecciona un proyecto

  3. Ingresa un nombre de cuenta de servicio para mostrar en la consola de Google Cloud.

    La consola de Google Cloud genera un ID de cuenta de servicio a partir de este nombre. Si es necesario, edita el ID. No podrás cambiar el ID más adelante.

  4. Opcional: Ingresa una descripción de la cuenta de servicio.

  5. Haz clic en Crear y continuar.

  6. Opcional: Haz clic en el campo Seleccionar una función.

  7. Selecciona Cloud Run > Invocador de Cloud Run.

  8. Haz clic en Listo.

Línea de comandos

  1. Crea la cuenta de servicio:

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

    Reemplaza los siguientes elementos:

    • SERVICE_ACCOUNT_NAME por un nombre único en minúscula dentro del proyecto de Google Cloud, por ejemplo, my-invoker-service-account-name
    • DISPLAYED_SERVICE_ACCOUNT_NAME por el nombre que deseas mostrar para esta cuenta de servicio, por ejemplo, en la consola, My Invoker Service Account
  2. En Cloud Run, debes otorgar permiso a la cuenta de servicio para invocar el servicio:

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

    Reemplaza los siguientes elementos:

    • SERVICE por el nombre del servicio que deseas que Pub/Sub invoque
    • SERVICE_ACCOUNT_NAME por el nombre de la cuenta de servicio
    • PROJECT_ID por el ID del proyecto de Google Cloud.
  3. Otórgale a tu cuenta de servicio acceso al proyecto para que tenga el permiso de completar acciones específicas en los recursos de tu proyecto.

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

    Reemplaza los siguientes elementos:

    • RESOURCE_ID es el ID del proyecto de Google Cloud.

    • PRINCIPAL: Un identificador para la principal o el miembro, que suele tener el siguiente formato: PRINCIPAL_TYPE:ID. Por ejemplo, user:my-user@example.com Si deseas obtener una lista completa de los valores que PRINCIPAL puede tener, consulta la referencia sobre la vinculación de políticas.

Terraform

Si deseas obtener más información para aplicar o quitar una configuración de Terraform, consulta los comandos básicos de Terraform.

  1. Para crear una cuenta de servicio, agrega lo siguiente al archivo .tf existente:

    resource "google_service_account" "sa" {
      account_id   = "cloud-run-pubsub-invoker"
      display_name = "Cloud Run Pub/Sub Invoker"
    }
  2. A fin de otorgar permiso a tu cuenta de servicio para invocar el servicio, agrega lo siguiente al archivo .tf existente:

    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}"]
    }

Crea un tema de Pub/Sub

Las solicitudes al servicio se activan mediante mensajes publicados en un tema de Pub/Sub, por lo que deberás crear uno:

Console

  1. Visita la página de temas de Pub/Sub en la consola de Google Cloud.

    Página Temas de Pub/Sub

  2. Haz clic en Crear un tema.

  3. Ingresa un Nombre único para tu tema, por ejemplo, MyTopic.

Línea de comandos

gcloud pubsub topics create TOPIC-NAME

Reemplaza TOPIC-NAME con un nombre de tema único dentro del proyecto de Google Cloud.

Terraform

Si deseas obtener más información para aplicar o quitar una configuración de Terraform, consulta los comandos básicos de Terraform.

En esta sección, se muestra cómo usar Terraform para definir tu servicio en una configuración de Terraform mediante el recurso google_pubsub_topic del proveedor de Google Cloud Platform.

Agrega lo siguiente a tu archivo .tf:

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

Crea una suscripción de envío y asóciala con la cuenta de servicio

Después de crear el tema de Pub/Sub, debes suscribirte al servicio para recibir mensajes enviados a un tema y asociar la suscripción con la cuenta de servicio que creaste para el servicio. Puedes usar la consola de Google Cloud o la línea de comandos de gcloud:

Console

  1. Ve a la página Temas de Pub/Sub

    Página Temas de Pub/Sub

  2. Haz clic en el tema al que deseas suscribirte.

  3. Haz clic en Create a subscription (Crear una suscripción) para mostrar el formulario de suscripción:

    formulario de suscripción

    En el formulario, debes hacer lo siguiente:

    1. Especificar el tipo de entrega push (envío).
    2. Para la URL de extremos, especifica la URL del servicio, que se muestra en la página de detalles del servicio.
    3. En el menú desplegable Cuenta de servicio, selecciona la cuenta de servicio que creaste con los permisos necesarios.
    4. Establece el vencimiento de la suscripción y un plazo de confirmación de recepción de 600 segundos.
    5. Haga clic en Crear.
  4. Se completó la suscripción. Los mensajes publicados en el tema ahora se enviarán al servicio.

Línea de comandos

  1. Permite que Pub/Sub cree tokens de autenticación en el proyecto:

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

    Reemplaza los siguientes elementos:

    • PROJECT-ID por el ID del proyecto de Google Cloud
    • PROJECT-NUMBER por tu número de proyecto de Google Cloud

      El ID y el número del proyecto se enumeran en el panel Información del proyecto en la consola de Google Cloud para el proyecto.

  2. Crea una suscripción de Pub/Sub con la cuenta de servicio que creaste con los permisos necesarios:

    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

    Reemplaza los siguientes elementos:

    • TOPIC-NAME por el tema que creaste antes
    • SERVICE-URL por la URL HTTPS que se proporcionó cuando implementaste el servicio. Puedes encontrarla mediante el comando gcloud run services describe y la especificación del nombre del servicio; busca la línea del resultado que comienza con domain
    • PROJECT-ID por el ID del proyecto de Google Cloud

    La marca --push-auth-service-account activa las funciones de envío de Pub/Sub para la autenticación y la autorización.

    Ten en cuenta que el plazo de confirmación se establece en el máximo de 600 segundos.

  3. Se completó la suscripción. Los mensajes publicados en el tema ahora se enviarán al servicio. Puedes enviar un mensaje de prueba al tema mediante el siguiente comando:

    gcloud pubsub topics publish TOPIC --message "hello"

    Reemplaza TOPIC por el nombre del tema que creaste.

Terraform

Si deseas obtener más información para aplicar o quitar una configuración de Terraform, consulta los comandos básicos de Terraform.

  1. Permite que Pub/Sub cree tokens de autenticación en el proyecto. Agrega lo siguiente a tu archivo .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. Crea una suscripción de Pub/Sub con la cuenta de servicio que creaste con los permisos necesarios. Agrega lo siguiente a tu archivo .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. Se completó la suscripción. Los mensajes publicados en el tema ahora se enviarán al servicio. Puedes enviar un mensaje de prueba al tema mediante el siguiente comando:

    gcloud pubsub topics publish TOPIC --message "hello"

    Reemplaza TOPIC por el nombre del tema que creaste.

¿Qué sigue?