背景
gRPC是Google开源的一个高性能RPC通信框架,通过Protocol Buffers作为其IDL,可以在不同语言开发的平台上使用,同时基于HTTP/2协议实现,继而提供了连接多路复用、头部压缩、流控等特性,极大地提高了客户端与服务端的通信效率。
那么在TKE如何将gRPC服务暴露到公网提供给客户使用呢?本次将给大家展示使用Nginx-Ingress 暴露gRPC服务到公网.
在腾讯云TKE-Ingress案例: TKE-Ingress与Nginx-Ingress共存文章中已经介绍了如何在TKE中部署nginx-ingress,这里就不详细赘述.
部署gRPC服务
服务代码以及镜像构建(以下为gRPC的server demo仅供演示使用,地址: https://github.com/lmdkfs/grpc-demo)
文件结构:
代码语言:txt复制 ~/d/g/grpc-demo tree 一 10/26 12:23:41 2020
.
├── Dockerfile
├── Makefile
├── README.md
├── bin
│ └── grpc-server
├── go.mod
├── go.sum
├── grpcapi
│ ├── grpcapi.pb.go
│ └── grpcapi.proto
└── server.go
2 directories, 9 files
server.go 代码:
代码语言:txt复制package main
import (
"context"
"fmt"
"os/signal"
"log"
"net"
"os"
"grpc-demo/grpcapi"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
)
type grpcServer struct{}
func (*grpcServer) GrpcService(ctx context.Context, req *grpcapi.GrpcRequest) (*grpcapi.GrpcResponse, error) {
fmt.Printf("grpcServer %vn", req)
name, _ := os.Hostname()
input := req.GetInput()
result := "Got input " input " server host: " name
res := &grpcapi.GrpcResponse{
Response: result,
}
return res, nil
}
func main() {
fmt.Println("Starting Server...")
log.SetFlags(log.LstdFlags | log.Lshortfile)
hostname := os.Getenv("SVC_HOST_NAME")
if len(hostname) <= 0 {
hostname = "0.0.0.0"
}
port := os.Getenv("SVC_PORT")
if len(port) <= 0 {
port = "50051"
}
lis, err := net.Listen("tcp", hostname ":" port)
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
opts := []grpc.ServerOption{}
s := grpc.NewServer(opts...)
grpcapi.RegisterGrpcServiceServer(s, &grpcServer{})
// reflection service on gRPC server.
reflection.Register(s)
go func() {
fmt.Println("Server running on ", (hostname ":" port))
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}()
// Wait for Control C to exit
ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
// Block until a signal is received
<-ch
fmt.Println("Stopping the server")
s.Stop()
fmt.Println("Closing the listener")
lis.Close()
fmt.Println("Server Shutdown")
}
grpcapi/grpcapi.proto
代码语言:txt复制syntax = "proto3";
package greet;
option go_package="grpcapi";
message GrpcRequest {
string input = 1;
}
message GrpcResponse {
string response = 1;
}
service GrpcService{
rpc grpcService(GrpcRequest) returns (GrpcResponse) {};
}
生成go代码(在grpcapi 目录下执行):
代码语言:txt复制protoc --go_out=plugins=grpc:. grpcapi.proto
代码语言:txt复制> 注意mac下安装protoc命令: brew install protobuf
执行完成之后会生成 grpcapi.pb.go
文件
打包并生成镜像:
代码语言:txt复制make linux
make docker
将打包好的镜像push到TCR的镜像仓库(我这边测试的地址为: ccr.ccs.tencentyun.com/ruiqingzhu-tke/grpc-server:0.1)
部署grpc-server 服务:
通过nginx-ingress 暴露gRPC 服务
Ingress Nginx暴露gRPC服务的时候,暂时只支持TLS(HTTPS)的方式,而不能通过普通HTTP方式,所以我们要配置TLS secret
生成key: openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout ssl_ingress.key -out ssl_ingress.pem -subj "/CN=grpc.example.com"
生成secret:
kubectl create secret tls grpcserver-secret --cert ssl_ingress.pem --key ssl_ingress.key -n grpcserver
gRPC的访问地址: grpc.example.com:443
ingress.yaml文件内容如下:
代码语言:txt复制apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
name: grpcserver
namespace: grpcserver
spec:
rules:
- host: grpc.example.com
http:
paths:
- backend:
serviceName: grpcserver
servicePort: 50051
tls:
# This secret must exist beforehand
# The cert must also contain the subj-name grpc.example.com
# https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/PREREQUISITES.md#tls-certificates
- secretName: grpcserver-secret
hosts:
- grpc.example.com
部署: kubectl apply -f ingress.yaml
测试调用
测试工具使用grpcurl(mac安装命令: brew install grpcurl)
在本地写hosts: xxx grpc.example.com
代码语言:txt复制> xxx 为nginx-controller的公网ip查看方法:
代码语言:txt复制➜ test_grpc grpcurl -insecure grpc.test.example:443 list
greet.GrpcService
grpc.reflection.v1alpha.ServerReflection
测试调用:
代码语言:txt复制➜ test_grpc grpcurl -insecure grpc.example.com:443 greet.GrpcService/grpcService
{
"response": "Got input server host: grpc-demo-5c4567f989-4p69n"
}
测试成功