一、etcd存储空间为什么总是不够用

相信很多运维同学都遇到过这样的情况:明明集群规模不大,但etcd的存储空间却像吹气球一样快速膨胀。这就像家里的衣柜,明明衣服不多,但总是塞得满满当当。etcd作为Kubernetes的大脑,记录着集群的所有关键数据,但有些数据就像过季的衣服,早就该清理了却一直占着空间。

造成这种情况的主要原因有三个:

  1. 频繁的部署操作会产生大量历史版本数据
  2. 未清理的终止Pod记录会持续堆积
  3. 过大的ConfigMap和Secret像衣柜里的大棉被特别占地方

举个例子,我们有个Java应用每天部署10次,一个月就会产生300个ReplicaSet记录。虽然Kubernetes默认会保留10个旧ReplicaSet,但如果配置不当,这些"过季时装"就会一直堆积。

二、手动清理的常规操作

先教大家几个立竿见影的清理方法,就像给衣柜做次大扫除。我们可以通过etcdctl工具直接操作:

# 查看当前etcd存储使用情况(技术栈:etcdctl + Kubernetes)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
endpoint status

这个命令会返回类似这样的信息:

https://127.0.0.1:2379, 2.5GB, 3.1GB

第二个数字是当前使用量,第三个是配额限制。

对于已经删除的资源残留数据,我们可以手动压缩:

# 获取当前修订版本
rev=$(ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 endpoint status | grep -oE 'revision:[0-9]+' | awk -F: '{print $2}')

# 执行压缩(保留最近10000个版本)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 compact $((rev - 10000))

# 整理磁盘碎片
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 defrag

注意压缩操作需要在所有etcd节点上执行,就像整理衣柜要把所有抽屉都清理一遍。

三、自动维护的进阶方案

手动清理毕竟不是长久之计,我们需要建立自动化机制。这里介绍两种方案:

方案1:调整Kubernetes垃圾回收策略

修改kube-apiserver启动参数,就像设置衣柜的自动整理规则:

# /etc/kubernetes/manifests/kube-apiserver.yaml 片段
spec:
  containers:
  - command:
    - kube-apiserver
    - --etcd-compaction-retention=8h  # 每8小时压缩一次
    - --storage-backend=etcd3
    - --delete-collection-workers=2
    - --api-audiences=https://kubernetes.default.svc

方案2:使用CronJob定期清理

创建一个定时清理Job,就像设置每周一次的衣柜整理闹钟:

# etcd-housekeeper-cronjob.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: etcd-housekeeper
spec:
  schedule: "0 3 * * 6"  # 每周六凌晨3点
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: cleaner
            image: bitnami/etcd:3.4.15
            command:
            - /bin/sh
            - -c
            - |
              rev=$(ETCDCTL_API=3 etcdctl endpoint status | grep -oE 'revision:[0-9]+' | awk -F: '{print $2}')
              etcdctl compact $((rev - 10000))
              etcdctl defrag
          restartPolicy: OnFailure

四、预防胜于治疗的配置优化

除了事后清理,更重要的是从源头控制存储增长:

  1. 调整Deployment的修订历史限制:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  revisionHistoryLimit: 5  # 只保留5个旧版本
  1. 为etcd设置合理的存储配额:
# 启动etcd时设置2GB存储配额
etcd --quota-backend-bytes=2147483648
  1. 监控etcd存储使用情况,配置Prometheus告警规则:
# prometheus-etcd-rules.yaml
groups:
- name: etcd
  rules:
  - alert: EtcdExcessiveStorageUsage
    expr: etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes > 0.8
    for: 10m
    labels:
      severity: warning
    annotations:
      summary: "Etcd storage usage over 80%"

五、特殊情况处理技巧

有时候我们会遇到一些棘手的情况,比如:

场景1:误删了重要资源,但etcd已经压缩过

这时候可以尝试从etcd备份恢复:

# 从快照恢复(技术栈:etcdctl)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
snapshot restore snapshot.db \
--data-dir=/var/lib/etcd-restore

场景2:ConfigMap过大导致性能问题

建议将大配置拆分成多个小ConfigMap,或者改用其他存储方案:

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-part1
data:
  config-part1.json: |
    {"section1": {"item1": "value1"}}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config-part2
data:
  config-part2.json: |
    {"section2": {"item2": "value2"}}

六、经验总结与最佳实践

经过多次实战,我总结了以下黄金法则:

  1. 监控先行:部署Prometheus监控etcd存储增长趋势
  2. 定期维护:设置每周自动压缩和碎片整理
  3. 合理配额:根据集群规模设置etcd存储配额
  4. 精简历史:所有Deployment都设置revisionHistoryLimit
  5. 分离存储:大文件考虑使用PV或对象存储

记住,etcd就像集群的记忆中枢,既不能让它负担过重,也不能让它失忆。通过合理的配置和维护,完全可以让etcd保持轻盈健康的状态。

最后分享一个真实案例:某电商平台在618大促前发现etcd存储使用率已达95%,通过压缩历史版本和调整Deployment配置,在一小时内将使用率降至65%,确保了活动期间集群的稳定运行。