Kubernetes Etcd不可用日志:NOSPACE 的问题修复

        两套k8s集群同一天同时出现etcd集群空间超过配额,kubectl get cs时发现所有的etcd均返回503报错,查看etcd的告警发现有NO SPACE的信息且 etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} endpoint status 中的DB SIZE大于2GiB。

        版本信息

  • kubernetes版本:v1.17.0

  • etcd版本:3.3.10,运行方式为docker容器

        解决步骤

注意:修复会导致所有节点Not Ready,需重启各个节点的kubelet

        1、将API版本调整为3

$ export ETCDCTL_API=3

        2、声明变量ETCD_ENDPOINT

export ETCD_ENDPOINT=(https://127.0.0.1:2379)
export ETCD_CAFILE=(/etc/kubernetes/pki/etcd/ca.crt)
export ETCD_CERTFILE=(/etc/kubernetes/pki/etcd/server.crt)
export ETCD_KEYFILE=(/etc/kubernetes/pki/etcd/server.key)

        如果不清楚etcd证书存放的位置可以使用ps命令查看,当然endpoint也可以用这种方法

$ ps -ef | grep -v grep | grep apiserver |sed 's/ /\n/g' | grep etcd
--etcd-cafile=/etc/ssl/etcd/ssl/ca.pem
--etcd-certfile=/etc/ssl/etcd/ssl/node-master-1.pem
--etcd-keyfile=/etc/ssl/etcd/ssl/node-master-1-key.pem
--etcd-servers=https://172.16.200.101:2379,https://172.16.200.102:2379,https://172.16.200.103:2379
--storage-backend=etcd3

        3、备份etcd

$ etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} \
snapshot save /var/lib/etcd/my-snapshot.db

        4、获取当前的修订编号,选取需要截断的历史

$ rev=$(etcdctl --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} endpoint status --write-out="json" |  \
egrep -o '"revision":[0-9]*' | egrep -o '[0-9]*'| awk 'NR==1{print $1}')

        5、按第四步得到的编号进行压缩

$ etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} compact $rev 

        6、释放物理空间

$ etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE}  defrag

此步骤最好将endpoints列表中的节点拆开依次执行,否则容易引起集群震荡

        7、解除告警

$ etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} alarm disarm 

此命令可能需执行两次,确保etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} alarm list再无输出

        8、重启kubelet

        经过一段时候后,如果发现所有节点都是Not Ready状态,只需要将每个节点的kubelet重启即可

$ for node in `kubectl get node --no-headers | awk '{print $1}' | xargs`;do ssh ${node} 'systemctl restart kubelet';done

        9、观察一段时间的DB SIZE,确保无大幅度增长

$ etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} endpoints status

参考:压缩完DB SIZE是30MiB,一段时间涨到132MiB后持续不动

        为什么会超过限值?

        令我感到十分的诧异的是出问题的两套集群分别是30个和33个节点,还有其他节点数更多的集群(48个节点)的etcd不仅是正常的,并且etcd的DB SIZE仅为143MiB,连一半都没到。同时在出现问题两套集群进行完一次修复后,第二天下午又出现etcd空间满的情况。这使我不得不探究下问题发生的原因。

        自动压缩机制

        关于自动压缩机制,官方说为了防止数据大量存入etcd导致性能下降并最终导致空间耗尽,etcd会周期性的将历史的数据进行一次压缩操作。压缩完成后指定revision版本之前的数据都将变得不可访问,同时压缩过的空间将会给新键的存放留出空间。那么这个自动压缩的周期是多少呢?

        由于我这里是3.3.x版本的列子,所以仅阐述3.3.x版本的自动压缩。自动压缩参数--auto-compaction-mode=periodic --auto-compaction-retention=30m表示每30分钟压缩一次,并且每次留存30分钟的数据量。假设现在的revision是7617,30分钟后revision编号是14221,那么压缩后revision编号为7617之前存放的键将不能访问。那么出现问题的etcd默认配置是什么呢?

$ cat /etc/etcd.env 
# Environment file for etcd v3.3.10
...
ETCD_AUTO_COMPACTION_RETENTION=8
...

        这个是默认的配置,保留8小时的数据量,同时压缩模式在未指定是就是periodic,即周期压缩。

--auto-compaction-mode

- Interpret 'auto-compaction-retention' one of: 'periodic', 'revision'. 'periodic' for duration based retention, defaulting to hours if no time unit is provided (e.g. '5m'). 'revision' for revision number based retention.-
- default: periodic
- env variable: ETCD_AUTO_COMPACTION_MODE

但是:不同于不满1小时的数据保留量是按照auto-compaction-retention的配置周期进行压缩。当保留的数据量大于1小时,是按照1h/次的压缩频率进行的。即保留量与压缩频率的关系如下:

if ( "--auto-compaction-retention" < 1h ):

​ 压缩频率 == 1次/"--auto-compaction-retention"

else:

​ 压缩频率 == 1次/h

        即说明出现问题的etcd默认的配置是:每1小时进行一次压缩,并且保留8个小时的数据量,同时最大空间是默认的2GiB。也就是说,如果8个小时的数据量超过了2GiB,就会引发etcd告警。那为什么唯独这两个集群有问题?后来我才发现这两套集群都是测试环境,测试环境嘛,总是会有大量的数据会写入到etcd集群,并且如果不同的业务组同时测试应用会引起etcd频繁的执行创建操作,由于etcd每小时才进行一次压缩,如果1个小时存入的数据过多etcd就会来不及压缩。久而久之,就会到达限额引发告警。反观节点数更多的生产环境,由于很少进行创建操作,DB SIZE自然会很小。理解了这个就明白了如果避免etcd空间告警了。只需etcd.env中修改如下参数并且重启etcd即可:

#更新保留时间缩短为4小时
ETCD_AUTO_COMPACTION_RETENTION=4
#添加etcd最大空间为8GiB的配置
ETCD_QUOTA_BACKEND_BYTES=8589934592

非docker启动的etcd集群参数如下:
--quota-backend-bytes=8589934592  --auto-compaction-retention=4

        再观察了几天之后,这两套etcd集群再没有发生过空间超过的问题。

        KeySpace与存储空间

        在解决步骤的第6步,会执行defrag命令,这是用来释放碎片文件的。碎片文件是etcd进行compaction操作后历史的数据,这部分的空间是可以被用来存放新键的。所以在进行完compaction操作后是没有必要进行defrag的。只有当etcd的空间满了进行释放空间的操作时才需要进行defrag操作。

        如何查看etcd空间的实际使用量?

        通过etcdctl命令查看的DB SIZE是etcd历史最大的数据量大小,不是目前的数据量。etcd对外暴露了mertics提供监控信息,其中名为etcd_mvcc_db_total_size_in_use_in_bytes的值即是目前数据量的大小。查询方法可使用下面的命令:

curl -s --cacert ${ETCD_CA_FILE} --cert ${ETCD_CERT_FILE} --key ${ETCD_KEY_FILE} `echo ${ETCD_ENDPOINTS}   \
| awk -F, '{print $1}'`/metrics -o-| egrep ^etcd_mvcc_db_total_size_in_use_in_bytes | awk '{print $2}' | awk '{printf("%.2fMiB",$0/1024/1024)}'

你可能感兴趣的:(Kubernetes,kubernetes,etcd,容器)