kuberesolver
PPG007 ... 2022-4-12 About 2 min
# kuberesolver
Kubernetes 中,以 Service 部署的 gRPC 服务之间互相调用时,如果只是使用服务的域名形式进行互相访问,如果 clientConnect 每次不重置,则所有的 gRPC 请求都会进入一个 gRPC 实例中,例如下面的代码:
var (
cc *grpc.ClientConn
err error
)
func init() {
cc, err = grpc.Dial("grpc-server-service:8000", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBalancerName(roundrobin.Name))
if err != nil {
panic(err)
}
}
func main() {
http.HandleFunc("/getResponse", func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
values, err := getResps()
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
b, _ := json.Marshal(values)
w.Write(b)
})
http.ListenAndServe("0.0.0.0:8080", nil)
}
func getResps() ([]string, error) {
if err != nil {
return nil, err
}
m := map[string]string{}
values := []string{}
s := proto.NewDemoServiceClient(cc)
for i := 0; i < 10; i++ {
resp, err := s.Demo(context.Background(), &proto.Empty{})
if err != nil {
return nil, err
}
m[resp.Value] = resp.Value
}
for _, v := range m {
values = append(values, v)
}
return values, nil
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
上面的代码中,clientConnect 只有在 init 中才初始化了一次,后续不再改变,调用这个 http 接口发现返回值唯一,说明没有负载均衡。
使用 Kuberesolver (opens new window) 可以实现客户端负载均衡,并且可以监控服务节点的动态上下线。
因为 kuberesolver 需要调用 Kubernetes 的 API,因此首先需要为使用了 kuberesolver 的 gRPC 客户端所在的 Pods 添加 ServiceAccount 及 Role:
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: example
name: kuberesolver
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: example
name: kuberesolver-role
rules:
- apiGroups: [""]
resources: ["endpoints", "pods"]
verbs: ["get", "watch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: kuberesolver-rolebinding
namespace: example
subjects:
- kind: ServiceAccount
name: kuberesolver
namespace: example
roleRef:
kind: Role
name: kuberesolver-role
apiGroup: rbac.authorization.k8s.io
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
将上面对的配置文件中的 namespace 修改为 gRPC server 所在的命名空间,也可以使用 ClusterRole 替代 Role。
然后修改客户端启动函数,首先执行:
go get github.com/sercand/kuberesolver/v3
1
修改客户端连接函数:
func init() {
kuberesolver.RegisterInCluster()
cc, err = grpc.Dial(endpoint, grpc.WithBalancerName(roundrobin.Name), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalln(err)
panic(err)
}
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
其中 endpoint 格式为:kubernetes:///<service.name>.<namespace>:targetPort
,端口号是 gRPC server 在容器中暴露的端口号,不是 gRPC server 的 Kubernetes Service 的端口号。