为Nginx Ingress配置GRPC协议的后端服务
本文介绍如何使用Nginx Ingress将流量路由到gRPC后端服务。
gRPC介绍
gRPC是一种高性能、通用的RPC开源软件框架,使用Protocol Buffer作为其接口定义语言(IDL)以及底层消息交换格式。同时GRPC采用HTTP/2标准协议实现,提供了多路复用、头部压缩、流控等特性,极大地提高了客户端与服务端的通信效率。更多信息参见Introduction to gRPC。
在gRPC中,客户端应用程序可以直接调用位于不同机器上的服务端应用方法,可以轻松创建分布式应用程序和服务。和许多其他RPC框架一样,使用gRPC需要定义调用服务的方法,包括参数和返回类型等,服务端需要实现被定义的方法,同时运行一个gRPC服务器来处理客户端请求。
准备工作
- 已创建CCE Standard集群,详情请参见购买Standard/Turbo集群。
- 集群中已安装NGINX Ingress控制器。
- 已安装和配置kubectl,详情请参见通过kubectl连接集群。
- 已安装grpcurl工具,详情请参见gRPCurl。
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证书
- 复制以下内容并保存至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
- 复制以下内容保存至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
- 执行以下命令生成证书。
chmod +x ./create.sh && ./create.sh
命令执行成功后,可得到server_key.pem私钥文件和server_cert.pem证书文件。
- 执行以下命令创建名为grpc-secret的TLS Secret。
kubectl create secret tls grpc-secret --key server_key.pem --cert server_cert.pem
步骤2:创建gRPC应用的工作负载
在集群中创建使用gRPC协议的工作负载。
- 复制以下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
- 执行以下命令创建工作负载。
kubectl apply -f grpc.yaml
步骤3:为工作负载创建Service及Ingress
- 复制以下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
- 执行以下命令创建Service:
kubectl apply -f grpc-svc.yaml
- 复制以下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
- 执行以下命令创建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