Use the Proxyless service mesh with gRPC services
Istio offers an additional deployment model for gRPC applications, enabling them to operate without a sidecar proxy. In this model, the Istio control plane uses the open-source xDS API to configure gRPC applications directly. This allows you to manage workloads with features such as traffic routing and mTLS authentication without a sidecar. This topic describes how to use proxyless Service Mesh features in your gRPC services.
Prerequisites
-
You have created an ASM instance version v1.12.4.2-gc5962641-aliyun or later. For more information, see Create an ASM instance.
Background information
The proxyless Service Mesh does not use a proxy for data plane communication, but it still requires an agent for initialization and communication with the control plane. The agent performs the following functions:
-
Fetches and rotates the certificates used in data plane communication.
-
Acts as an xDS proxy, connecting and authenticating with Istiod on behalf of the application.
-
At startup, the agent generates a bootstrap file, similar to how it does for Envoy. The file instructs the gRPC library on how to connect to Istiod, where to find certificates for data plane communication, and what data to send to the control plane.
The following frameworks and platforms support Istio's proxyless mode:
-
Apache Dubbo: Dubbo is a high-performance Java RPC framework that integrates with Istio to support service calls in proxyless mode. For more information, see https://cn.dubbo.apache.org/en/overview/tasks/mesh/proxyless/.
-
gRPC framework: The gRPC project provides extensive support for the xDS API. For more information, see the community documentation at https://istio.io/latest/blog/2021/proxyless-grpc/.
-
Kitex Proxyless: Using the xDS protocol, Kitex services can interact directly with service mesh control plane components without an Envoy sidecar. Kitex dynamically obtains service governance rules from the control plane and converts them into Kitex-specific rules to implement service governance features. For more information, see https://www.cloudwego.io/blog/2022/12/20/kitex-proxyless-practicetraffic-lane-implementation-with-istio-and-opentelemetry/.
Limitations
The proxyless mode has the following limitations:
-
PERMISSIVE mode (plaintext or mutual TLS) is not supported. If you need to use STRICT mode on the server, you must use an explicit mTLS configuration with ISTIO_MUTUAL on the client.
-
Requests made through
grpc.Serve(listener)orgrpc.Dial("xds://...")may fail before the bootstrap file or xDS configuration takes effect. You can useholdApplicationUntilProxyStartsto avoid this issue. -
The implementation of the xDS API in gRPC may be incompatible with Envoy, resulting in missing features or configurations that fail to apply. Verify that your Istio configuration applies to your proxyless gRPC application. For more information, see xDS Features in gRPC.
Features supported in proxyless mode
Compared to Envoy, the xDS API in gRPC currently supports only a subset of features. The supported features are as follows:
|
Feature category |
Supported features |
|
Service discovery |
gRPC services can discover other pods registered in the mesh. |
|
DestinationRule |
|
|
VirtualService |
|
|
PeerAuthentication |
Use DISABLE and STRICT mTLS modes. |
Use proxyless Service Mesh
This topic uses a sample gRPC application named Echo, which supports proxyless mode, to demonstrate how to use traffic routing and mTLS authentication features without a sidecar.
Deploy the sample application
-
Add the
inject.istio.io/templates: grpc-agentannotation to the echo-grpc application pod.If your application code supports proxyless mode, you must add the
inject.istio.io/templates: grpc-agentannotation to the application pod to enable proxyless mode. Also, add theproxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}'annotation to the gRPC server to ensure that the agent's xDS proxy and the bootstrap file are ready before the gRPC server initializes (ASM enables this by default).The following snippet shows the annotations for the echo-grpc application. For the complete YAML file, see grpc-echo.
template: metadata: annotations: inject.istio.io/templates: grpc-agent proxy.istio.io/config: '{"holdApplicationUntilProxyStarts": true}' labels: app: echo version: v1 -
Connect to the ACK cluster by using kubectl. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
-
Run the following command to create the echo-grpc namespace:
kubectl create namespace echo-grpc -
Run the following command to add a label to the echo-grpc namespace to enable sidecar injection:
Proxyless mode uses an agent, not a sidecar, for control plane communication. This agent is deployed using the sidecar injection mechanism, so you must still enable sidecar injection for the namespace.
kubectl label namespace echo-grpc istio-injection=enabled -
Run the following command to deploy the echo-grpc application:
kubectl -n echo-grpc apply -f https://alibabacloudservicemesh.oss-cn-beijing.aliyuncs.com/asm-grpc-proxyless/grpc-echo.yaml -
Verify that the application is deployed successfully.
-
Run the following command to expose port 17171:
kubectl -n echo-grpc port-forward $(kubectl -n echo-grpc get pods -l version=v1 -ojsonpath='{.items[0].metadata.name}') 17171 & -
Run the following command to access the echo-grpc application:
grpcurl -plaintext -d '{"url": "xds:///echo.echo-grpc.svc.cluster.local:7070", "count": 5}' :17171 proto.EchoTestService/ForwardEcho | jq -r '.output | join("")' | grep HostnameExpected output:
[0 body] Hostname=echo-v1-f76996c45-h7plh [1 body] Hostname=echo-v1-f76996c45-h7plh [2 body] Hostname=echo-v2-7d76b7969-ltlkp [3 body] Hostname=echo-v2-7d76b7969-ltlkp [4 body] Hostname=echo-v1-f76996c45-h7plh
-
Scenario 1: Traffic routing
-
Create a DestinationRule.
Use a DestinationRule to create a subset for each version of the workload.
-
Log on to the ASM console. In the left-side navigation pane, choose .
-
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose . On the page that appears, click Create.
-
On the Create page, set Namespaces to echo-grpc, enter a Name, and set Host to echo.echo-grpc.svc.cluster.local.
-
Click Service Version (Subset), and then click Add Service Version (Subset). In the Version 1 section, set Name to v1, click Add Label, and set Key to version and Value to v1.
-
Click Add Service Version (Subset). In the Version 2 section, set Name to v2, click Add Label, and set Key to version and Value to v2.
-
Click Create.
-
-
Create a VirtualService.
Use a VirtualService to route 80% of traffic to the v2 subset and 20% to the v1 subset.
-
Log on to the ASM console. In the left-side navigation pane, choose .
-
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose . On the page that appears, click Create.
-
On the Create page, set Namespaces to echo-grpc and enter a Name.
-
Click HTTP Route, click Add Route, and enter a Name. Click Add Route Destination, set Host to echo.echo-grpc.svc.cluster.local, Subset to v1, and Weight to 20.
-
Click Add Route Destination, set Host to echo.echo-grpc.svc.cluster.local, Subset to v2, and Weight to 80.
-
Click Create.
-
-
Run the following command to send 10 requests to the echo-grpc application:
grpcurl -plaintext -d '{"url": "xds:///echo.echo-grpc.svc.cluster.local:7070", "count": 10}' :17171 proto.EchoTestService/ForwardEcho | jq -r '.output | join("")' | grep ServiceVersionExpected output:
[0 body] ServiceVersion=v2 [0 body] ServiceVersion=v1 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v1 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v2 [0 body] ServiceVersion=v2The output shows that out of 10 requests sent to the echo-grpc application, 8 are routed to the v2 subset and 2 are routed to the v1 subset. This confirms that the traffic routing rules are working correctly.
Scenario 2: mTLS authentication
Enable mTLS authentication to encrypt communication between services.
-
Create a DestinationRule.
Use a DestinationRule to enable mTLS on the client side.
-
Log on to the ASM console.
-
In the left-side navigation pane, choose .
-
On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.
-
In the left-side navigation pane, choose , and then click Create.
-
On the Create page, set Namespaces to echo-grpc, enter a Name, and set Host to echo.echo-grpc.svc.cluster.local.
-
Click Traffic Policy, click Add Policy, switch on Client TLS, and set TLS Mode to Istio Mutual.
-
Click Create.
-
-
Run the following command to access the echo-grpc application:
grpcurl -plaintext -d '{"url": "xds:///echo.echo-grpc.svc.cluster.local:7070"}' :17171 proto.EchoTestService/ForwardEcho | jq -r '.output | join("")'Expected output:
ERROR: Code: Unknown Message: 1/1 requests had errors; first error: rpc error: code = Unavailable desc = all SubConns are in TransientFailureThe request to the echo-grpc application fails because mTLS authentication is not enabled on the server side.
-
Create a PeerAuthentication policy.
Use a PeerAuthentication policy to enable mTLS on the server side.
-
Log on to the ASM console. In the left-side navigation pane, choose .
-
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose . On the page that appears, click Create mTLS Mode.
-
On the Create mTLS Mode page, set Namespaces to echo-grpc, enter a Name, set mTLS Mode to STRICT - Strictly Enforce mTLS, and then click Create.
-
-
Run the following command to access the echo-grpc application:
grpcurl -plaintext -d '{"url": "xds:///echo.echo-grpc.svc.cluster.local:7070"}' :17171 proto.EchoTestService/ForwardEcho | jq -r '.output | join("")'Expected output:
[0] grpcecho.Echo(${xds:///echo.echo-grpc.svc.cluster.local:7070 map [] 0 <nil> 5s false }) [0 body] RequestHeader=x-request-id:0 [0 body] Host=echo.echo-grpc.svc.cluster.local [0 body] RequestHeader=:authorit:echo.echo-grpc.svc.cluster.local:7070 ........The request to the echo-grpc application succeeds.
Modify your gRPC application code
If your gRPC service does not yet support proxyless mode, modify its client and server code to enable xDS API support. You can then use features such as traffic policies in proxyless mode.
Modifying application code to enable the xDS API is supported only for gRPC applications version 1.39.0 and later.
Modify the gRPC client
-
Modify the gRPC code as follows to register the xDS resolver and balancer in gRPC.
The following content must be added to the main package or the same package that calls grpc.Dial.
import _ "google.golang.org/grpc/xds" -
Modify the gRPC code so that the connection URL uses the
xds:///scheme, followed by the service's fully qualified domain name (FQDN).conn, err := grpc.DialContext(ctx, "xds:///foo.ns.svc.cluster.local:7070") -
Modify the gRPC code to pass a special TransportCredentials option to DialContext when using mTLS.
FallbackCredsallows the call to succeed even if Istiod does not send a security configuration.import "google.golang.org/grpc/credentials/xds" ... creds, err := xds.NewClientCredentials(xds.ClientOptions{ FallbackCreds: insecure.NewCredentials() }) // handle err conn, err := grpc.DialContext( ctx, "xds:///foo.ns.svc.cluster.local:7070", grpc.WithTransportCredentials(creds), )
Modify the gRPC server
-
Modify the gRPC code to create the gRPC server with a special xDS constructor.
import "google.golang.org/grpc/xds" ... server = xds.NewGRPCServer() RegisterFooServer(server, &fooServerImpl) -
If the Go code generated by
protocis outdated, you must regenerate it to ensure compatibility with the xDS server.The generated RegisterFooServer function must have the following signature:
func RegisterFooServer(s grpc.ServiceRegistrar, srv FooServer) { s.RegisterService(&FooServer_ServiceDesc, srv) } -
Modify the gRPC code as follows to enable security support.
creds, err := xds.NewServerCredentials(xdscreds.ServerOptions{FallbackCreds: insecure.NewCredentials()}) // handle err server = xds.NewGRPCServer(grpc.Creds(creds))