远程过程调用gRPC(Google Remote Procedure Call)是基于HTTP/2协议标准和ProtoBuf(Protocol Buffers)序列化协议开发设计,且支持众多开发语言,继而提供了连接多路复用、头部压缩、流控等特性,极大地提高了客户端与服务端的通信效率。本文介绍如何通过阿里云容器服务Ingress
Controller实现gRPC协议的服务后端的路由功能。
背景信息
gRPC是Google开源的一个高性能RPC通信框架,通过
Protocol Buffers作为其IDL,在不同语言开发的平台上使用,同时gRPC基于HTTP/2协议实现,提供了多路复用、头部压缩、流控等特性,极大地提高了客户端与服务端的通信效率。
在gRPC服务中,客户端应用可以同本地方法一样调用到位于不同服务器上的服务端应用方法,可以很方便地创建分布式应用和服务。同其他RPC框架一样,gRPC也需要定义一个服务接口,同时指定被远程调用的方法和返回类型。服务端需要实现被定义的接口,同时运行一个gRPC服务器来处理客户端请求。
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 Hello World。
示例说明
NGINX Ingress Controller中,gRPC服务只运行在HTTPS端口(默认443)上,因此在生产环境中,需要域名和对应的SSL证书。本示例使用 grpc.example.com
和自签SSL证书。
本示例基于1.20.4-aliyun集群,Nginx Ingress Controller组件版本为v0.44.0.3-8e83e7dc6-aliyun。
若您已有gRPC服务,可直接执行步骤三:创建Ingress路由规则。
步骤一:申请SSL证书
使用Ingress转发gRPC服务需要对应域名拥有SSL证书,使用TLS协议进行通信。
您可以在SSL证书控制台购买证书,也可以通过Let's Encrypt等第三方平台申请免费的SSL证书。
本示例使用OpenSSL生成的自签证书。
- 复制以下内容并保存至/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
- 执行以下命令签署证书请求。
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"
- 执行以下命令签署证书。
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的TLS Secret添加到集群中。
或可通过控制台将TLS Secret添加到集群中。具体操作,请参见
创建保密字典。
kubectl create secret tls grpc-secret --key grpc.key --cert grpc.crt
步骤二:创建gRPC服务所需资源
在集群中创建使用gRPC协议的后端服务。本示例使用镜像registry.cn-hangzhou.aliyuncs.com/acs-sample/grpc-server
创建gRPC服务。
- 复制以下YAML内容创建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
- 执行以下命令创建gRPC Deployment资源以及对应的服务。
kubectl apply -f grpc.yaml
预期输出:
deployment.apps/grpc-service created
service/grpc-service created
- 执行以下命令查看Pod。
kubectl get pod
预期输出:
NAME READY STATUS RESTARTS AGE
grpc-service-57884679-2bkbr 1/1 Running 0 98s
从预期输出可得,
grpc-service-57884679-2bkbr的状态为
Running,已成功启动。
步骤三:创建Ingress路由规则
- 复制以下YAML内容创建grpc-ingress.yaml文件。
注意
- 部署gRPC服务所使用的Ingress需要在annotation中加入
nginx.ingress.kubernetes.io/backend-protocol
,值为GRPC。
- 本示例使用的域名为
grpc.example.com
,请根据实际情况修改。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grpc-ingress
annotations:
# 注意这里:必须要配置以指明后端服务为gRPC服务
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
spec:
# 指定证书
tls:
- hosts:
- grpc.example.com
secretName: grpc-secret
rules:
# gRPC服务域名
- host: grpc.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
# gRPC服务
name: grpc-service
port:
number: 50051
- 执行以下命令创建Ingress路由规则。
kubectl apply -f grpc-ingress.yaml
预期输出:
ingress.networking.k8s.io/grpc-ingress created
结果验证
本地安装gRPCurl工具后,输入grpcurl <域名>:443 list
验证请求是否成功转发到后端服务。
本示例中使用域名grpc.example.com
以及自签证书,执行以下命令验证请求是否成功转发到后端服务。
grpcurl -insecure -authority grpc.example.com <ip_address>:443 list
说明 ip_address为Nginx Ingress Controller的Service外部IP,可通过kubectl get ingress
获取。
预期输出:
grpc.reflection.v1alpha.ServerReflection
helloworld.Greeter
从预期输出可得,流量被Ingress成功转发到后端gRPC服务。
后续步骤
关于如何通过Ingress Controller实现gRPC服务的灰度发布,请参见通过Ingress实现灰度发布和蓝绿发布。
注意 由于Nginx grpc_pass的限制,目前对于gRPC服务,暂不支持service-weight的配置。