升级K8s APIServer使用etcdv3 API后,etcdctl查询返回乱码求助
我来帮你分析下这个问题,你遇到的etcdctl读取乱码、新Pod数据无法正常读取的情况,主要是两个核心原因导致的:
1. etcdctl的API版本和Kubernetes写入数据的API版本不匹配
etcd v3.x版本的etcdctl默认是用v3 API来操作的,但Kubernetes 1.7.x不会自动切换到etcd3存储后端——除非你显式给APIServer加上--storage-backend=etcd3参数。如果你的APIServer没设置这个参数,哪怕etcd已经升级到v3,K8s依然会用etcd2 API往etcd集群里写数据(etcd v3是兼容v2 API的)。这时候用默认v3模式的etcdctl去读,自然找不到存在v2键空间里的数据,或者读到不兼容的格式,就会显示乱码。
反过来,如果你的APIServer因为etcd集群的配置触发了自动切换(比如端点配置的是etcd v3的地址),用了etcd3 backend,那数据会存在v3键空间,但etcdctl默认读取时可能需要指定正确的前缀或者命令才能识别。
2. 存储媒体类型导致二进制数据显示乱码
如果Kubernetes真的用了etcd3 backend,它默认的storage-media-type是application/vnd.kubernetes.protobuf——这是一种二进制序列化格式,不是明文的JSON。直接用etcdctl get读取的话,看到的就是二进制乱码,而不是可读的文本内容。
解决步骤:
第一步:先确认K8s用的是哪个存储后端
先检查APIServer的启动参数,看看是不是真的用了etcd3:
# CoreOS上K8s组件大多跑在pod里,先查kube-apiserver的参数 kubectl describe pod kube-apiserver-$(hostname) -n kube-system | grep -E "storage-backend|storage-media-type"
如果输出里没有--storage-backend=etcd3,说明K8s用的是etcd2 backend,数据存在etcd的v2键空间。
第二步:用对应API版本的etcdctl读取数据
如果是etcd2 backend:
你需要让etcdctl切换到v2模式来读数据,要么加参数:# 举个读取default namespace下某个Pod的例子,替换成你的实际路径 etcdctl --use-etcdv2 get /registry/pods/default/<你的Pod名称>要么设置环境变量让etcdctl默认用v2:
export ETCDCTL_API=2 etcdctl get /registry/pods/default/<你的Pod名称>如果是etcd3 backend:
首先etcdctl默认就是v3模式,直接读的话看到的是二进制protobuf数据,确实会乱码。如果要读可读内容,更推荐用Kubernetes的原生命令,比如kubectl get pod <Pod名称> -o yaml,比直接读etcd方便得多。要是一定要用etcdctl看,你可以配合protobuf解码工具,但过程比较繁琐,不如用kubectl直接查资源。
第三步:如果想彻底切换到etcd3(可选)
如果你打算长期用etcd3 API,需要修改APIServer的启动参数,加上:
--storage-backend=etcd3 --storage-media-type=application/vnd.kubernetes.protobuf # 这是etcd3 backend的默认值,也可以指定成application/json,但性能会稍差
改完后重启kube-apiserver,不过要注意:切换存储后端之前一定要备份etcd数据,而且需要重新初始化或者迁移现有数据,不然会出现数据不一致的问题。
另外补充下:Kubernetes 1.7.x对etcd3的支持还比较早期,要是遇到兼容性问题,也可以直接给APIServer加上--storage-backend=etcd2参数,利用etcd v3对v2 API的兼容性,这样数据还是用JSON格式存储,etcdctl用v2模式就能正常读取了。
内容的提问来源于stack exchange,提问作者Kun Li

