记一次tiller proxy swift和tiller版本兼容性问题

Posted by 爱折腾的工程师 on Sunday, December 29, 2019

环境

  • Kubernetes v1.14.6
  • Etcd 3.3.12
  • Docker 18.09.9
  • Swift 0.9.0
  • Tiller v2.10.0

简介

swift是helm tiller的proxy, 负责把grpc请求转为rest http请求

现象

chart大小超过4M,swift获取release列表就有问题;不通过swift,以harbor chart为例,来重现这个问题

原始chart大小不超过4M

# du -sh harbor/
336K    harbor/

创建一个4M的文件

# fallocate -l 4M harbor/test
# du -sh harbor/
4.4M    harbor/

部署

# helm install -n harbor harbor/
# helm ls
NAME    REVISION        UPDATED                         STATUS          CHART           APP VERSION  NAMESPACE
harbor  1               Mon Dec 30 09:54:14 2019        DEPLOYED        harbor-1.0.0    1.7.0        default  

helm ls是直接通过grpc跟tiller通信的,正常

验证调用swift api,通过k8s apiserver proxy的方式获取所有命名空间的release列表

# export TOKEN=`awk '/token/ {print $2}' ~/.kube/config`
# export SERVER=`awk '/server/ {print $2}' ~/.kube/config`

# curl -X GET $SERVER/api/v1/namespaces/kube-system/services/helm-api:http/proxy/tiller/v2/releases/json?all=true \
    --header "Authorization: Bearer $TOKEN" \
    --cacert /etc/kubernetes/pki/ca.crt 
{"code":8,"message":"grpc: received message larger than max (4639744 vs. 4194304)"} 

调用失败,返回grpc接收的message超过最大值(4194304), 4194304 / 1024 / 1024 = 4M,问题应该出在swift上

分析

确认下版本,swift是0.9.0, helm tiller是2.10.0, 按照官网版本对应的关系是:

Swift Version Helm/Tiller Version
v0.12.1 2.14.0
0.11.1 2.13.0
0.10.0 2.12.0
0.9.0 2.11.0
0.8.1 2.9.0
0.7.3 2.8.0
0.5.2 2.7.0
0.3.2 2.5.x, 2.6.x
0.2.0 2.5.x, 2.6.x
0.1.0 2.5.x, 2.6.x

swift 0.9.0版本对应的tiller版本是2.11.0

查阅helm v2.10.0版本代码,发现tiller已经支持20M, grpc接收/发送默认大小是4M. commit链接 fix(grpc): Fixes issue where message sending limited to 4mb

// maxMsgSize use 20MB as the default message size limit.
// grpc library default is 4MB
var maxMsgSize = 1024 * 1024 * 20

// DefaultServerOpts returns the set of default grpc ServerOption's that Tiller requires.
func DefaultServerOpts() []grpc.ServerOption {
	return []grpc.ServerOption{
		grpc.MaxRecvMsgSize(maxMsgSize),
		grpc.MaxSendMsgSize(maxMsgSize),
		grpc.UnaryInterceptor(newUnaryInterceptor()),
		grpc.StreamInterceptor(newStreamInterceptor()),
	}
}

查阅swift 0.9.0版本代码, 发现grpc没设置接收大小,默认就是4M了

opts := []grpc.DialOption{
        grpc.WithBlock(), // required for timeout 
        grpc.WithUnaryInterceptor(grpc_glog.UnaryClientInterceptor(glogEntry, optsGLog...)),
        grpc.WithStreamInterceptor(grpc_glog.StreamClientInterceptor(glogEntry, optsGLog...)),
}

代码链接:https://github.com/kubepack/swift/blob/0.9.0/pkg/connectors/common.go#L37

查阅swift 0.11.1版本代码, 已经设置grpc接收大小为20M了

maxReceiveMsgSize = 1024 * 1024 * 20
opts := []grpc.DialOption{
        grpc.WithBlock(), // required for timeout
        grpc.WithUnaryInterceptor(grpc_glog.UnaryClientInterceptor(glogEntry, optsGLog...)),
        grpc.WithStreamInterceptor(grpc_glog.StreamClientInterceptor(glogEntry, optsGLog...)),
        grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(maxReceiveMsgSize)),
}

更新验证

tiller镜像更新到gcr.io/kubernetes-helm/tiller:v2.13.0, swift镜像更新到appscode/swift:0.11.1

调用swift api

获取所有命名空间的release

# curl -X GET $SERVER/api/v1/namespaces/kube-system/services/helm-api:http/proxy/tiller/v2/releases/json?all=true \
    --header "Authorization: Bearer $TOKEN" \
    --cacert /etc/kubernetes/pki/ca.crt 

正常返回

获取指定命名空间的release

# curl -X GET $SERVER/api/v1/namespaces/kube-system/services/helm-api:http/proxy/tiller/v2/releases/json?namespace=ceph \
    --header "Authorization: Bearer $TOKEN" \
    --cacert /etc/kubernetes/pki/ca.crt 
{"code":13,"message":"runtime error: invalid memory address or nil pointer dereference"}

看到这个返回,以为是个报错,实际上是因为该命名空间下没有release

参考链接

「真诚赞赏,手留余香」

爱折腾的工程师

真诚赞赏,手留余香

使用微信扫描二维码完成支付