在 GKE 上设置无代理 gRPC 服务网格
本页介绍了如何将无代理 gRPC 客户端和服务器示例部署到 Cloud Service Mesh。
前提条件
首先,本指南假定您已完成以下操作:
使用要求
本部分列出了受支持服务的要求:
- gRPC C++ - 1.62.0 版或更高版本
- gRPC Java - 1.65.0 版或更高版本
- gRPC Go - 1.65.0 版或更高版本
- gRPC Python - 1.65.0 版或更高版本
设置服务
部署 gRPC 服务:
C++
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Service
metadata:
name: helloworld
spec:
selector:
app: psm-grpc-server
ports:
- port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-server
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:latest
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: NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CSM_WORKLOAD_NAME
value: psm-grpc-server
- 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: Memory
EOF
Java
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Service
metadata:
name: helloworld
spec:
selector:
app: psm-grpc-server
ports:
- port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-server
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:latest
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: NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CSM_WORKLOAD_NAME
value: psm-grpc-server
- 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: Memory
EOF
Go
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Service
metadata:
name: helloworld
spec:
selector:
app: psm-grpc-server
ports:
- port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-server
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:latest
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: NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CSM_WORKLOAD_NAME
value: psm-grpc-server
- 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: Memory
EOF
Python
kubectl apply -f - <<EOF
---
apiVersion: v1
kind: Service
metadata:
name: helloworld
spec:
selector:
app: psm-grpc-server
ports:
- port: 50051
targetPort: 50051
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-server
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:latest
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: NAMESPACE_NAME
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CSM_WORKLOAD_NAME
value: psm-grpc-server
- 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: Memory
EOF
输出类似于以下内容
service/helloworld created
deployment.apps/psm-grpc-server created
验证 Pod 是否已创建:
kubectl get pods
输出类似于以下内容
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
等待所有 Pod 准备就绪并显示
Status
运行状态,然后再继续。部署 HTTPRoute:
kubectl apply -f - <<EOF apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: app1 spec: parentRefs: - name: helloworld kind: Service group: "" rules: - backendRefs: - name: helloworld port: 50051 EOF
此命令会创建一个名为 app1 的 HTTPRoute,并将所有 RPC 发送到
helloworld
服务。请注意,
parentRef
服务也是helloworld
,这意味着我们的 HTTPRoute 会附加到此服务,并会处理发送到此服务的所有 RPC。对于无代理 gRPC,它表示通过 gRPC 通道向目标xds:///helloworld.default.svc.cluster.local:50051
发送 RPC 的任何客户端。验证是否已创建新的 app1 HTTPRoute:
kubectl get httproute
输出类似于以下内容
NAME HOSTNAMES AGE app1 72s
设置客户端
本部分介绍如何使用 gRPC 客户端验证 Cloud Service Mesh 是否在网格中正确路由流量。
运行 gRPC 客户端,并指示其使用 HTTPRoute 指定的路由配置:
C++
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-client
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-server:latest
imagePullPolicy: Always
args:
"--target=xds:///helloworld.default.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: 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: Memory
EOF
Java
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-client
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-server:latest
imagePullPolicy: Always
args:
"world"<br/>"xds:///helloworld.default.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: 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: Memory
EOF
Go
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-client
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-server:latest
imagePullPolicy: Always
args:
"--target=xds:///helloworld.default.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: 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: Memory
EOF
Python
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: psm-grpc-client
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-server:latest
imagePullPolicy: Always
args:
"--target=xds:///helloworld.default.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: 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: Memory
EOF
输出类似于以下内容
deployment.apps/psm-grpc-client created
Google Cloud Managed Service for Prometheus 设置(可选)
您可以部署 Google Cloud Managed Service for Prometheus
PodMonitoring
资源,以将指标导出到 Cloud Monitoring。
对于服务器,请运行以下命令:
kubectl apply -f - <<EOF apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: psm-grpc-server-gmp spec: selector: matchLabels: app: psm-grpc-server endpoints: - port: 9464 interval: 10s EOF
对于客户端,请运行以下命令:
kubectl apply -f - <<EOF apiVersion: monitoring.googleapis.com/v1 kind: PodMonitoring metadata: name: psm-grpc-client-gmp spec: selector: matchLabels: app: psm-grpc-client endpoints: - port: 9464 interval: 10s EOF
部署
PodMonitoring
资源后,系统将每 10 秒抓取每个匹配 Pod 的localhost:9464/metrics
,并将结果导出到 Cloud Monitoring。
如需在 Cloud Monitoring 中查看指标,请执行以下步骤:
您可以前往 Google Cloud 控制台的 Metrics Explorer 部分,依次选择 Prometheus Target > Grpc 以查找指标。
验证无代理 gRPC 服务网格设置和服务网格可观测性
检查客户端 pod 的指标输出:
kubectl exec $(kubectl get po | grep psm-grpc-client | awk '{print $1;}') -- /usr/bin/curl -s http://localhost:9464/metrics
输出显示从端点抓取的指标(带有服务网格标签):
Defaulted container "psm-grpc-client" out of: psm-grpc-client, grpc-td-init (init) # HELP exposer_transferred_bytes_total Transferred bytes to metrics services # TYPE exposer_transferred_bytes_total counter exposer_transferred_bytes_total 36047 # HELP exposer_scrapes_total Number of times metrics were scraped # TYPE exposer_scrapes_total counter exposer_scrapes_total 1 # HELP exposer_request_latencies Latencies of serving scrape requests, in microseconds # TYPE exposer_request_latencies summary exposer_request_latencies_count 1 exposer_request_latencies_sum 1246 exposer_request_latencies{quantile="0.5"} Nan exposer_request_latencies{quantile="0.9"} Nan exposer_request_latencies{quantile="0.99"} Nan # HELP grpc_client_attempt_rcvd_total_compressed_message_size_By Compressed message bytes received per call attempt # TYPE grpc_client_attempt_rcvd_total_compressed_message_size_By histogram grpc_client_attempt_rcvd_total_compressed_message_size_By_count{csm_mesh_id="gsmmesh-35av-my-cluster-3-us-east7-c-35av6nnbi9jz",csm_remote_workload_canonical_service="unknown",csm_remote_workload_cluster_name="my-cluster-3",csm_remote_workload_location="us-east7-c",csm_remote_workload_name="psm-grpc-server",csm_remote_workload_namespace_name="default",csm_remote_workload_project_id="grpc-testing",csm_remote_workload_type="gcp_kubernetes_engine",csm_workload_canonical_service="unknown",grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",grpc_target="xds:///helloworld.default.svc.cluster.local:50051"} 114 1695445356167 ...
检查服务器输出的指标:
kubectl exec $(kubectl get po | grep psm-grpc-server | awk '{print $1;}' | head -n 1) -- /usr/bin/curl -s http://localhost:9464/metrics
输出显示从端点抓取的指标(带有服务网格标签):
Defaulted container "psm-grpc-server" out of: psm-grpc-server, grpc-td-init (init) # HELP exposer_transferred_bytes_total Transferred bytes to metrics services # TYPE exposer_transferred_bytes_total counter exposer_transferred_bytes_total 35945 # HELP exposer_scrapes_total Number of times metrics were scraped # TYPE exposer_scrapes_total counter exposer_scrapes_total 1 # HELP exposer_request_latencies Latencies of serving scrape requests, in microseconds # TYPE exposer_request_latencies summary exposer_request_latencies_count 1 exposer_request_latencies_sum 2369 exposer_request_latencies{quantile="0.5"} Nan exposer_request_latencies{quantile="0.9"} Nan exposer_request_latencies{quantile="0.99"} Nan # HELP target Target metadata # TYPE target gauge target_info{otel_scope_name="grpc-c++",otel_scope_version="1.62.0-dev",service_name="unknown_service",k8s_pod_name="psm-grpc-server-6f75c8f857-qst5k",k8s_namespace_name="default",k8s_container_name="$(CONTAINER_NAME)",telemetry_sdk_version="1.13.0",telemetry_sdk_name="opentelemetry",telemetry_sdk_language="cpp"} 1 1708157423871 # HELP grpc_server_call_sent_total_compressed_message_size_bytes Compressed message bytes sent per server call # TYPE grpc_server_call_sent_total_compressed_message_size_bytes histogram grpc_server_call_sent_total_compressed_message_size_bytes_count{csm_mesh_id="gsmmesh-fogj-my-cluster-us-central1-a-fogjnvmqo8fn",csm_remote_workload_canonical_service="unknown",csm_remote_workload_cluster_name="my-cluster",csm_remote_workload_location="us-central1-a",csm_remote_workload_name="test-workload-name",csm_remote_workload_namespace_name="default",csm_remote_workload_project_id="project-id",csm_remote_workload_type="gcp_kubernetes_engine",csm_workload_canonical_service="unknown",grpc_method="helloworld.Greeter/SayHello",grpc_status="OK",otel_scope_name="grpc-c++",otel_scope_version="1.62.0-dev"} 1796 1708157423871 …
排查 Cloud Service Mesh 可观测性问题
本部分介绍了如何排查常见问题。
指标的属性值显示为“未知”
如果该指标上的属性值显示为“未知”,请确保已为涉及的所有二进制文件(客户端和服务器)在 GKE 上设置了无代理 gRPC 服务网格。
请注意,Cloud Service Mesh 可观测性通过环境标签确定网格拓扑信息。确保客户端和服务的 Pod 或服务规范都指定了示例中所述的所有标签。
描述 psm-grpc-server 部署:
kubectl describe Deployment psm-grpc-server | grep "psm-grpc-server:" -A 12
输出类似于以下内容:
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)
描述 psm-grpc-client 部署:
kubectl describe Deployment psm-grpc-client | grep "psm-grpc-client:" -A 12
输出类似于以下内容:
psm-grpc-client: Image: grpc/csm-example-client:2024-02-13 Port: <none> Host Port: <none> Args: --target=xds:///helloworld.default.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
指标未显示
如果您使用的是 Prometheus 导出器,请验证 Prometheus 导出器的网址是否已按预期设置。
确保 gRPC 通道已启用 Cloud Service Mesh。渠道的目标应采用 xds:///
的格式。Cloud Service Mesh 始终启用 gRPC 服务器。