共计 3137 个字符,预计需要花费 8 分钟才能阅读完成。
在生产环境集群中,运行一年多突然出现了 etcd 集群空间超过配额的问题。查看 etcd 的告警,发现有 NO SPACE
的信息,并且 etcdctl endpoints status
中的 DB SIZE
大于 2GiB。
版本信息
- etcd 版本:3.3.10(运行方式为 Docker 容器)
解决步骤
1. 将 API 版本调整为 3
export ETCDCTL_API=3
2. 声明变量 ETCD_ENDPOINT
ETCD_ENDPOINT=(https://xx:xx:xx:xx:2379,https://xx:xx:xx:xx:2379,https://xx:xx:xx:xx:2379)
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 证书存放的位置,可以使用 ps
命令查看:
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 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
确保 DB SIZE
无大幅度增长:
etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} endpoints status
参考:压缩完 DB SIZE
是 30MiB,一段时间后涨到 132MiB 后持续不动。
自动压缩机制
etcd 的自动压缩机制用于防止数据大量存入导致性能下降和空间耗尽。压缩完成后,指定 revision
版本之前的数据将不可访问,压缩过的空间将用于存放新键。
自动压缩周期
以 etcd 3.3.x 版本为例:
-
参数:
--auto-compaction-mode=periodic
--auto-compaction-retention=30m
(每 30 分钟压缩一次,保留 30 分钟的数据)
-
压缩逻辑:
- 当前
revision
为 7617,30 分钟后revision
编号为 14221。 - 压缩后,7617 之前的键不可访问。
- 当前
默认配置
cat /etc/etcd.env
# Environment file for etcd v3.3.10
...
ETCD_AUTO_COMPACTION_RETENTION=8
...
- 默认配置说明:
ETCD_AUTO_COMPACTION_RETENTION=8
(保留 8 小时的数据量)--auto-compaction-mode=periodic
(周期压缩)- 最大空间默认 2GiB
问题原因:测试环境中 8 小时的数据量超过 2GiB,导致 etcd 告警。
解决方案
修改 etcd.env
配置:
# 更新保留时间缩短为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 的 metrics 获取,具体指标为 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 | \
egrep ^etcd_mvcc_db_total_size_in_use_in_bytes | awk '{print $2}' | awk '{printf("%.2fMiB",$0/1024/1024)}'