在Nginx Ingress Controller后端部署gRPC服务

如果您的服务采用分布式架构,您可以使用gRPC协议提升客户端与服务器端的通讯效率。将使用gRPC协议的服务部署在Nginx Ingress Controller的后端时,您需要对Ingress资源进行特殊的配置。

背景信息

gRPC(Google Remote Procedure Call)是一个基于HTTP/2协议标准和ProtoBuf(Protocol Buffers)序列化协议设计的远程过程调用(RPC)框架。它由Google开源,支持在多语言开发的平台上使用。其因其高效、灵活和跨语言的特性,gRPC适用于分布式系统和微服务架构场景,例如微服务间调用、物联网设备间通讯、使用复杂数据结构的远程API服务等。

gRPC服务示例

定义如下gRPC服务,客户端可调用helloworld.Greeter服务的SayHello接口。

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

更多gRPC服务示例,请参见grpc-go

前提条件

步骤一:将SSL证书保存到集群Secret资源中

使用Nginx Ingress Controller时,gRPC服务只运行在HTTPS端口(默认443)上,因此需要使用SSL证书。证书需要以Secret资源的方式保存在集群中。

(可选)生成自签名证书

如果您暂未拥有证书,您可参照下方的步骤生成自签名证书,示例中使用grpc.example.com作为证书的域名。

重要

由于缺乏可靠的CA认证,自签名证书在浏览器和客户端中默认不受信任,通常会导致客户访问时收到安全警告。本文中生成的自签名证书仅作为示例,请勿在生产环境中使用。

  1. 创建并拷贝以下内容至/tmp/openssl.cnf文件中。

    [ req ]
    #default_bits           = 2048
    #default_md             = sha256
    #default_keyfile        = privkey.pem
    distinguished_name      = req_distinguished_name
    attributes              = req_attributes
    req_extensions          = v3_req
    
    [ req_distinguished_name ]
    countryName                     = Country Name (2 letter code)
    countryName_min                 = 2
    countryName_max                 = 2
    stateOrProvinceName             = State or Province Name (full name)
    localityName                    = Locality Name (eg, city)
    0.organizationName              = Organization Name (eg, company)
    organizationalUnitName          = Organizational Unit Name (eg, section)
    commonName                      = Common Name (eg, fully qualified host name)
    commonName_max                  = 64
    emailAddress                    = Email Address
    emailAddress_max                = 64
    
    [ req_attributes ]
    challengePassword               = A challenge password
    challengePassword_min           = 4
    challengePassword_max           = 20
    
    [v3_req]
    # Extensions to add to a certificate request
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName = @alt_names
    
    [alt_names]
    DNS.1 = grpc.example.com
  2. 执行以下命令签署证书请求。

    openssl req -new -nodes -keyout grpc.key -out grpc.csr -config /tmp/openssl.cnf -subj "/C=CN/ST=Zhejiang/L=Hangzhou/O=AlibabaCloud/OU=ContainerService/CN=grpc.example.com"
  3. 执行以下命令签署证书。

    openssl x509 -req -days 3650 -in grpc.csr -signkey grpc.key -out grpc.crt -extensions v3_req -extfile /tmp/openssl.cnf

    命令执行成功后,可得到证书grpc.crt与私钥文件grpc.key。

执行以下命令,将证书通过grpc-secret添加到集群中。

kubectl create secret tls grpc-secret --key grpc.key --cert grpc.crt # grpc.key替换为您的证书文件,grpc.crt替换为您的私钥文件

步骤二:创建gRPC服务

  1. 创建并将以下内容拷贝到grpc.yaml文件中。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: grpc-service
    spec:
      replicas: 1
      selector:
        matchLabels:
          run: grpc-service
      template:
        metadata:
          labels:
            run: grpc-service
        spec:
          containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs-sample/grpc-server:latest
            imagePullPolicy: Always
            name: grpc-service
            ports:
            - containerPort: 50051
              protocol: TCP
          restartPolicy: Always
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: grpc-service
    spec:
      ports:
      - port: 50051
        protocol: TCP
        targetPort: 50051
      selector:
        run: grpc-service
      sessionAffinity: None
      type: NodePort
  2. 执行以下命令创建gRPC服务。

    kubectl apply -f grpc.yaml

    预期输出:

    deployment.apps/grpc-service created
    service/grpc-service created

步骤三:创建Ingress

  1. 创建并拷贝以下内容到grpc-ingress.yaml文件中。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: grpc-ingress
      annotations:
        # 必须指明后端服务为gRPC服务
        nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
    spec:
      # 指定通过Secret保存的SSL证书
      tls:
      - hosts:
        - grpc.example.com
        secretName: grpc-secret
      rules:
      - host: grpc.example.com # gRPC服务域名,替换为您的域名
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                # gRPC服务
                name: grpc-service
                port:
                  number: 50051
    重要

    由于Nginx grpc_pass的限制,目前对于gRPC服务,暂不支持service-weight的配置。

  2. 执行以下命令创建Ingress。

    kubectl apply -f grpc-ingress.yaml

    预期输出:

    ingress.networking.k8s.io/grpc-ingress created

步骤四:效果验证

  1. 执行以下命令,查看Ingress信息。

    kubectl get ingress

    预期输出:

    NAME           CLASS   HOSTS              ADDRESS         PORTS     AGE
    grpc-ingress   nginx   grpc.example.com   139.196.*****   80, 443   3m51s

    记录ADDRESS对应的IP地址。

  2. 使用grpcurl连接服务。

    grpcurl -insecure -authority grpc.example.com <IP_ADDRESS>:443 list # <IP_ADDRESS>替换为上一步中记录的IP地址

    输出如下,表明流量被Ingress成功转发到后端gRPC服务:

    grpc.reflection.v1alpha.ServerReflection
    helloworld.Greeter

相关文档