Set up a proxyless gRPC service mesh on GKE

This pages describes how to deploy an example proxyless gRPC client and server to a Cloud 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 within your service mesh:

Method 1: Manual Configuration

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

  • InitContainer: Use an initContainer within your pod's specification to execute the Cloud Service Mesh gRPC Bootstrap generator. This generator produces the required configuration for your service.
  • Volume Mount: Mount a volume that contains the generated configuration from the initContainer. This ensures your application can access the necessary settings.
  • Environment Variables: Include the appropriate environment variables to enable CSM Observability metrics emission from your application. These metrics provide 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 a simplified approach using the Proxyless Bootstrap Injector.

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

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

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

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

Manual

  1. Apply the Namespace

     kubectl  
    apply  
    -f  
    -  
    <<EOF
    ---
    kind:  
    Namespace
    apiVersion:  
    v1
    metadata:  
    name:  
    proxyless-example
    EOF 
    
  2. Deploy a gRPC service:

C++

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
service.istio.io/canonical-name:  
deployment-psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-cpp-server:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-server  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-server  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Java

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
service.istio.io/canonical-name:  
deployment-psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-java-server:v1.68.2  
imagePullPolicy:  
Always  
args:  
-  
 "50051" 
  
-  
 "9464" 
  
ports:  
-  
containerPort:  
 50051 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-server  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-server  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Go

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
service.istio.io/canonical-name:  
deployment-psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-go-server:v1.69.4  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-server  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-server  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Python

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
service.istio.io/canonical-name:  
deployment-psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-python-server:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-server  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-server  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

The output is similar to

 namespace/proxyless-example created
service/helloworld created
deployment.apps/psm-grpc-server created 

Automatic

  1. Apply the Namespace

     kubectl  
    apply  
    -f  
    -  
    <<EOF
    ---
    kind:  
    Namespace
    apiVersion:  
    v1
    metadata:  
    name:  
    proxyless-example
    EOF 
    
  2. Run the following command to enable Proxyless Bootstrap Injector in the proxyless-example namespace:

     kubectl  
    label  
    namespace  
    proxyless-example  
    mesh.cloud.google.com/csm-injection = 
    proxyless 
    
  3. Deploy a gRPC service:

C++

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-cpp-server:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
EOF 

Java

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-java-server:v1.68.2  
imagePullPolicy:  
Always  
args:  
-  
 "50051" 
  
-  
 "9464" 
  
ports:  
-  
containerPort:  
 50051 
EOF 

Go

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-go-server:v1.69.4  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
EOF 

Python

 kubectl  
apply  
-f  
-  
<<EOF
---
apiVersion:  
v1
kind:  
Service
metadata:  
name:  
helloworld  
namespace:  
proxyless-example
spec:  
selector:  
app:  
psm-grpc-server  
ports:  
-  
port:  
 50051 
  
targetPort:  
 50051 
---
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-server  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-server
spec:  
replicas:  
 2 
  
selector:  
matchLabels:  
app:  
psm-grpc-server  
template:  
metadata:  
labels:  
app:  
psm-grpc-server  
spec:  
containers:  
-  
name:  
psm-grpc-server  
image:  
grpc/csm-o11y-example-python-server:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--port=50051" 
  
ports:  
-  
containerPort:  
 50051 
EOF 

The output is similar to

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

     kubectl  
    get  
    pods  
    -n  
    proxyless-example 
    

    The output is similar to

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

    Wait for all Pods to be ready and have the Status Running before continuing.

  2. Deploy a HTTPRoute:

     kubectl  
    apply  
    -f  
    -  
    <<EOF
    apiVersion:  
    gateway.networking.k8s.io/v1beta1
    kind:  
    HTTPRoute
    metadata:  
    name:  
    app1  
    namespace:  
    proxyless-example
    spec:  
    parentRefs:  
    -  
    name:  
    helloworld  
    namespace:  
    proxyless-example  
    kind:  
    Service  
    group:  
     "" 
      
    rules:  
    -  
    backendRefs:  
    -  
    name:  
    helloworld  
    port:  
     50051 
    EOF 
    

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

    Note that the parentRef service is also helloworld which means our HTTPRoute is attached to this service and will process all RPCs addressed to this service. In case of proxyless gRPC it means any client sending RPCs on a gRPC channel for target xds:///helloworld.proxyless-example.svc.cluster.local:50051 .

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

     kubectl  
    get  
    httproute  
    -n  
    proxyless-example 
    

    The output is similar to

     NAME   HOSTNAMES   AGE
    app1               72s 
    

Set up the Proxyless gRPC Client

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

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

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 the method that best suits your needs and preferences.

Manual

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

C++

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
service.istio.io/canonical-name:  
deployment-psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-cpp-client:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-client  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-client  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Java

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
service.istio.io/canonical-name:  
deployment-psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-java-client:v1.68.2  
imagePullPolicy:  
Always  
args:  
-  
 "world" 
  
-  
 "xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
  
-  
 "9464" 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-client  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-client  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Go

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
service.istio.io/canonical-name:  
deployment-psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-go-client:v1.69.4  
imagePullPolicy:  
Always  
args:  
-  
 "--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-client  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-client  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Python

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
service.istio.io/canonical-name:  
deployment-psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-python-client:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
  
 env:  
-  
name:  
GRPC_XDS_BOOTSTRAP  
value:  
 "/tmp/grpc-xds/td-grpc-bootstrap.json" 
  
-  
name:  
CSM_WORKLOAD_NAME  
value:  
psm-grpc-client  
-  
name:  
CSM_CANONICAL_SERVICE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.labels [ 
 'service.istio.io/canonical-name' 
 ] 
  
-  
name:  
CSM_MESH_ID  
value:  
proj- PROJECT_NUMBER 
  
-  
name:  
POD_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.name  
-  
name:  
NAMESPACE_NAME  
valueFrom:  
fieldRef:  
fieldPath:  
metadata.namespace  
-  
name:  
CONTAINER_NAME  
value:  
psm-grpc-client  
-  
name:  
OTEL_RESOURCE_ATTRIBUTES  
value:  
k8s.pod.name = 
 \$ 
 ( 
POD_NAME ) 
,k8s.namespace.name = 
 \$ 
 ( 
NAMESPACE_NAME ) 
,k8s.container.name = 
 \$ 
 ( 
CONTAINER_NAME ) 
  
volumeMounts:  
-  
mountPath:  
/tmp/grpc-xds/  
name:  
grpc-td-conf  
readOnly:  
 true 
  
initContainers:  
-  
name:  
grpc-td-init  
image:  
gcr.io/trafficdirector-prod/td-grpc-bootstrap:0.16.0  
imagePullPolicy:  
Always  
args:  
-  
 "--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-conf  
volumes:  
-  
name:  
grpc-td-conf  
emptyDir:  
medium:  
MemoryEOF 

Automatic

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

C++

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-cpp-client:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
EOF 

Java

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-java-client:v1.68.2  
imagePullPolicy:  
Always  
args:  
-  
 "world" 
  
-  
 "xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
  
-  
 "9464" 
EOF 

Go

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-go-client:v1.69.4  
imagePullPolicy:  
Always  
args:  
-  
 "--target=xds:///helloworld.proxyless-example.svc.cluster.local:50051" 
EOF 

Python

 kubectl  
apply  
-f  
-  
<<EOF
apiVersion:  
apps/v1
kind:  
Deployment
metadata:  
name:  
psm-grpc-client  
namespace:  
proxyless-example  
labels:  
app:  
psm-grpc-client
spec:  
replicas:  
 1 
  
selector:  
matchLabels:  
app:  
psm-grpc-client  
template:  
metadata:  
labels:  
app:  
psm-grpc-client  
spec:  
containers:  
-  
name:  
psm-grpc-client  
image:  
grpc/csm-o11y-example-python-client:v1.68.1  
imagePullPolicy:  
Always  
args:  
-  
 "--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:

 kubectl  
logs  
-n  
proxyless-example  
 $( 
kubectl  
get  
po  
-n  
proxyless-example  
 | 
  
grep  
psm-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 the Google Cloud Managed Service for Prometheus PodMonitoring resource to export the metrics to Cloud Monitoring.

  • For servers, run the following command:

     kubectl  
    apply  
    -f  
    -  
    <<EOF
    apiVersion:  
    monitoring.googleapis.com/v1
    kind:  
    PodMonitoring
    metadata:  
    name:  
    psm-grpc-server-gmp  
    namespace:  
    proxyless-example
    spec:  
    selector:  
    matchLabels:  
    app:  
    psm-grpc-server  
    endpoints:  
    -  
    port:  
     9464 
      
    interval:  
    10s
    EOF 
    
  • For clients, , run the following command:

     kubectl  
    apply  
    -f  
    -  
    <<EOF
    apiVersion:  
    monitoring.googleapis.com/v1
    kind:  
    PodMonitoring
    metadata:  
    name:  
    psm-grpc-client-gmp  
    namespace:  
    proxyless-example
    spec:  
    selector:  
    matchLabels:  
    app:  
    psm-grpc-client  
    endpoints:  
    -  
    port:  
     9464 
      
    interval:  
    10s
    EOF 
    

    After deploying the PodMonitoring resource, each matching pod's localhost:9464/metrics will be scraped every 10 seconds and will export the results to Cloud Monitoring.

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

you can navigate to the "Metrics Explorer" section of your Google 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) are set up with Observability .

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

Make sure that the gRPC channels are Cloud Service Mesh enabled. The channels should have a target of the form xds:/// . gRPC servers are always enabled for Cloud Service Mesh.

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

Cloud Service Mesh Observability determines the mesh topological information through environment labels. Make sure that the Pod or service spec for both the client and the service specify all the labels as described in the example.

  1. Describe the psm-grpc-server deployment:

     kubectl  
    describe  
    Deployment  
    psm-grpc-server  
    -n  
    proxyless-example  
     \ 
     | 
      
    grep  
     "psm-grpc-server:" 
      
    -A  
     12 
     
    

    The output is similar to:

     psm-grpc-server:
    Image:      grpc/csm-example-server:2024-02-13
    Port:       50051/TCP
    Host Port:  0/TCP
    Args:
      --port=50051
    Environment:
      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:

     kubectl  
    describe  
    Deployment  
    psm-grpc-client  
    -n  
    proxyless-example  
     \ 
     | 
      
    grep  
     "psm-grpc-client:" 
      
    -A  
     12 
     
    

    The output is similar to:

     psm-grpc-client:
    Image:      grpc/csm-example-client:2024-02-13
    Port:       <none>
    Host Port:  <none>
    Args:
      --target=xds:///helloworld.proxyless-example.svc.cluster.local:50051
    Environment:
      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 
    
Create a Mobile Website
View Site in Mobile | Classic
Share by: