为了账号安全,请及时绑定邮箱和手机立即绑定

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版本,请更新到此版本以获取修复临时报告堆积问题的修复。

如果你看到这些临时报告不断生成,你可以做以下事情,或采取相应措施。

  1. 禁用入院相关的事件报告,请参见this comment
  2. 调整--aggregationWorkers参数以提高处理ephemeralreports的能力,参见this comment。可以通过容器标志这里直接配置,或者通过Helm的extraArgs进行配置。
介绍

我们先来了解一下Amazon EKS的结构,它由两个主要组件组成。

  1. Amazon EKS 的 控制平面
  2. 注册到控制平面的 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.271.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"筛选出特定的存储大小信息。

ETCD出问题了

最近,我遇到了一个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的全面故障。以下是我执行的步骤,以恢复集群的健康状态。

  1. 确定哪些对象占用大量ETCD空间,在我的情况下,是 ephemeralreports资源 导致了问题。
  2. 使用上面的脚本尝试从ETCD中删除这些对象,但由于ETCD完全堵塞,删除失败。
  3. 以关键业务问题联系了AWS支持,并尽可能地升级了问题。很明显我不能从我的端解决这个问题。
  4. 在最初的测试不同脚本的支持调查后,我们无法解锁ETCD存储。因此,EKS/ETCD团队决定将存储从8GB或10GB增加到12GB。
  5. 存储增加到12GB后解开了存储,但这导致了其他问题,即没有任何kubectl命令得到执行。看起来ETCD失去了与API服务器的连接。
  6. 进一步调查和测试显示,API服务器出现延迟,ETCD在处理泄漏的 ephemeralreports资源 时遇到困难。这项调查是由AWS EKS团队内部进行的。
  7. 经过数小时的调试和调查后,认为AWS ETCD团队需要直接从存储中移除这些对象,以便ETCD再次正常运行。
  8. 最后,需要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

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消