How-To: Invoke services using gRPC

    This article describe how to use Dapr to connect services using gRPC. By using Dapr’s gRPC proxying capability, you can use your existing proto based gRPC services and have the traffic go through the Dapr sidecar. Doing so yields the following Dapr Service Invocation benefits to developers:

    1. Mutual authentication
    2. Tracing
    3. Metrics
    4. Access lists
    5. Network level resiliency
    6. API token based authentication

    The following example is taken from the .

    Note this example is in Go, but applies to all programming languages supported by gRPC.

    This Go app implements the Greeter proto service and exposes a SayHello method.

    Since gRPC proxying is currently a preview feature, you need to opt-in using a configuration file. See https://docs.dapr.io/operations/configuration/preview-features/ for more information.

    1. apiVersion: dapr.io/v1alpha1
    2. kind: Configuration
    3. metadata:
    4. name: serverconfig
    5. spec:
    6. tracing:
    7. samplingRate: "1"
    8. zipkin:
    9. endpointAddress: http://localhost:9411/api/v2/spans
    10. features:
    11. - name: proxy.grpc
    12. enabled: true

    Run the sidecar and the Go server:

    1. dapr run --app-id server --app-protocol grpc --app-port 50051 --config config.yaml -- go run main.go

    The following example shows you how to discover the Greeter service using Dapr from a gRPC client. Notice that instead of invoking the target service directly at port 50051, the client is invoking its local Dapr sidecar over port 50007 which then provides all the capabilities of service invocation including service discovery, tracing, mTLS and retries.

    1. package main
    2. import (
    3. "context"
    4. "log"
    5. "time"
    6. "google.golang.org/grpc"
    7. "google.golang.org/grpc/metadata"
    8. )
    9. const (
    10. address = "localhost:50007"
    11. )
    12. func main() {
    13. // Set up a connection to the server.
    14. conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
    15. if err != nil {
    16. log.Fatalf("did not connect: %v", err)
    17. }
    18. defer conn.Close()
    19. c := pb.NewGreeterClient(conn)
    20. ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
    21. defer cancel()
    22. ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server")
    23. r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Darth Tyrannus"})
    24. if err != nil {
    25. log.Fatalf("could not greet: %v", err)
    26. }
    27. log.Printf("Greeting: %s", r.GetMessage())
    28. }

    The following line tells Dapr to discover and invoke an app named server:

    1. ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server")

    All languages supported by gRPC allow for adding metadata. Here are a few examples:

    1. var metadata = new Metadata
    2. {
    3. { "dapr-app-id", "server" }
    4. };
    5. var call = client.SayHello(new HelloRequest { Name = "Darth Nihilus" }, metadata);
    1. metadata = (('dapr-app-id', 'server'))
    2. response = stub.SayHello(request={ name: 'Darth Revan' }, metadata=metadata)
    1. const metadata = new grpc.Metadata();
    2. metadata.add('dapr-app-id', 'server');
    1. metadata = { 'dapr-app-id' : 'server' }
    2. response = service.sayHello({ 'name': 'Darth Bane' }, metadata)

    Run the client using the Dapr CLI

    Since gRPC proxying is currently a preview feature, you need to opt-in using a configuration file. See https://docs.dapr.io/operations/configuration/preview-features/ for more information.

    1. apiVersion: dapr.io/v1alpha1
    2. kind: Configuration
    3. metadata:
    4. name: serverconfig
    5. spec:
    6. tracing:
    7. samplingRate: "1"
    8. zipkin:
    9. endpointAddress: http://localhost:9411/api/v2/spans
    10. features:
    11. - name: proxy.grpc
    12. enabled: true
    1. dapr run --app-id client --dapr-grpc-port 50007 --config config.yaml -- go run main.go

    If you’re running Dapr locally with Zipkin installed, open the browser at http://localhost:9411 and view the traces between the client and server.

    Step 1: Apply the following configuration YAML using kubectl

    1. apiVersion: dapr.io/v1alpha1
    2. kind: Configuration
    3. metadata:
    4. name: serverconfig
    5. spec:
    6. tracing:
    7. samplingRate: "1"
    8. zipkin:
    9. endpointAddress: http://localhost:9411/api/v2/spans
    10. features:
    11. - name: proxy.grpc
    12. enabled: true
    1. kubectl apply -f config.yaml

    If your app uses an SSL connection, you can tell Dapr to invoke your app over an insecure SSL connection with the app-ssl: "true" annotation (full list here)

    Namespaces

    When running on namespace supported platforms, you include the namespace of the target app in the app ID:

    For example, invoking the gRPC server on a different namespace:

    1. ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server.production")

    See the for more information on namespaces.

    The example above showed you how to directly invoke a different service running locally or in Kubernetes. Dapr outputs metrics, tracing and logging information allowing you to visualize a call graph between services, log errors and optionally log the payload body.

    For more information on tracing and logs see the observability article.