更新时间:2024-09-26 GMT+08:00
分享

为Nginx Ingress配置GRPC协议的后端服务

本文介绍如何使用Nginx Ingress将流量路由到gRPC后端服务。

gRPC介绍

gRPC是一种高性能、通用的RPC开源软件框架,使用Protocol Buffer作为其接口定义语言(IDL)以及底层消息交换格式。同时GRPC采用HTTP/2标准协议实现,提供了多路复用、头部压缩、流控等特性,极大地提高了客户端与服务端的通信效率。更多信息参见Introduction to gRPC

图1 gRPC示意图

在gRPC中,客户端应用程序可以直接调用位于不同机器上的服务端应用方法,可以轻松创建分布式应用程序和服务。和许多其他RPC框架一样,使用gRPC需要定义调用服务的方法,包括参数和返回类型等,服务端需要实现被定义的方法,同时运行一个gRPC服务器来处理客户端请求。

准备工作

gRPC服务示例

在proto文件中定义如下的gRPC服务,客户端可调用helloworld.Greeter服务的SayHello接口。关于gRPC服务示例的源码,请参见gRPC Hello World

syntax = "proto3";
 
option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";
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;
}

Nginx Ingress中,gRPC服务只运行在HTTPS端口(默认443)上,因此在生产环境中,需要域名和对应的SSL证书。本示例使用 grpc.example.com和自签SSL证书。

步骤1:创建SSL证书

  1. 复制以下内容并保存至openssl.cnf文件中。

    [req]
    distinguished_name = req_distinguished_name
    attributes = req_attributes
     
    [req_distinguished_name]
     
    [req_attributes]
     
    [test_ca]
    basicConstraints        = critical,CA:TRUE
    subjectKeyIdentifier    = hash
    authorityKeyIdentifier  = keyid:always,issuer:always
    keyUsage                = critical,keyCertSign
     
    [test_server]
    basicConstraints        = critical,CA:FALSE
    subjectKeyIdentifier    = hash
    keyUsage                = critical,digitalSignature,keyEncipherment,keyAgreement
    subjectAltName          = @server_alt_names
     
    [server_alt_names]
    DNS.1 = grpc.example.com
     
    [test_client]
    basicConstraints        = critical,CA:FALSE
    subjectKeyIdentifier    = hash
    keyUsage                = critical,nonRepudiation,digitalSignature,keyEncipherment
    extendedKeyUsage        = critical,clientAuth

  2. 复制以下内容保存至create.sh文件中,create.sh与openssl.cnf文件位于同一目录下。

    #!/bin/bash
     
    # Create the server CA certs.
    openssl req -x509                                     \
      -newkey rsa:4096                                    \
      -nodes                                              \
      -days 3650                                          \
      -keyout ca_key.pem                                  \
      -out ca_cert.pem                                    \
      -subj /C=CN/ST=CA/L=SVL/O=gRPC/CN=test-server_ca/   \
      -config ./openssl.cnf                               \
      -extensions test_ca                                 \
      -sha256
     
    # Create the client CA certs.
    openssl req -x509                                     \
      -newkey rsa:4096                                    \
      -nodes                                              \
      -days 3650                                          \
      -keyout client_ca_key.pem                           \
      -out client_ca_cert.pem                             \
      -subj /C=CN/ST=CA/L=SVL/O=gRPC/CN=test-client_ca/   \
      -config ./openssl.cnf                               \
      -extensions test_ca                                 \
      -sha256
     
    # Generate a server cert.
    openssl genrsa -out server_key.pem 4096
    openssl req -new                                    \
      -key server_key.pem                               \
      -days 3650                                        \
      -out server_csr.pem                               \
      -subj /C=CN/ST=CA/L=SVL/O=gRPC/CN=test-server1/   \
      -config ./openssl.cnf                             \
      -reqexts test_server
    openssl x509 -req           \
      -in server_csr.pem        \
      -CAkey ca_key.pem         \
      -CA ca_cert.pem           \
      -days 3650                \
      -set_serial 1000          \
      -out server_cert.pem      \
      -extfile ./openssl.cnf    \
      -extensions test_server   \
      -sha256
    openssl verify -verbose -CAfile ca_cert.pem  server_cert.pem
     
    # Generate a client cert.
    openssl genrsa -out client_key.pem 4096
    openssl req -new                                    \
      -key client_key.pem                               \
      -days 3650                                        \
      -out client_csr.pem                               \
      -subj /C=CN/ST=CA/L=SVL/O=gRPC/CN=test-client1/   \
      -config ./openssl.cnf                             \
      -reqexts test_client
    openssl x509 -req           \
      -in client_csr.pem        \
      -CAkey client_ca_key.pem  \
      -CA client_ca_cert.pem    \
      -days 3650                \
      -set_serial 1000          \
      -out client_cert.pem      \
      -extfile ./openssl.cnf    \
      -extensions test_client   \
      -sha256
    openssl verify -verbose -CAfile client_ca_cert.pem  client_cert.pem
     
    rm *_csr.pem

  3. 执行以下命令生成证书。

    chmod +x ./create.sh && ./create.sh

    命令执行成功后,可得到server_key.pem私钥文件和server_cert.pem证书文件。

  4. 执行以下命令创建名为grpc-secret的TLS Secret。

    kubectl create secret tls grpc-secret --key server_key.pem --cert server_cert.pem

步骤2:创建gRPC应用的工作负载

在集群中创建使用gRPC协议的工作负载。

  1. 复制以下YAML内容创建grpc.yaml文件。本文中使用官方示例应用构建的Docker镜像作为示例。

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      annotations:
        description: ''
      labels:
        appgroup: ''
        version: v1
      name: grpc-hello
      namespace: default
    spec:
      selector:
        matchLabels:
          app: grpc-hello
          version: v1
      template:
        metadata:
          labels:
            app: grpc-hello
            version: v1
        spec:
          containers:
            - name: container-1
              image: swr.cn-east-3.myhuaweicloud.com/container/grpc-hello:latest  #本文镜像仅作示例
              imagePullPolicy: IfNotPresent
          imagePullSecrets:
            - name: default-secret
          terminationGracePeriodSeconds: 30
          dnsPolicy: ClusterFirst
      replicas: 1

  2. 执行以下命令创建工作负载。

    kubectl apply -f grpc.yaml

步骤3:为工作负载创建Service及Ingress

  1. 复制以下YAML内容创建grpc-svc.yaml文件。

    apiVersion: v1
    kind: Service
    metadata:
      name: grpc-hello
      namespace: default
      labels:
        app: grpc-hello
    spec:
      ports:
        - name: cce-service-0
          protocol: TCP
          port: 50051
          targetPort: 50051
      selector:
        app: grpc-hello
      type: NodePort
      sessionAffinity: None

  2. 执行以下命令创建Service:

    kubectl apply -f grpc-svc.yaml

  3. 复制以下YAML内容创建grpc-ingress.yaml文件。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: grpc-hello
      namespace: default
      annotations:
        nginx.ingress.kubernetes.io/backend-protocol: GRPC # 指定后端服务为gRPC服务
    spec:
      ingressClassName: nginx
      tls:
        - secretName: grpc-secret
      rules:
        - host: grpc.example.com
          http:
            paths:
              - path: /
                pathType: Prefix
                backend:
                  service:
                    name: grpc-hello
                    port:
                      number: 50051

  4. 执行以下命令创建Ingress路由规则。

    kubectl apply -f grpc-ingress.yaml

结果验证

本地安装grpcurl工具后,执行以下命令,验证是否安装成功

./grpcurl -insecure -servername "grpc.example.com" <ip_address>:443 list

其中,<ip_address>为负载均衡器的ip地址,可通过kubectl get ingress获取。

预期输出:

grpc.examples.echo.Echo
grpc.reflection.v1.ServerReflection
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter

相关文档