Amazon EKS-管理和修复ETCD数据库大小问题
这里有个故事,讲述如何排查和解决在使用EKS时遇到的ETCD数据库问题。首先,你会了解我是如何由于ETCD负载过高,把我们的EKS集群搞瘫痪了的。
(更新 2024年06月14日)
本文中提到的 kyverno 问题已被团队视为最高优先级处理。该问题特别与 kyverno 1.12 版本相关,请关注此 github 问题,以避免生成过多的 ephemeralreports
。kyverno 团队正在努力尽快发布 1.12.4 版本以解决该问题。请注意,已经在 1.12.4-rc2 版本中提供了一个修复。
此外,这不是第一次在资源报告中发现 ETCD 过载的情况,因此,目前提出了一种名为 kyverno 报告服务器的解决方案。如需更多信息,请参阅 -> https://kyverno.io/blog/2024/05/29/kyverno-reports-server-the-ultimate-solution-to-scale-reporting/
更新于 07/01/2024
Kyverno v1.12.4现已发布。如果您正在使用1.12版本,请更新到此版本以获取修复临时报告堆积问题的修复。
如果你看到这些临时报告不断生成,你可以做以下事情,或采取相应措施。
- 禁用入院相关的事件报告,请参见this comment
- 调整
--aggregationWorkers
参数以提高处理ephemeralreports的能力,参见this comment。可以通过容器标志这里直接配置,或者通过Helm的extraArgs进行配置。
我们先来了解一下Amazon EKS的结构,它由两个主要组件组成。
- Amazon EKS 的 控制平面
- 注册到控制平面的 Amazon EKS 节点
亚马逊EKS控制平面由运行如ETCD和Kubernetes API服务器等Kubernetes软件的控制节点组成。控制平面运行在由AWS管理的账户中,,并通过该端点公开Kubernetes API,该端点与您的集群相关联。每个亚马逊EKS集群的控制平面都是单租户且独一无二的,并运行在自己的Amazon EC2实例集上。
ETCD节点及其关联的Amazon EBS卷存储的所有数据都使用AWS KMS进行加密。集群控制平面分布在多个可用区中,并并通过Amazon的网络负载均衡器进行前端部署。Amazon EKS还在您的VPC子网中提供了弹性网络接口,以实现控制平面实例与节点之间的连接(例如,支持kubectl exec
logs
proxy
数据传输)。
EKS 1.30 和与之匹配的 CLI
> $ kubectl version
客户端版本:v1.30.1
Kustomize 版本:v5.0.4–0.20230601165947–6ce0bf390ce3
服务器版本:v1.30.0-eks-036c24b
ETCD是什么?为什么保护它非常重要,而且要确保它永远不会达到极限?
ETCD 是一个开源的、分布式的、一致性的键值数据存储。在我的 Kubernetes 集群(例如 EKS)中,所有对象都会被持久化存储并在 ETCD 中进行追踪。ETCD 旨在作为配置管理、服务发现和分布式工作协调的键值存储来使用。etcd 的 文档 提供了使用场景及与其他系统的对比。当创建一个 EKS 集群时,Amazon EKS 为 Kubernetes 中的 ETCD 设置了 推荐的最大数据库大小,即 8GB。虽然对于大多数使用场景来说,8GB 的 etcd 数据库已经足够,但在某些有效和意外的情况下,最大允许的数据库大小可能会被超出。
值得注意的是,当数据库大小限制被超过时,ETCD 会发出没有空间的警报并停止接受新的写入请求。本质上,EKS 集群进入只读模式,所有修改对象(如创建新 pod 或扩展部署)的请求都将被 API 服务器拒绝。此外,用户将无法删除对象或对象修订以释放 ETCD 存储空间。这主要是因为删除依赖于 compact 操作来清理对象,而当无空间警报激活时,compact 操作将被禁止。不过 compact 只能释放 ETCD 数据库内的空间,但不会释放文件系统中 etcd 数据库占用的空间。要将空间归还操作系统并减小 ETCD 数据库大小,需要运行 defrag 操作来实现。
监控控制平面相关的指标,尤其是ETCD的指标监控 Kubernetes API 指标可以帮助你了解控制平面的运行状况并识别问题。不健康的控制平面可能会影响集群内工作负载的可用性。例如,编写不当的控制器可能导致 API 服务器过载,影响应用程序的可用性。
Kubernetes 在 /metrics
端点提供了控制平面的指标。
使用 kubectl
可以查看暴露的指标数据。
运行命令 kubectl get --raw /metrics
获取 Kubernetes 集群的度量数据。
这个信息非常重要,尤其是在频繁使用/metrics端点时,特别是当ETCD存储遇到问题时。
重要提示: 根据上游指导,在Amazon EKS环境中,etcd
存储限制为8 GiB,。你可以通过运行以下命令来查看当前数据库大小。如果你的Kubernetes版本低于1.28
,请将 _apiserver_storage_size_bytes_
替换为以下内容:
• Kubernetes 版本 1.27
和 1.26
– **apiserver_storage_db_total_size_in_bytes**
• Kubernetes 版本 1.25
及以下版本 – **etcd_db_total_size_in_bytes**
kubectl get --raw=/metrics | grep "apiserver_storage_size_bytes"
此处命令用于获取API服务器存储大小的度量数据。通过kubectl get --raw=/metrics
获取所有度量数据,并使用grep "apiserver_storage_size_bytes"
筛选出特定的存储大小信息。
最近,我遇到了一个EKS集群的生产问题,该问题正好处于只读模式,因为ETCD数据库的空间已满。这是一个P1级别的事故,需要花数小时与AWS支持一起解决这个问题。
所以让我展示一下我收集并借助AWS处理的一些信息,我也从中学习了不少东西。
首先需要指出的是,基于我的经验,Amazon EKS集群自带8GB的ETCD存储空间,但这只是一个软性限制。硬性限额是10GB,我们也突破了这个限制,这导致了严重的锁定问题。整个由AWS集中管理的EKS控制平面也因此出现严重锁定问题。
如何判断ETCD空间不足?Amazon EKS 控制面日志功能直接从集群的控制面提供审核和诊断日志至您的 Amazon CloudWatch 账户。可以启用的日志类型之一为 Kubernetes 审核日志,审核日志记录了对您集群造成影响的个别用户、管理员或系统组件。当集群的 ETCD 数据库大小超出限制时,审核日志会记录错误响应“数据库空间超出”。您可以使用以下 Amazon CloudWatch 日志洞察查询 查找首次出现此错误消息的时间戳。
字段:@timestamp, @message, @logStream
| 筛选 @logStream 包含 /kube-apiserver-audit/
| 筛选 @message 包含 /mvcc: 数据库空间已满/
| 限制为 10
responseObject.code 500
responseObject.kind 状态类型
responseObject.message etcdserver: mvcc: 数据库空间已满
responseObject.status 失败状态
如识内容在消耗ETCD数据库空间
对象计数功能
可能会出现存储在ETCD中的总对象数量增加导致存储消耗增加的情况。Kubernetes API服务器提供了一个指标,显示按类型分类的对象数量。
# 1.22 及更高版本,如下命令:
kubectl get --raw=/metrics | grep apiserver_storage_objects | awk '$2>100' | sort -g -k 2
# 1.21 及之前的版本,如下命令:
kubectl get --raw=/metrics | grep etcd_object_counts | awk '$2>100' | sort -g -k 2
示例输出如下:
// 获取 metrics 并筛选 apiserver 存储对象数量大于 100 的条目
$ kubectl get --raw=/metrics | grep apiserver_storage_objects |awk '$2>100' |sort -g -k 2
apiserver_storage_objects{resource="controllerrevisions.apps"} 109
apiserver_storage_objects{resource="externalsecrets.external-secrets.io"} 116
apiserver_storage_objects{resource="rolebindings.rbac.authorization.k8s.io"} 124
apiserver_storage_objects{resource="customresourcedefinitions.apiextensions.k8s.io"} 128
apiserver_storage_objects{resource="clusterrolebindings.rbac.authorization.k8s.io"} 135
apiserver_storage_objects{resource="policyreports.wgpolicyk8s.io"} 135
apiserver_storage_objects{resource="deployments.apps"} 163
apiserver_storage_objects{resource="clusterroles.rbac.authorization.k8s.io"} 170
apiserver_storage_objects{resource="serviceaccounts"} 171
apiserver_storage_objects{resource="configmaps"} 187
apiserver_storage_objects{resource="secrets"} 217
apiserver_storage_objects{resource="pods"} 619
apiserver_storage_objects{resource="replicasets.apps"} 1091
apiserver_storage_objects{resource="admissionreports.kyverno.io"} 2854
apiserver_storage_objects{resource="events"} 2955
如何释放etcd的空间?
您可以使用 kubectl delete 命令来移除未使用或孤立的对象。
例如,下面的 shell 脚本展示了如何删除 admissionreports.kyverno.io 和/或 ephemeralreports.reports.kyverno.io 对象。
#!/bin/bash
COUNTER=5 # 将计数器设置为待删除对象总数除以$LIMIT
LIMIT=1000 # 每个 kubectl 调用中待删除的对象数量
# 如果脚本输出:Error from server (NotFound): the server could not find the requested resource,这可能意味着以下参数配置有误
GROUP="reports.kyverno.io" # 根据需要替换为自己的资源组
VERSION="v1" # 根据需要替换为自己的资源版本
NAMESPACE="trading" # 根据需要替换为自己的资源命名空间
KIND="ephemeralreports" # 根据需要替换为自己的资源种类
# 取消注释以删除 admissionreports
# GROUP="kyverno.io"
# VERSION="v2"
# NAMESPACE="trading"
# KIND="admissionreports"
function formRequestURI(){
echo "/apis/$GROUP/$VERSION/namespaces/$NAMESPACE/$KIND"
}
requestURI=$(formRequestURI)
echo "即将删除不需要的对象,requestURI: $requestURI, 计数器: $COUNTER, 限制: $LIMIT"
for (( i = 1; i <= $COUNTER; i++ ))
do
$(kubectl delete --now=true --wait=false --raw $requestURI?limit=$LIMIT)
done
备注:
- 计数器- 客户可以根据需要调整for循环的迭代次数。
- limit- 由于存在已知问题,如果不指定适当的限制,
kubectl delete --now=true --wait=false --raw $requestURI
可能会超时,详情请参阅:Github链接。 - 要形成requestURI- 通常资源-uri的形成如下:
/apis/<group>/<version>/namespaces/<namespace>/<kind>
,详情请参阅官方文档中的资源URI部分:文档链接。
需要注意的是,通过我的观察,上述脚本仅在 ETCD 未被锁定时才有效。所以请务必监控您的 ETCD 大小,并确保永远不要达到 8GB 的上限。
故障EKS和ETCD的解决步骤如下我用EKS 1.30导致了ETCD的全面故障。以下是我执行的步骤,以恢复集群的健康状态。
- 确定哪些对象占用大量ETCD空间,在我的情况下,是 ephemeralreports资源 导致了问题。
- 使用上面的脚本尝试从ETCD中删除这些对象,但由于ETCD完全堵塞,删除失败。
- 以关键业务问题联系了AWS支持,并尽可能地升级了问题。很明显我不能从我的端解决这个问题。
- 在最初的测试不同脚本的支持调查后,我们无法解锁ETCD存储。因此,EKS/ETCD团队决定将存储从8GB或10GB增加到12GB。
- 存储增加到12GB后解开了存储,但这导致了其他问题,即没有任何kubectl命令得到执行。看起来ETCD失去了与API服务器的连接。
- 进一步调查和测试显示,API服务器出现延迟,ETCD在处理泄漏的 ephemeralreports资源 时遇到困难。这项调查是由AWS EKS团队内部进行的。
- 经过数小时的调试和调查后,认为AWS ETCD团队需要直接从存储中移除这些对象,以便ETCD再次正常运行。
- 最后,需要AWS首席工程师介入处理,他需要得到我的同意和AWS高层总监的批准,才能直接从ETCD中使用类似命令如“meks etcdctl delete — prefix — key “/registry/reports.kyverno.io/ephemeralreports/trading” — create-review ”清除这些对象。
最后一步,直接从ETCD中删除泄露的那些对象解决了这个问题,EKS再次正常运行。
如果你感兴趣的话,整个问题花了超过7个小时才解决完,我多次明确告诉AWS支持团队,他们应该立即通过他们那边的ETCD来移除这些对象。我之前遇到过ETCD的问题,所以我知道这可能是必要的。这么长时间的生产事故本可以由7小时缩短到30分钟,然而,AWS支持团队更倾向于不听从我的建议。我甚至书面授权他们立即从ETCD移除对象。
我希望这个故事中的事情不会发生在你身上。不过,如果你遇到了这样的问题,你就知道怎么处理这些问题了。
赞助我一下 [在 GitHub Sponsors 上赞助 @marcincuber 赞助支持大家好,我是 Marcin,一名专注于 DevOps 领域的高级工程师。我也是获得了 AWS 解决方案认证的专业人士…github.com](https://github.com/sponsors/marcincuber?source=post_page-----b6fb875888cb--------------------------------)
就像我在Medium上写的其他任何故事一样,我完成了文中记录的任务。这就是我在研究过程中遇到的问题。
谢谢大家的阅读,Marcin Cuber
共同学习,写下你的评论
评论加载中...
作者其他优质文章