Pub/Sub mit Cloud Run for Anthos in Google Cloud verwenden

In dieser Anleitung wird gezeigt, wie Sie einen Cloud Run for Anthos-Dienst in Google Cloud über ein Pub/Sub-Push-Abo schreiben, bereitstellen und aufrufen.

Ziele

  • Dienst für Cloud Run for Anthos in Google Cloud schreiben, erstellen und bereitstellen
  • Eine Nachricht in einem Pub/Sub-Thema veröffentlichen, um den Dienst aufzurufen

Kosten

In dieser Anleitung werden kostenpflichtige Komponenten von Google Cloud verwendet, darunter:

Sie können mithilfe des Preisrechners eine Kostenschätzung für Ihre voraussichtliche Nutzung erstellen.

Neuen Google Cloud-Nutzern steht möglicherweise eine kostenlose Testversion zur Verfügung.

Hinweis

  1. Melden Sie sich bei Ihrem Google-Konto an.

    Wenn Sie noch kein Konto haben, melden Sie sich hier für ein neues Konto an.

  2. Wählen Sie in der Google Cloud Console auf der Seite der Projektauswahl ein Google Cloud-Projekt aus oder erstellen Sie eines.

    Zur Projektauswahl

  3. Die Abrechnung für das Cloud-Projekt muss aktiviert sein. So prüfen Sie, ob die Abrechnung für Ihr Projekt aktiviert ist.

  4. Cloud Run for Anthos in Google Cloud API aktivieren
  5. Installieren und initialisieren Sie das Cloud SDK.
  6. Installieren Sie die Komponente kubectl:
    gcloud components install kubectl
  7. Installieren Sie die Komponente beta:
    gcloud components install beta
  8. Aktualisieren Sie die Komponenten:
    gcloud components update
  9. Wenn Sie Cloud Run for Anthos in Google Cloud verwenden, erstellen Sie mithilfe der Anleitung unter Cloud Run for Anthos in Google Cloud einrichten einen neuen Cluster.

gcloud-Standardeinstellungen einrichten

So konfigurieren Sie gcloud mit Standardeinstellungen für Ihren Cloud Run for Anthos-Dienst in Google Cloud:

  1. Legen Sie ein Standardprojekt fest:

    gcloud config set project PROJECT_ID

    Ersetzen Sie PROJECT_ID durch den Namen des Projekts, das Sie für diese Anleitung verwenden.

  2. Konfigurieren Sie gcloud für Ihren Cluster:

    gcloud config set kuberun/cluster CLUSTER-NAME
    gcloud config set kuberun/cluster_location REGION

    Ersetzen Sie

    • CLUSTER-NAME durch den Namen, den Sie für den Cluster verwendet haben, und
    • REGION durch den unterstützten Clusterstandort Ihrer Wahl.

Pub/Sub-Thema erstellen

Der Beispieldienst wird durch Nachrichten ausgelöst, die in einem Pub/Sub-Thema veröffentlicht werden. Daher müssen Sie in Pub/Sub ein Thema erstellen.

Verwenden Sie den folgenden Befehl, um ein neues Pub/Sub-Thema zu erstellen:

gcloud pubsub topics create myRunTopic

Sie können myRunTopic verwenden oder durch einen Themennamen ersetzen, der in Ihrem Cloud-Projekt eindeutig ist.

Codebeispiel abrufen

So rufen Sie das gewünschte Codebeispiel ab:

  1. Klonen Sie das Repository der Beispiel-App auf Ihren lokalen Computer:

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Go

    git clone https://github.com/GoogleCloudPlatform/golang-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    Sie können auch das Beispiel als ZIP-Datei herunterladen und extrahieren.

  2. Wechseln Sie in das Verzeichnis, das den Beispielcode für Cloud Run for Anthos in Google Cloud enthält:

    Node.js

    cd nodejs-docs-samples/kuberun/pubsub/

    Python

    cd python-docs-samples/kuberun/pubsub/

    Go

    cd golang-samples/kuberun/pubsub/

    Java

    cd java-docs-samples/kuberun/pubsub/

Codebeispiel

Der Code dieser Anleitung besteht aus folgenden Elementen:

  • Einem Server, der eingehende Anfragen verarbeitet.

    Node.js

    Für einen einfacheren Test des Dienstes Node.js ist die Serverkonfiguration vom Serverstart getrennt.

    Der Node.js-Webserver wird in app.js eingerichtet.

    const express = require('express');
    const bodyParser = require('body-parser');
    const app = express();
    
    app.use(bodyParser.json());
    Der Webserver wird in index.js gestartet:
    const app = require('./app.js');
    const PORT = process.env.PORT || 8080;
    
    app.listen(PORT, () =>
      console.log(`nodejs-pubsub-tutorial listening on port ${PORT}`)
    );

    Python

    import base64
    import os
    
    from flask import Flask, request
    
    app = Flask(__name__)

    Go

    
    // Sample pubsub is a KubeRun service which handles Pub/Sub messages.
    package main
    
    import (
    	"encoding/json"
    	"io/ioutil"
    	"log"
    	"net/http"
    	"os"
    )
    
    func main() {
    	http.HandleFunc("/", HelloPubSub)
    	// Determine port for HTTP service.
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "8080"
    		log.Printf("Defaulting to port %s", port)
    	}
    	// Start HTTP server.
    	log.Printf("Listening on port %s", port)
    	if err := http.ListenAndServe(":"+port, nil); err != nil {
    		log.Fatal(err)
    	}
    }
    

    Java

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class PubSubApplication {
      public static void main(String[] args) {
        SpringApplication.run(PubSubApplication.class, args);
      }
    }

  • Ein Handler, der die Pub/Sub-Nachricht verarbeitet und ein Greeting protokolliert.

    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)

    Go

    
    // PubSubMessage is the payload of a Pub/Sub event.
    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 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);
      }
    }

    Sie müssen den Dienst so programmieren, dass ein genauer HTTP-Antwortcode zurückgegeben wird. Erfolgscodes wie HTTP 200 oder 204 bestätigen die vollständige Verarbeitung der Pub/Sub-Nachricht. Fehlercodes wie HTTP 400 oder 500 zeigen an, dass der Versand der Nachricht noch einmal versucht wird. Weitere Informationen finden Sie unter Nachrichten mit Push empfangen.

  • Einem Dockerfile, das die Betriebsumgebung für den Dienst definiert. Der Inhalt des Dockerfile variiert je nach Sprache.

    Node.js

    
    # Use the official lightweight Node.js 10 image.
    # https://hub.docker.com/_/node
    FROM node:12-slim
    
    # Create and change to the app directory.
    WORKDIR /usr/src/app
    
    # Copy application dependency manifests to the container image.
    # A wildcard is used to ensure both package.json AND package-lock.json are copied.
    # Copying this separately prevents re-running npm install on every code change.
    COPY package*.json ./
    
    # Install dependencies.
    # If you add a package-lock.json speed your build by switching to 'npm ci'.
    # RUN npm ci --only=production
    RUN npm install --production
    
    # Copy local code to the container image.
    COPY . .
    
    # Run the web service on container startup.
    CMD [ "npm", "start" ]
    

    Python

    
    # Use the official Python image.
    # https://hub.docker.com/_/python
    FROM python:3.9
    
    # Allow statements and log messages to immediately appear in the KubeRun logs
    ENV PYTHONUNBUFFERED True
    
    # Copy application dependency manifests to the container image.
    # Copying this separately prevents re-running pip install on every code change.
    COPY requirements.txt ./
    
    # Install production dependencies.
    RUN pip install -r requirements.txt
    
    # Copy local code to the container image.
    ENV APP_HOME /app
    WORKDIR $APP_HOME
    COPY . ./
    
    # Run the web service on container startup.
    # Use gunicorn webserver with one worker process and 8 threads.
    # For environments with multiple CPU cores, increase the number of workers
    # to be equal to the cores available.
    CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
    

    Go

    
    # Use the offical golang image to create a binary.
    # This is based on Debian and sets the GOPATH to /go.
    # https://hub.docker.com/_/golang
    FROM golang:1.15-buster as builder
    
    # Create and change to the app directory.
    WORKDIR /app
    
    # Retrieve application dependencies.
    # This allows the container build to reuse cached dependencies.
    # Expecting to copy go.mod and if present go.sum.
    COPY go.* ./
    RUN go mod download
    
    # Copy local code to the container image.
    COPY . ./
    
    # Build the binary.
    RUN go build -mod=readonly -v -o server
    
    # Use the official Debian slim image for a lean production container.
    # https://hub.docker.com/_/debian
    # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
    FROM debian:buster-slim
    RUN set -x && apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
        ca-certificates && \
        rm -rf /var/lib/apt/lists/*
    
    # Copy the binary to the production image from the builder stage.
    COPY --from=builder /app/server /server
    
    # Run the web service on container startup.
    CMD ["/server"]
    

    Java

    In diesem Beispiel wird Jib verwendet, um Docker-Images mit gängigen Java-Tools zu erstellen. Jib optimiert Container-Builds, ohne dass ein Dockerfile erforderlich ist oder Docker installiert sein muss. Weitere Informationen zum Erstellen von Java-Containern mit Jib
    <plugin>
      <groupId>com.google.cloud.tools</groupId>
      <artifactId>jib-maven-plugin</artifactId>
      <version>2.7.0</version>
      <configuration>
        <to>
          <image>gcr.io/PROJECT_ID/pubsub</image>
        </to>
      </configuration>
    </plugin>
    

Weitere Informationen dazu, wie Sie den Ursprung von Cloud Pub/Sub-Anfragen authentifizieren können, finden Sie unten im Abschnitt In Pub/Sub integrieren.

Code versenden

Das Versenden von Code besteht aus drei Schritten: Erstellen eines Container-Images mit Cloud Build, Hochladen des Container-Images in Container Registry und Bereitstellen des Container-Images in Cloud Run for Anthos in Google Cloud.

So versenden Sie den Code:

  1. Erstellen Sie einen Container und veröffentlichen Sie ihn in Container Registry.

    Node.js

    gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub

    Dabei ist PROJECT_ID Ihre Cloud-Projekt-ID und pubsub der Name, den Sie dem Dienst geben möchten.

    Bei Erfolg sollte eine Bestätigungsmeldung mit der ID, der Erstellungszeit und dem Image-Namen angezeigt werden. Das Image wird in Container Registry gespeichert und kann bei Bedarf wiederverwendet werden.

    Python

    gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub

    Dabei ist PROJECT_ID Ihre Cloud-Projekt-ID und pubsub der Name, den Sie dem Dienst geben möchten.

    Bei Erfolg sollte eine Bestätigungsmeldung mit der ID, der Erstellungszeit und dem Image-Namen angezeigt werden. Das Image wird in Container Registry gespeichert und kann bei Bedarf wiederverwendet werden.

    Go

    gcloud builds submit --tag gcr.io/PROJECT_ID/pubsub

    Dabei ist PROJECT_ID Ihre Cloud-Projekt-ID und pubsub der Name, den Sie dem Dienst geben möchten.

    Bei Erfolg sollte eine Bestätigungsmeldung mit der ID, der Erstellungszeit und dem Image-Namen angezeigt werden. Das Image wird in Container Registry gespeichert und kann bei Bedarf wiederverwendet werden.

    Java

    mvn compile jib:build -Dimage=gcr.io/PROJECT_ID/pubsub

    Dabei ist PROJECT_ID Ihre Cloud-Projekt-ID und pubsub der Name, den Sie dem Dienst geben möchten.

    Bei Erfolg sollte die Nachricht „BUILD SUCCESS“ angezeigt werden. Das Image wird in Container Registry gespeichert und kann bei Bedarf wiederverwendet werden.

  2. Stellen Sie die Anwendung mit dem folgenden Befehl bereit:

    gcloud kuberun core services create pubsub-tutorial --image gcr.io/PROJECT_ID/pubsub

    Ersetzen Sie PROJECT_ID durch Ihre Cloud-Projekt-ID. pubsub ist der Containername und pubsub-tutorial der Name des Dienstes. Das Container-Image wird für den Dienst und den Cluster bereitgestellt, den Sie zuvor unter gcloud-Standardeinstellungen einrichten konfiguriert haben.

    Warten Sie, bis die Bereitstellung abgeschlossen ist. Dies kann ungefähr eine halbe Minute dauern. Bei Erfolg wird in der Befehlszeile die Dienst-URL angezeigt. Diese URL wird zum Konfigurieren eines Pub/Sub-Abos verwendet.

  3. Wenn Sie eine Codeaktualisierung für den Dienst bereitstellen möchten, wiederholen Sie die vorherigen Schritte. Bei jeder Bereitstellung für einen Dienst wird eine neue Version erstellt und der Traffic wird automatisch verarbeitet, sobald der Dienst bereit ist.

In Pub/Sub integrieren

Nach der Bereitstellung des Dienstes in Cloud Run for Anthos in Google Cloud konfigurieren Sie Pub/Sub so, dass Nachrichten per Push an den Dienst übertragen werden.

So integrieren Sie den Dienst in Pub/Sub:

  1. Aktivieren Sie Pub/Sub, um Authentifizierungstokens in Ihrem Projekt zu erstellen:

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

    Ersetzen Sie

    • PROJECT_ID durch Ihre Cloud-Projekt-ID.
    • PROJECT-NUMBER durch Ihre Cloud-Projektnummer.
  2. Erstellen oder wählen Sie ein Dienstkonto, das die Pub/Sub-Abo-Identität darstellen soll.

    gcloud iam service-accounts create kuberun-pubsub-invoker \
         --display-name "KubeRun Pub/Sub Invoker"

    Sie können kuberun-pubsub-invoker verwenden oder durch einen Namen ersetzen, der in Ihrem Cloud-Projekt eindeutig ist.

  3. Erstellen Sie ein Pub/Sub-Abo mit dem Dienstkonto:

    1. Aktivieren Sie Auto-TLS und HTTPS für Ihren Cluster und fügen Sie Ihrem Dienst eine Domainzuordnung hinzu.

    2. Registrieren Sie die Domaininhaberschaft für Pub/Sub.

    3. Fügen Sie Code hinzu, um das Authentifizierungstoken zu validieren, das an Pub/Sub-Nachrichten angehängt ist. Beispielcode finden Sie unter Authentifizierung und Autorisierung durch den Push-Endpunkt.

      Mit der Authentifizierung wird geprüft, ob das Token gültig ist und mit dem erwarteten Dienstkonto verknüpft ist. Im Gegensatz zu Cloud Run (vollständig verwaltet) hat Cloud Run for Anthos in Google Cloud keine integrierte Autorisierungsprüfung, die feststellt, ob das Token gültig ist oder ob das Dienstkonto berechtigt ist, Cloud Run for Anthos in Google Cloud aufzurufen.

    4. Erstellen Sie ein Pub/Sub-Abo mit dem Dienstkonto:

      gcloud pubsub subscriptions create myRunSubscription --topic myRunTopic \
           --push-endpoint=SERVICE-URL/ \
           --push-auth-service-account=kuberun-pubsub-invoker@PROJECT_ID.iam.gserviceaccount.com

      Ersetzen Sie

      • myRunTopic durch das zuvor erstellte Thema.
      • SERVICE-URL durch Ihre benutzerdefinierte Dienst-URL. Geben Sie https als Protokoll an.
      • PROJECT_ID durch Ihre Cloud-Projekt-ID.

      Das Flag --push-auth-service-account aktiviert die Pub/Sub-Push-Funktion für die Authentifizierung und Autorisierung.

Ihr Dienst ist jetzt vollständig in Pub/Sub integriert.

Testen

So testen Sie die durchgängige Lösung:

  1. Senden Sie eine Pub/Sub-Nachricht an das Thema:

    gcloud pubsub topics publish myRunTopic --message "Runner"

    Anstatt über die in dieser Anleitung beschriebene Befehlszeile können Sie Nachrichten auch programmatisch veröffentlichen. Weitere Informationen finden Sie unter Nachrichten veröffentlichen.

  2. Rufen Sie die Dienstlogs auf:

    1. Öffnen Sie die Google Cloud Console:
    2. Klicken Sie auf den Dienst pubsub-tutorial.
    3. Wählen Sie den Tab Logs aus.

      Es kann einige Momente dauern, bis Logs angezeigt werden. Falls sie nicht sofort angezeigt werden, warten Sie kurz ab und sehen Sie dann noch einmal nach.

  3. Suchen Sie nach der Nachricht „Hello Runner!“.

Bereinigen

Wenn Sie einen Anwendungsfall durchgehen möchten, in dem die Verwendung von Pub/Sub mit Cloud Run for Anthos in Google Cloud ausführlicher beschrieben wird, überspringen Sie vorerst die Bereinigung und fahren mit der Anleitung Bildverarbeitung fort.

Wenn Sie ein neues Projekt für diese Anleitung erstellt haben, löschen Sie das Projekt. Wenn Sie ein vorhandenes Projekt verwendet haben und es beibehalten möchten, ohne die Änderungen in dieser Anleitung hinzuzufügen, löschen Sie die für die Anleitung erstellten Ressourcen.

Projekt löschen

Am einfachsten vermeiden Sie weitere Kosten, wenn Sie das zum Ausführen der Anleitung erstellte Projekt löschen.

So löschen Sie das Projekt:

  1. Wechseln Sie in der Cloud Console zur Seite Ressourcen verwalten.

    Zur Seite „Ressourcen verwalten“

  2. Wählen Sie in der Projektliste das Projekt aus, das Sie löschen möchten, und klicken Sie dann auf Löschen.
  3. Geben Sie im Dialogfeld die Projekt-ID ein und klicken Sie auf Shut down (Beenden), um das Projekt zu löschen.

Anleitungsressourcen löschen

  1. Löschen Sie den Cloud Run for Anthos in Google Cloud-Dienst, den Sie in dieser Anleitung bereitgestellt haben:

    gcloud kuberun core services delete SERVICE-NAME

    Dabei ist SERVICE-NAME der von Ihnen ausgewählte Dienstname.

    Sie können Cloud Run for Anthos in Google Cloud-Dienste auch über die Google Cloud Console löschen.

  2. Entfernen Sie die gcloud-Standardkonfigurationen, die Sie während der Einrichtung der Anleitung hinzugefügt haben.

     gcloud config unset kuberun/cluster
     gcloud config unset kuberun/cluster_location
    
  3. Entfernen Sie die Projektkonfiguration:

     gcloud config unset project
    
  4. Löschen Sie sonstige Google Cloud-Ressourcen, die in dieser Anleitung erstellt wurden:

Weitere Informationen