两套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集群再没有发生过空间超过的问题。
在解决步骤的第6步,会执行defrag
命令,这是用来释放碎片文件的。碎片文件是etcd进行compaction
操作后历史的数据,这部分的空间是可以被用来存放新键的。所以在进行完compaction
操作后是没有必要进行defrag
的。只有当etcd的空间满了进行释放空间的操作时才需要进行defrag
操作。
通过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)}'