Stay organized with collections Save and categorize content based on your preferences.

Set up proxyless gRPC services

This guide demonstrates how to set up a proxyless gRPC service mesh with Mesh and GRPCRoute resources.

Proxyless gRPC services with GRPCRoute and Mesh resources
Proxyless gRPC services with GRPCRoute and Mesh resources (click to enlarge)

Before you begin

Make sure that your deployment meets the prerequisites described in the following guides:

Configure the Mesh resource

When a proxyless gRPC application connects to an xds://hostname, the gRPC client library establishes a connection to Traffic Director. The client library uses the connection to obtain the routing configuration that is needed to route requests for the hostname.

Make sure that you note the name of the Mesh resource, which is the key that the proxyless gRPC application uses to request the configuration associated with this Mesh.

  1. Create the Mesh specification and save it in a file called mesh.yaml.

    name: grpc-mesh
    
  2. Create the Mesh resource using the mesh.yaml specification:

    gcloud network-services meshes import grpc-mesh \
      --source=mesh.yaml \
      --location=global
    

After the Mesh resource is created, Traffic Director is ready to serve the configuration, but because there are no services defined yet, the configuration is empty. In the next section, you define the services and attach them to the Mesh resource.

Configure the gRPC server

For demonstration purposes, you create a backend service with autoscaled VMs in a managed instance group. The VMs serve the phrase hello world using the gRPC protocol on port 50051.

  1. Create the Compute Engine VM instance template with a helloworld gRPC service that is exposed on port 50051:

    gcloud compute instance-templates create grpc-td-vm-template \
       --scopes=https://www.googleapis.com/auth/cloud-platform \
       --tags=allow-health-checks \
       --image-family=debian-10 \
       --image-project=debian-cloud \
       --metadata-from-file=startup-script=<(echo '#! /bin/bash
     set -e
     cd /root
     sudo apt-get update -y
     sudo apt-get install -y openjdk-11-jdk-headless
     curl -L https://github.com/grpc/grpc-java/archive/v1.38.0.tar.gz | tar -xz
     cd grpc-java-1.38.0/examples/example-hostname
     ../gradlew --no-daemon installDist
     sudo systemd-run ./build/install/hostname-server/bin/hostname-server')
     
  2. Create a managed instance group based on the template:

    gcloud compute instance-groups managed create grpc-td-mig-us-east1 \
      --zone=ZONE \
      --size=2 \
      --template=grpc-td-vm-template
    
  3. Create the named port for the gRPC service. The named port is the port on which the gRPC service listens for requests. In the following example, the named port is 50051:

    gcloud compute instance-groups set-named-ports grpc-td-mig-us-east1 \
     --named-ports=grpc-helloworld-port:50051 \
     --zone=ZONE
    
  4. Create a gRPC health check. The services must implement the gRPC health checking protocol so that gRPC health checks work properly. For more information, see health checks.

    gcloud compute health-checks create grpc grpc-helloworld-health-check \
      --use-serving-port
    
  5. Create a firewall rule to allow health check connections to instances in your network:

    gcloud compute firewall-rules create grpc-vm-allow-health-checks \
      --network=default \
      --action=ALLOW \
      --direction=INGRESS \
      --source-ranges=35.191.0.0/16,130.211.0.0/22 \
      --target-tags allow-health-checks \
      --rules=tcp:50051
    
  6. Create a global backend service with a load balancing scheme of INTERNAL_SELF_MANAGED and add the health check to the backend service. The port specified here is used to connect to the VMs in the managed instance group.

    gcloud compute backend-services create grpc-helloworld-service \
      --global \
      --load-balancing-scheme=INTERNAL_SELF_MANAGED \
      --protocol=GRPC \
      --port-name=grpc-helloworld-port \
      --health-checks grpc-helloworld-health-check
    
  7. Add the managed instance group to the backend service.

    gcloud compute backend-services add-backend \
      grpc-helloworld-service \
      --instance-group=grpc-td-mig-us-east1
      --instance-group-zone=ZONE \
      --global
    

The Mesh resource and services are configured. In the next section, you set up routing.

Set up routing with GRPCRoute

The Mesh resource and gRPC server are configured. Use the following instructions to set up routing.

  1. Create the GRPCRoute specification and save it in a file called grpc_route.yaml.

    You can use either PROJECT_ID or PROJECT_NUMBER.

    name: helloworld-grpc-route
    hostnames:
    - helloworld-gce
    meshes:
    - projects/PROJECT_NUMBER/locations/global/meshes/grpc-mesh
    rules:
    - action:
        destinations:
        - serviceName: projects/PROJECT_NUMBER/locations/global/backendServices/grpc-helloworld-service
    
  2. Create the GrpcRoute resource using the grpc_route.yaml specification:

    gcloud network-services grpc-routes import helloworld-grpc-route \
      --source=grpc_route.yaml \
      --location=global
    

Traffic Director is now configured to load balance traffic for the services specified in the GRPCRoute resource across backends in the managed instance group.

Create a gRPC client

You can verify the configuration by instantiating a proxyless gRPC application and connecting it to Traffic Director. In its bootstrap file, the application must specify the VPC network indicated in the Mesh.

After it is configured, the application can send a request to the instances or endpoints associated with helloworld-gce using the xds:///helloworld-gce service URI.

In the following examples, you use the grpcurl tool to test the gRPC service.

  1. Create a client VM.

    gcloud compute instances create grpc-client \
      --zone=ZONE\
      --scopes=https://www.googleapis.com/auth/cloud-platform \
      --image-family=debian-10 \
      --image-project=debian-cloud \
      --metadata-from-file=startup-script=<(echo '#! /bin/bash
    set -e
    export GRPC_XDS_BOOTSTRAP=/run/td-grpc-bootstrap.json
    echo export GRPC_XDS_BOOTSTRAP=$GRPC_XDS_BOOTSTRAP | sudo tee /etc/profile.d/grpc-xds-bootstrap.sh
    curl -L https://storage.googleapis.com/traffic-director/td-grpc-bootstrap-0.14.0.tar.gz | tar -xz
    ./td-grpc-bootstrap-0.14.0/td-grpc-bootstrap --config-mesh-experimental grpc-mesh | tee $GRPC_XDS_BOOTSTRAP')
    

Set up the bootstrap file

The client application must have a bootstrap configuration file. The startup script in the previous section sets the GRPC_XDS_BOOTSTRAP environment variable and uses a helper script to generate the bootstrap file. The values for TRAFFICDIRECTOR_GCP_PROJECT_NUMBER and zone in the generated bootstrap file are obtained from the metadata server that knows these details about your VM instances. You can provide these values to the helper script manually using the --gcp-project-number option. You must provide a mesh name matching the Mesh resource using the --config-mesh-experimental option.

To verify the configuration, log in to the client VM and run the following.

  1. SSH to the client VM.

    gcloud compute ssh grpc-client
    
  2. Download and install the grpcurl tool.

    curl -L https://github.com/fullstorydev/grpcurl/releases/download/v1.8.1/grpcurl_1.8.1_linux_x86_64.tar.gz | tar -xz
    
  3. Run the grpcurl tool with xds:///helloworld-gce as the service URI and helloworld.Greeter/SayHello as the service name and method to invoke. The parameters to the SayHello method are passed using the -d option.

    ./grpcurl --plaintext \
      -d '{"name": "world"}' \
      xds:///helloworld-gce helloworld.Greeter/SayHello
    

You should see output similar to the following, where INSTANCE_HOSTNAME is the name of the VM instance:

   Greeting: Hello world, from INSTANCE_HOSTNAME
   

The output verifies that the proxyless gRPC client successfully connected to Traffic Director and learned about the backends for the helloworld-gce service using the xds name resolver. The client sent a request to one of the service's backends without needing to know about the IP address or performing DNS resolution.