Set up a proxyless gRPC service mesh

This guide demonstrates how to configure a proxyless gRPC service mesh.

The configuration is supported for Preview customers but we do not recommended it for new Cloud Service Mesh users. For more information, see the Cloud Service Mesh overview.

Before you begin

Do not create a proxyless gRPC service mesh in a namespace where Envoy sidecar auto-injection is enabled. To determine whether sidecar injection is enabled, run the following command:

kubectl get namespace default --show-labels

If sidecar auto-injection is enabled, run this command to remove the label:

kubectl label namespace default istio-injection-

Deploy a gRPC service

In this section, you deploy a gRPC helloworld example service. The helloworld example service is a gRPC server application that returns a simple message in response to a gRPC client's request. The helloworld service exposes the gRPC service on port 8080 in the cluster.

  1. In the grpc-td-helloworld.yaml file, save the following:

    apiVersion: v1
    kind: Service
    metadata:
      name: helloworld
      namespace: default
    spec:
      ports:
      - port: 8080
        name: helloworld
        protocol: TCP
        targetPort: 50051
      selector:
        run: app1
      type: ClusterIP
    
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        run: app1
      name: app1
      namespace: default
    spec:
      selector:
        matchLabels:
          run: app1
      replicas: 2
      template:
        metadata:
          labels:
            run: app1
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          containers:
          - image: grpc/java-example-hostname:1.37.0
            name: app1
            ports:
            - protocol: TCP
              containerPort: 50051
    
  2. Apply the file grpc-td-helloworld.yaml:

    kubectl apply -f grpc-td-helloworld.yaml
    
  3. Verify that the new helloworld service is created:

    kubectl get svc -n default
    

    The output is similar to the following:

    NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT (S)   AGE
    helloworld     ClusterIP   10.71.9.71   <none>        8080/TCP  41m
    [..skip..]
    
  4. Verify that the application Pod is running:

    kubectl get pods -n default
    
  5. The output Pods should be similar to the following:

    NAME                        READY     STATUS    RESTARTS   AGE
    app1-6db459dcb9-zvfg2   1/1       Running   0          6m
    app1-6db459dcb9-hlvhj   1/1       Running   0          6m
    [..skip..]
    

Configure a gRPC service mesh

In this section, you configure a simple gRPC service mesh.

  1. In the file td-grpc-mesh.yaml, save the following mesh manifest:

    kind: TDMesh
    apiVersion: net.gke.io/v1alpha1
    metadata:
      name: td-grpc-mesh
      namespace: default
    spec:
      gatewayClassName: gke-td
      allowedRoutes:
        namespaces:
          from: All
        kinds:
        - group: net.gke.io
          kind: TDGRPCRoute
    
  2. Apply the mesh manifest to gke-1:

    kubectl apply -f td-grpc-mesh.yaml
    

    The example TDMesh allows only TDGRPCRoute resources to be attached to it. The manifest defines which types of route are allowed.

  3. Verify that the new td-grpc-mesh mesh is created:

    kubectl describe tdmesh td-grpc-mesh -n default
    

    The output is similar to the following:

    ...
    Status:
      Conditions:
        Last Transition Time:  2022-04-14T22:22:09Z
        Message:
        Reason:                MeshReady
        Status:                True
        Type:                  Ready
        Last Transition Time:  2022-04-14T22:21:41Z
        Message:
        Reason:                Scheduled
        Status:                True
        Type:                  Scheduled
    Events:
      Type    Reason  Age   From                Message
      ----    ------  ----  ----                -------
      Normal  ADD     79s   mc-mesh-controller  Processing mesh default/td-grpc-mesh
      Normal  UPDATE  79s   mc-mesh-controller  Processing mesh default/td-grpc-mesh
      Normal  SYNC    50s   mc-mesh-controller  SYNC on default/td-grpc-mesh was a success
    
  4. In the file helloworld-route.yaml, save the following manifest:

    kind: TDGRPCRoute
    apiVersion: net.gke.io/v1alpha1
    metadata:
      name: helloworld-route
      namespace: default
    spec:
      parentRefs:
      - name: td-grpc-mesh
        namespace: default
        group: net.gke.io
        kind: TDMesh
      hostnames:
      - helloworld
      rules:
      - backendRefs:
        - name: helloworld
          port: 8080
          namespace: default
    
  5. Apply the helloworld-route.yaml manifest to gke-1:

    kubectl apply -f helloworld-route.yaml
    
  6. Verify that the new helloworld-route GRPCRoute resource is created:

    kubectl get tdgrpcroute -n default
    

Verify the configuration

When the configuration process is complete, verify that you can reach the helloworld gRPC server using a proxyless gRPC client. This client connects to Cloud Service Mesh, obtains information about the helloworld service, and uses this information to send traffic to the service's backends.

In the following example, you use the grpcurl tool to verify that the Cloud Service Mesh is routing traffic correctly in the mesh. You create a client Pod, then open a shell and run the verification commands from the shell.

Set up the environment variable and bootstrap file

  1. In a file grpc-client.yaml, save the following Pod manifest:

    apiVersion: v1
    kind: Pod
    metadata:
      name: static-sleeper
      namespace: default
      annotations:
        sidecar.istio.io/inject: "false"
    spec:
      containers:
      - image: curlimages/curl:7.82.0
        imagePullPolicy: IfNotPresent
        name: sleeper
        command:
        - sleep
        - 365d
        env:
        - name: GRPC_XDS_BOOTSTRAP
          value: "/tmp/grpc-xds/td-grpc-bootstrap.json"
        volumeMounts:
        - name: grpc-td-conf
          mountPath: /tmp/grpc-xds/
      initContainers:
      - args:
        - --config-mesh-experimental
        - "gketd-td-grpc-mesh"
        - --output
        - "/tmp/bootstrap/td-grpc-bootstrap.json"
        image: gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0
        imagePullPolicy: IfNotPresent
        name: grpc-td-init
        volumeMounts:
        - name: grpc-td-conf
          mountPath: /tmp/bootstrap/
      volumes:
      - name: grpc-td-conf
        emptyDir:
          medium: Memory
    
  2. Apply the Pod manifest in gke-1:

    kubectl apply -f grpc-client.yaml
    
  3. When the Pod is ready, open a shell to the client Pod:

    kubectl exec -it static-sleeper -- /bin/sh
    

You can use the grpcurl tool as a proxyless gRPC client. The grpcurl tool uses environment variable and bootstrap information to connect to Cloud Service Mesh. The tool then learns about the helloworld service, which was configured with Cloud Service Mesh.

To verify your configuration using the grpcurl tool:

  1. Download and install the grpcurl tool:

    cd /home/curl_user
    curl -L https://github.com/fullstorydev/grpcurl/releases/download/v1.8.1/grpcurl_1.8.1_linux_x86_64.tar.gz | tar -xz
    
  2. Run the grpcurl tool with xds:///helloworld 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 helloworld.Greeter/SayHello
    

    The output is similar to the following, where INSTANCE_HOST_NAME is the hostname of the Pod:

    Greetings: Hello world, from INSTANCE_HOST_NAME
    

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

What's next