Use the Proxyless service mesh with gRPC services

Updated at:
Copy as MD

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

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:

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) or grpc.Dial("xds://...") may fail before the bootstrap file or xDS configuration takes effect. You can use holdApplicationUntilProxyStarts to 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

  • Split traffic into different instance groups based on label selectors.

  • Use the ROUND_ROBIN load balancing policy.

  • Use DISABLE and ISTIO_MUTUAL TLS modes.

VirtualService

  • Match requests by header and URI in the format /ServiceName/RPCName.

  • Configure destination hosts and subsets.

  • Configure traffic weight ratios to implement traffic routing.

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

  1. Add the inject.istio.io/templates: grpc-agent annotation to the echo-grpc application pod.

    If your application code supports proxyless mode, you must add the inject.istio.io/templates: grpc-agent annotation to the application pod to enable proxyless mode. Also, add the proxy.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
  2. 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.

  3. Run the following command to create the echo-grpc namespace:

    kubectl create namespace echo-grpc
  4. 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
  5. 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
  6. Verify that the application is deployed successfully.

    1. 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 &
    2. 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 Hostname

      Expected 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

  1. Create a DestinationRule.

    Use a DestinationRule to create a subset for each version of the workload.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Traffic Management Center > DestinationRule. On the page that appears, click Create.

    3. On the Create page, set Namespaces to echo-grpc, enter a Name, and set Host to echo.echo-grpc.svc.cluster.local.

    4. 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.

    5. 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.

    6. Click Create.

  2. Create a VirtualService.

    Use a VirtualService to route 80% of traffic to the v2 subset and 20% to the v1 subset.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Traffic Management Center > VirtualService. On the page that appears, click Create.

    3. On the Create page, set Namespaces to echo-grpc and enter a Name.

    4. 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.

    5. Click Add Route Destination, set Host to echo.echo-grpc.svc.cluster.local, Subset to v2, and Weight to 80.

    6. Click Create.

  3. 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 ServiceVersion

    Expected 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=v2

    The 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.

  1. Create a DestinationRule.

    Use a DestinationRule to enable mTLS on the client side.

    1. Log on to the ASM console.

    2. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    3. 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.

    4. In the left-side navigation pane, choose Traffic Management Center > DestinationRule, and then click Create.

    5. On the Create page, set Namespaces to echo-grpc, enter a Name, and set Host to echo.echo-grpc.svc.cluster.local.

    6. Click Traffic Policy, click Add Policy, switch on Client TLS, and set TLS Mode to Istio Mutual.

    7. Click Create.

  2. 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 TransientFailure

    The request to the echo-grpc application fails because mTLS authentication is not enabled on the server side.

  3. Create a PeerAuthentication policy.

    Use a PeerAuthentication policy to enable mTLS on the server side.

    1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

    2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > PeerAuthentication. On the page that appears, click Create mTLS Mode.

    3. 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.

  4. 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.

Important

Modifying application code to enable the xDS API is supported only for gRPC applications version 1.39.0 and later.

Modify the gRPC client

  1. 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"
  2. 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")
  3. Modify the gRPC code to pass a special TransportCredentials option to DialContext when using mTLS.

    FallbackCreds allows 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

  1. 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)
  2. If the Go code generated by protoc is 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)
    }
  3. 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))