Utiliser gRPC

Cette page, qui présente des détails propres à Cloud Run, s'adresse aux développeurs qui souhaitent utiliser gRPC afin de connecter un service Cloud Run à d'autres services, par exemple pour fournir une communication simple et hautes performances entre des microservices internes. Avec Cloud Run, vous pouvez utiliser tous les types gRPC en streaming ou unaire.

Exemples d'utilisation possible :

  • Communication entre des microservices internes.
  • Charges de données élevées (gRPC utilise des tampons de protocole, qui sont jusqu'à sept fois plus rapides que les appels REST).
  • Seule une définition de service simple est nécessaire, vous ne souhaitez pas écrire une bibliothèque cliente complète.
  • Utilisez des gRPC en streaming sur votre serveur gRPC pour créer des applications et des API plus réactives.

Pour intégrer votre service à gRPC, procédez comme suit :

  • Configurez votre service pour qu'il utilise HTTP/2 si vous utilisez gRPC en streaming. HTTP/2 est la méthode de transport pour le streaming gRPC.
  • Définissez les messages de requête et les réponses dans un fichier proto, puis compilez-les.
  • Créez un serveur gRPC pour gérer les requêtes et renvoyer des réponses : il doit écouter la variable d'environnement PORT.
  • Créez un client qui envoie des requêtes et gère les réponses du serveur gRPC.
  • Vous pouvez éventuellement ajouter une authentification.
  • Créez et déployez votre service.

Configurer votre service pour utiliser HTTP/2

Si vous utilisez gRPC en streaming, configurez votre service pour qu'il utilise HTTP/2.

Définir et compiler des messages dans un fichier proto

Vous n'avez pas besoin d'ajouter d'éléments supplémentaires ou propres à Cloud Run dans vos définitions de proto. Comme pour toute autre utilisation de gRPC, vous utilisez des tampons de protocole gRPC pour les définitions de service et la sérialisation des données.

Créer un client gRPC

Vous n'avez pas besoin d'ajouter d'éléments supplémentaires ou propres à Cloud Run à un client qui utilise gRPC : suivez les documents gRPC sur l'utilisation des définitions de service dans le code client et les exemples de clients fournis dans les tutoriels gRPC propres aux différents langages.

Écouter des requêtes gRPC dans un service Cloud Run

La seule condition requise pour un serveur gRPC exécuté dans Cloud Run est d'écouter le port spécifié par la variable d'environnement PORT, comme indiqué dans le code :

Go

func main() {
	log.Printf("grpc-ping: starting server...")

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}

	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatalf("net.Listen: %v", err)
	}

	grpcServer := grpc.NewServer()
	pb.RegisterPingServiceServer(grpcServer, &pingService{})
	if err = grpcServer.Serve(listener); err != nil {
		log.Fatal(err)
	}
}

Ouvrir une connexion gRPC à un service

Pour ouvrir une connexion gRPC à un service afin d'envoyer des messages gRPC, vous devez spécifier le domaine hôte, qui est l'URL du service Cloud Run ou le domaine personnalisé mappé avec ce service, ainsi que le port 443, qui est le port censé être utilisé par gRPC.

Go


import (
	"crypto/tls"
	"crypto/x509"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
)

// NewConn creates a new gRPC connection.
// host should be of the form domain:port, e.g., example.com:443
func NewConn(host string, insecure bool) (*grpc.ClientConn, error) {
	var opts []grpc.DialOption
	if host != "" {
		opts = append(opts, grpc.WithAuthority(host))
	}

	if insecure {
		opts = append(opts, grpc.WithInsecure())
	} else {
		systemRoots, err := x509.SystemCertPool()
		if err != nil {
			return nil, err
		}
		cred := credentials.NewTLS(&tls.Config{
			RootCAs: systemRoots,
		})
		opts = append(opts, grpc.WithTransportCredentials(cred))
	}

	return grpc.Dial(host, opts...)
}

Envoyer des requêtes gRPC sans authentification

L'exemple suivant montre comment envoyer une requête sans authentification, à l'aide d'une connexion gRPC configurée comme indiqué précédemment.

Go


import (
	"context"
	"time"

	pb "github.com/GoogleCloudPlatform/golang-samples/run/grpc-ping/pkg/api/v1"
	"google.golang.org/grpc"
)

// pingRequest sends a new gRPC ping request to the server configured in the connection.
func pingRequest(conn *grpc.ClientConn, p *pb.Request) (*pb.Response, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	client := pb.NewPingServiceClient(conn)
	return client.Send(ctx, p)
}

Envoyer des requêtes gRPC avec authentification

L'exemple suivant montre comment utiliser l'authentification entre les services, si le service appelant dispose d'une autorisation d'appel sur le service destinataire. Notez que ce code crée un en-tête d'autorisation doté du jeton d'identité approprié : cela est obligatoire. Les autorisations requises et l'en-tête d'autorisation sont décrites en détail sur la page Authentification de service à service.

Go


import (
	"context"
	"fmt"
	"time"

	"google.golang.org/api/idtoken"
	"google.golang.org/grpc"
	grpcMetadata "google.golang.org/grpc/metadata"

	pb "github.com/GoogleCloudPlatform/golang-samples/run/grpc-ping/pkg/api/v1"
)

// pingRequestWithAuth mints a new Identity Token for each request.
// This token has a 1 hour expiry and should be reused.
// audience must be the auto-assigned URL of a Cloud Run service or HTTP Cloud Function without port number.
func pingRequestWithAuth(conn *grpc.ClientConn, p *pb.Request, audience string) (*pb.Response, error) {
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()

	// Create an identity token.
	// With a global TokenSource tokens would be reused and auto-refreshed at need.
	// A given TokenSource is specific to the audience.
	tokenSource, err := idtoken.NewTokenSource(ctx, audience)
	if err != nil {
		return nil, fmt.Errorf("idtoken.NewTokenSource: %v", err)
	}
	token, err := tokenSource.Token()
	if err != nil {
		return nil, fmt.Errorf("TokenSource.Token: %v", err)
	}

	// Add token to gRPC Request.
	ctx = grpcMetadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+token.AccessToken)

	// Send the request.
	client := pb.NewPingServiceClient(conn)
	return client.Send(ctx, p)
}

Exemple de code pour le streaming gRPC

Pour obtenir un exemple de code, reportez-vous à la mise en œuvre de RouteGuide dans le tutoriel gRPC "Principes de base" dans la langue de votre choix. Par exemple, pour Go, reportez-vous à la section Mettre en œuvre RouteGuide.