Set up a proxyless gRPC service mesh on GKE

This pages describes how to deploy an example proxyless gRPC client and server to aCloud Service Mesh.

Prerequisites

As a starting point, this guide assumes that you have already:

Requirements

This section lists the requirements for supported services:

  • gRPC C++ - version 1.68.1 or later
  • gRPC Java - version 1.68.2 or later
  • gRPC Go - version 1.68.0 or later
  • gRPC Python - version 1.68.1 or later

Set up the Proxyless gRPC Service

This guide outlines two methods for setting up a proxyless gRPC service withinyour service mesh:

Method 1: Manual Configuration

This method requires you to manually configure the necessary components for yourproxyless gRPC service.

  • InitContainer: Use an initContainer within your pod's specification toexecute the Cloud Service Mesh gRPC Bootstrap generator. This generator produces therequired configuration for your service.
  • Volume Mount: Mount a volume that contains the generated configurationfrom the initContainer. This ensures your application can access the necessarysettings.
  • Environment Variables: Include the appropriate environment variables toenable CSM Observability metrics emission from your application. These metricsprovide valuable insights into your service's performance.

Method 2: Automatic using Proxyless Bootstrap Injector

Instead of manually configuring your proxyless gRPC service, you can opt for asimplified approach using the Proxyless Bootstrap Injector.

This feature automates the setup process, making it easier to deploy yourservice. To enable it, add the labelmesh.cloud.google.com/csm-injection=proxyless to your namespace.

By adding this label to your namespace, the injector takes care of all thenecessary configurations, saving you valuable time and effort.

If you need more granular control you can also apply this label directly to individualpods. This lets you to override the namespace-level setting and customize theinjection behavior on a per-pod basis.

Note: The Proxyless Bootstrap Injector simplifies the setup of your proxyless gRPC service. However, it does introduce a dependency on Google infrastructure for pod initialization. If you prefer to avoid this dependency for reliability or other reasons, you can maintain greater control by using the manual configuration method. This provides a more self-contained approach, though it requires additional steps.

By following either of these methods, you can successfully establish a proxylessgRPC service within your service mesh.

Manual

  1. Apply the Namespace

    kubectlapply-f-<<EOF---kind:NamespaceapiVersion:v1metadata:name:proxyless-exampleEOF
  2. Deploy a gRPC service:

C++

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverservice.istio.io/canonical-name:deployment-psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-cpp-server:v1.68.1imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:CONTAINER_NAMEvalue:psm-grpc-server-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-server-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Java

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverservice.istio.io/canonical-name:deployment-psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-java-server:v1.68.2imagePullPolicy:Alwaysargs:-"50051"-"9464"ports:-containerPort:50051env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:CONTAINER_NAMEvalue:psm-grpc-server-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-server-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Go

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverservice.istio.io/canonical-name:deployment-psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-go-server:v1.69.4imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:CONTAINER_NAMEvalue:psm-grpc-server-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-server-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Python

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverservice.istio.io/canonical-name:deployment-psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-python-server:v1.68.1imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:CONTAINER_NAMEvalue:psm-grpc-server-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-server-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

The output is similar to

namespace/proxyless-example createdservice/helloworld createddeployment.apps/psm-grpc-server created

Automatic

  1. Apply the Namespace

    kubectlapply-f-<<EOF---kind:NamespaceapiVersion:v1metadata:name:proxyless-exampleEOF
  2. Run the following command to enable Proxyless Bootstrap Injector in theproxyless-example namespace:

    kubectllabelnamespaceproxyless-examplemesh.cloud.google.com/csm-injection=proxyless
  3. Deploy a gRPC service:

C++

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-cpp-server:v1.68.1imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051EOF

Java

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-java-server:v1.68.2imagePullPolicy:Alwaysargs:-"50051"-"9464"ports:-containerPort:50051EOF

Go

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-go-server:v1.69.4imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051EOF

Python

kubectlapply-f-<<EOF---apiVersion:v1kind:Servicemetadata:name:helloworldnamespace:proxyless-examplespec:selector:app:psm-grpc-serverports:-port:50051targetPort:50051---apiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-servernamespace:proxyless-examplelabels:app:psm-grpc-serverspec:replicas:2selector:matchLabels:app:psm-grpc-servertemplate:metadata:labels:app:psm-grpc-serverspec:containers:-name:psm-grpc-serverimage:grpc/csm-o11y-example-python-server:v1.68.1imagePullPolicy:Alwaysargs:-"--port=50051"ports:-containerPort:50051EOF

The output is similar to

namespace/proxyless-example createdservice/helloworld createddeployment.apps/psm-grpc-server created
  1. Verify that the Pods have been created:

    kubectlgetpods-nproxyless-example

    The output is similar to

    NAME                               READY   STATUS    RESTARTS   AGEpsm-grpc-server-65966bf76d-2wwxz   1/1     Running   0          13spsm-grpc-server-65966bf76d-nbxd2   1/1     Running   0          13s

    Wait for all Pods to be ready and have theStatus Running beforecontinuing.

  2. Deploy a HTTPRoute:

    kubectlapply-f-<<EOFapiVersion:gateway.networking.k8s.io/v1beta1kind:HTTPRoutemetadata:name:app1namespace:proxyless-examplespec:parentRefs:-name:helloworldnamespace:proxyless-examplekind:Servicegroup:""rules:-backendRefs:-name:helloworldport:50051EOF

    This command creates an HTTPRoute called app1 and sends all RPCs to thehelloworld service.

    Note that theparentRef service is alsohelloworld which means ourHTTPRoute is attached to this service and will process all RPCs addressed tothis service. In case of proxyless gRPC it means any client sending RPCs ona gRPC channel for targetxds:///helloworld.proxyless-example.svc.cluster.local:50051.

  3. Verify that the new app1 HTTPRoute has been created:

    kubectlgethttproute-nproxyless-example

    The output is similar to

    NAME   HOSTNAMES   AGEapp1               72s

Set up the Proxyless gRPC Client

This sections describes how to use a gRPC client to verify thatCloud Service Mesh is routing traffic correctly in the mesh.

Just like configuring the service, you have two choices for setting up theclient:

Method 1: Manual Configuration

This approach involves manually setting up the necessary components for your client, mirroring the manual service configuration.

Method 2: Automatic using Proxyless Bootstrap Injector

Alternatively, you can use the automatic injector to streamline the client setup process. This simplifies configuration and reduces manual intervention. This is achieved by applying the label on the namespace.

Both options provide the necessary capabilities for your client. Choose themethod that best suits your needs and preferences.

Manual

Run a gRPC client and direct it to use the routing configuration specified bythe HTTPRoute:

C++

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientservice.istio.io/canonical-name:deployment-psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-cpp-client:v1.68.1imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-client-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CONTAINER_NAMEvalue:psm-grpc-client-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Java

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientservice.istio.io/canonical-name:deployment-psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-java-client:v1.68.2imagePullPolicy:Alwaysargs:-"world"-"xds:///helloworld.proxyless-example.svc.cluster.local:50051"-"9464"env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-client-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CONTAINER_NAMEvalue:psm-grpc-client-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Go

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientservice.istio.io/canonical-name:deployment-psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-go-client:v1.69.4imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-client-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CONTAINER_NAMEvalue:psm-grpc-client-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Python

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientservice.istio.io/canonical-name:deployment-psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-python-client:v1.68.1imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"env:-name:GRPC_XDS_BOOTSTRAPvalue:"/tmp/grpc-xds/td-grpc-bootstrap.json"-name:CSM_WORKLOAD_NAMEvalue:psm-grpc-client-name:CSM_CANONICAL_SERVICE_NAMEvalueFrom:fieldRef:fieldPath:metadata.labels['service.istio.io/canonical-name']-name:CSM_MESH_IDvalue:proj-PROJECT_NUMBER-name:POD_NAMEvalueFrom:fieldRef:fieldPath:metadata.name-name:NAMESPACE_NAMEvalueFrom:fieldRef:fieldPath:metadata.namespace-name:CONTAINER_NAMEvalue:psm-grpc-client-name:OTEL_RESOURCE_ATTRIBUTESvalue:k8s.pod.name=\$(POD_NAME),k8s.namespace.name=\$(NAMESPACE_NAME),k8s.container.name=\$(CONTAINER_NAME)volumeMounts:-mountPath:/tmp/grpc-xds/name:grpc-td-confreadOnly:trueinitContainers:-name:grpc-td-initimage:gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0imagePullPolicy:Alwaysargs:-"--output=/tmp/bootstrap/td-grpc-bootstrap.json"-"--vpc-network-name=default"-"--xds-server-uri=trafficdirector.googleapis.com:443"-"--generate-mesh-id"volumeMounts:-mountPath:/tmp/bootstrap/name:grpc-td-confvolumes:-name:grpc-td-confemptyDir:medium:MemoryEOF

Automatic

Run a gRPC client and direct it to use the routing configuration specified bythe HTTPRoute:

C++

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-cpp-client:v1.68.1imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"EOF

Java

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-java-client:v1.68.2imagePullPolicy:Alwaysargs:-"world"-"xds:///helloworld.proxyless-example.svc.cluster.local:50051"-"9464"EOF

Go

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-go-client:v1.69.4imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"EOF

Python

kubectlapply-f-<<EOFapiVersion:apps/v1kind:Deploymentmetadata:name:psm-grpc-clientnamespace:proxyless-examplelabels:app:psm-grpc-clientspec:replicas:1selector:matchLabels:app:psm-grpc-clienttemplate:metadata:labels:app:psm-grpc-clientspec:containers:-name:psm-grpc-clientimage:grpc/csm-o11y-example-python-client:v1.68.1imagePullPolicy:Alwaysargs:-"--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051"EOF

The output is similar to

deployment.apps/psm-grpc-client created

To verify if the client was able to reach the service, view the client's logs:

kubectllogs-nproxyless-example$(kubectlgetpo-nproxyless-example|greppsm-grpc-client|awk'{print $1;}')-f

The output is similar to:

Defaulted container "psm-grpc-client" out of: psm-grpc-client, grpc-td-init (init)Greeter received: Hello from psm-grpc-server-xxxxxxx-xxxx world

Google Cloud Managed Service for Prometheus Setup (Optional)

You can deploy theGoogle Cloud Managed Service for PrometheusPodMonitoring resource to export the metrics to Cloud Monitoring.

  • For servers, run the following command:

    kubectlapply-f-<<EOFapiVersion:monitoring.googleapis.com/v1kind:PodMonitoringmetadata:name:psm-grpc-server-gmpnamespace:proxyless-examplespec:selector:matchLabels:app:psm-grpc-serverendpoints:-port:9464interval:10sEOF
  • For clients, , run the following command:

    kubectlapply-f-<<EOFapiVersion:monitoring.googleapis.com/v1kind:PodMonitoringmetadata:name:psm-grpc-client-gmpnamespace:proxyless-examplespec:selector:matchLabels:app:psm-grpc-clientendpoints:-port:9464interval:10sEOF

    After deploying thePodMonitoring resource, each matching pod'slocalhost:9464/metrics will be scraped every 10 seconds and will export theresults to Cloud Monitoring.

To view the metrics in Cloud Monitoring, perform the following steps:

you can navigate to the "Metrics Explorer" section of yourGoogle Cloud console, select Prometheus Target > Grpc to find the metrics.

Go to Metrics Explorer

You can observe the deployed workloads and services in the "Service Mesh" section of your Google Cloud console.

Go to Service Mesh

Troubleshoot Cloud Service Mesh observability

This section shows how to troubleshoot common issues.

Metrics are not exported / displayed

Make sure that all binaries involved (both client and server) areset up with Observability.

If you're using the Prometheus exporter, verify that the URL for the Prometheusexporter is set up as expected.

Make sure that the gRPC channels are Cloud Service Mesh enabled. The channelsshould have a target of the formxds:///. gRPC servers are always enabled forCloud Service Mesh.

No metrics exported / An attribute value on a metric shows up as unknown

Cloud Service Mesh Observability determines the mesh topologicalinformation through environment labels. Make sure that the Pod or service specfor both the client and the service specify all the labels as described in theexample.

  1. Describe the psm-grpc-server deployment:

    kubectldescribeDeploymentpsm-grpc-server-nproxyless-example\|grep"psm-grpc-server:"-A12

    The output is similar to:

    psm-grpc-server:Image:      grpc/csm-example-server:2024-02-13Port:       50051/TCPHost Port:  0/TCPArgs:  --port=50051Environment:  GRPC_XDS_BOOTSTRAP:          /tmp/grpc-xds/td-grpc-bootstrap.json  POD_NAME:                     (v1:metadata.name)  NAMESPACE_NAME:               (v1:metadata.namespace)  CSM_WORKLOAD_NAME:           psm-grpc-server  OTEL_RESOURCE_ATTRIBUTES:    k8s.pod.name=$(POD_NAME),k8s.namespace.name=$(NAMESPACE_NAME),k8s.container.name=$(CONTAINER_NAME)
  2. Describe the psm-grpc-client deployment:

    kubectldescribeDeploymentpsm-grpc-client-nproxyless-example\|grep"psm-grpc-client:"-A12

    The output is similar to:

    psm-grpc-client:Image:      grpc/csm-example-client:2024-02-13Port:       <none>Host Port:  <none>Args:  --target=xds:///helloworld.proxyless-example.svc.cluster.local:50051Environment:  GRPC_XDS_BOOTSTRAP:          /tmp/grpc-xds/td-grpc-bootstrap.json  CSM_WORKLOAD_NAME:           test-workload-name  POD_NAME:                     (v1:metadata.name)  NAMESPACE_NAME:               (v1:metadata.namespace)  CONTAINER_NAME:              psm-grpc-client

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-19 UTC.