大家好!今天,我们想分享我们使用 Google Kubernetes Engine 管理我们的 Kubernetes 集群的经验。最近三年我们一直在生产中使用它,并且很高兴我们不再需要担心自己管理这些集群。 目前,我们所有的测试环境和独特的基础设施集群都在 Kubernetes 的控制之下。今天,我们想谈谈我们如何在测试集群上遇到问题,以及我们如何希望这篇文章能节省其他人的时间和精力。 我们必须提供有关我们的测试基础设施的信息,以充分了解我们的问题。我们有五个以上的永久性测试环境,并根据要求为开发人员部署环境。工作日白天模块数量达到6000个,并持续增长。由于负载不稳定,我们将模块打包得很紧以节省成本,转售资源是我们最好的策略。 这种配置对我们来说效果很好,直到有一天我们收到警报并且无法删除命名空间。我们收到的有关命名空间删除的错误消息是: $ kubectl delete namespace arslanbekov Error from server (Conflict): Operation cannot be fulfilled on namespaces "arslanbekov": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system. 即使使用强制删除选项也没有解决问题: $ kubectl get namespace arslanbekov -o yaml apiVersion: v1 kind: Namespace metadata: ... spec: finalizers: - kubernetes status: phase: Terminating 为了解决卡住的命名空间问题,我们遵循了 。尽管如此,这个临时解决方案并不理想,因为我们的开发人员应该能够使用命名空间抽象随意创建和删除他们的环境。 一个指南 为了找到更好的解决方案,我们决定进一步调查。警报表明存在指标问题,我们通过运行命令确认了这一点: $ kubectl api-resources --verbs=list --namespaced -o name error: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request 我们发现 metrics-server pod 在日志中遇到内存不足 (OOM) 错误和恐慌错误: apiserver panic'd on GET /apis/metrics.k8s.io/v1beta1/nodes: killing connection/stream because serving request timed out and response had been started goroutine 1430 [running]: 原因是 pod 的资源受到限制: 容器由于其定义而遇到这些问题,定义如下(限制块): resources: limits: cpu: 51m memory: 123Mi requests: cpu: 51m memory: 123Mi 问题是容器只分配了 ,这大约相当于 ,这不足以处理如此大量的 pod 的指标。主要使用 CFS 调度程序。 51m CPU 一个核心 CPU 的 0.05 通常,解决此类问题很简单,只需为 pod 分配更多资源即可。但是,在 GKE 中,此选项在 UI 中或通过 gcloud CLI 不可用。这是因为谷歌保护系统资源不被修改,考虑到所有管理都是在他们这边完成的,这是可以理解的。 我们发现我们不是唯一面临这个问题的人,并且发现了一个 ,作者试图手动更改 pod 定义。他成功了,但我们没有。当我们尝试更改 YAML 文件中的资源限制时,GKE 迅速将它们回滚。 类似的问题 我们需要找到另一种解决方案。 我们的第一步是了解为什么将资源限制设置为这些值。 pod 由两个容器组成: 和 。后者负责在集群中添加或删除节点时调整资源,充当集群垂直自动缩放的看守人。 metrics-server addon-resizer 它的命令行定义如下: command: - /pod_nanny - --config-dir=/etc/config - --cpu=40m - --extra-cpu=0.5m - --memory=35Mi - --extra-memory=4Mi ... 在此定义中,CPU 和内存代表基线资源,而 和 代表每个节点的额外资源。 180个节点的计算如下: extra-cpu extra-memory 0.5m * 180 + 40m=~130m 同样的逻辑也适用于内存资源。 不幸的是,增加资源的唯一方法是添加更多节点,而我们并不想这么做。因此,我们决定探索其他选择。 。我们了解到,YAML 定义中的某些属性可以在不被 GKE 回滚的情况下更改。为了解决这个问题, , ,并根据 。 尽管无法完全解决问题,但我们希望尽快稳定部署 我们将副本数从 1 个增加到 5 个 增加了健康检查 这篇文章 调整了 rollout 策略 这些操作有助于减少 metrics-server 实例的负载,并确保我们始终至少有一个可以提供指标的工作 pod。我们花了一些时间重新考虑这个问题并刷新我们的想法。 回想起来,解决方案最终变得简单明了。 我们深入研究了 addon-resizer 的内部结构,发现它可以通过配置文件和命令行参数进行配置。乍一看,似乎命令行参数应该覆盖配置值,但事实并非如此。 经过调查,我们发现配置文件是通过addon-resizer容器的命令行参数连接到pod的: --config-dir=/etc/config 配置文件被映射为系统命名空间中名称为 的 ConfigMap,GKE 不会回滚此配置! metrics-server-config 我们通过此配置添加资源,如下所示: apiVersion: v1 data: NannyConfiguration: |- apiVersion: nannyconfig/v1alpha1 kind: NannyConfiguration baseCPU: 100m cpuPerNode: 5m baseMemory: 100Mi memoryPerNode: 5Mi kind: ConfigMap metadata: 它奏效了!这对我们来说是一场胜利。 在集群调整大小时,我们保留了两个带有健康检查和零停机策略的 pod,并且在进行这些更改后我们没有再收到任何警报。 结论 如果您有一个密集的 GKE 集群,您可能会遇到 metrics-server pod 的问题。如果每个节点的 Pod 数量接近限制(每个节点 110 个),则分配给 Pod 的默认资源可能不够。 GKE 保护其系统资源,包括系统 pod,并且无法直接控制它们。但是,有时可以找到解决方法。 请务必注意,无法保证该解决方案在未来更新后仍然有效。我们只在我们的测试环境中遇到过这些问题,我们有一个资源超卖策略,所以虽然令人沮丧,但我们仍然可以管理它。