如何降低Kubernetes系统资源的CPU限制?

28
我希望保持我的GKE集群核心数量不超过3个。如果将K8s复制控制器和Pod的CPU限制从100m降低到最高50m,这将变得更加可行。否则,仅K8s Pod就会占用70%的一个核心。
我决定不增加节点的CPU功率。在我看来,这在概念上是错误的,因为CPU限制被定义为以核心计量。相反,我做了以下事情:
  • 使用默认CPU限制为"50m"的版本替换limitranges/limits(不必要,但在我看来更清洁)
  • 修补kube-system命名空间中所有复制控制器,使其所有容器都使用50m
  • 删除它们的Pod
  • 使用所有容器都使用50m的版本替换kube-system命名空间中的所有非rc Pod
这是很多工作,可能也很脆弱。即将推出的K8s版本或GKE配置的更改可能会破坏它。
那么,有更好的方法吗?
4个回答

13

我发现减少GKE集群系统资源请求的最佳途径之一是使用垂直自动缩放器

这里是我使用的VPA定义:

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: kube-dns-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: Deployment
    name: kube-dns
  updatePolicy:
    updateMode: "Auto"

---

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: heapster-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: Deployment
    name: heapster-v1.6.0-beta.1
  updatePolicy:
    updateMode: "Initial"

---

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: metadata-agent-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: DaemonSet
    name: metadata-agent
  updatePolicy:
    updateMode: "Initial"

---

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: metrics-server-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: Deployment
    name: metrics-server-v0.3.1
  updatePolicy:
    updateMode: "Initial"

---

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: fluentd-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: DaemonSet
    name: fluentd-gcp-v3.1.1
  updatePolicy:
    updateMode: "Initial"

---

apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
  namespace: kube-system
  name: kube-proxy-vpa
spec:
  targetRef:
    apiVersion: "extensions/v1beta1"
    kind: DaemonSet
    name: kube-proxy
  updatePolicy:
    updateMode: "Initial"

这里是一个截图,展示了它对kube-dns部署的影响。


我们的kube-dns终于只占用不到20%的CPU,谢天谢地!但是(当然)似乎存在高默认的RAM请求。现在每个请求都需要262 MiB,这使得它对所有事情来说都不太可用。 - fiws
我正在我们的集群上使用一个修改过的版本:https://github.com/ARISEChurch/autoscaler/tree/arise-tweaks。它似乎对我们的工作负载功能更好,但您的用例可能会有所不同。 - Tim Smart
非常感谢您的配置@TimSmart,您能详细说明使用“auto”和有时使用“initial”的原因吗?此外,您是否遇到过在系统资源上拥有VPA或更新配置时遇到任何问题?谢谢! - lucbas
@fiws vpa-recommender 默认情况下具有 cmd flag --pod-recommendation-min-memory-mb,默认设置为 250。 我已经在 deploy/recommender-deployment.yamlrecommender 容器中添加了以下内容: args: ["--pod-recommendation-min-cpu-millicores=5", "--pod-recommendation-min-memory-mb=40", "--v=4", "--stderrthreshold=info", "--prometheus-address=http://prometheus.monitoring.svc"] - Denis Isaev

12
改变默认命名空间的 LimitRange spec.limits.defaultRequest.cpu 应该是改变新Pod的默认值的合法解决方案。请注意,LimitRange对象是命名空间相关的,因此如果使用额外的命名空间,则可能需要考虑它们的合理默认值。
正如您所指出的,这将不会影响现有对象或kube-system命名空间中的对象。
kube-system命名空间中的对象大多基于经验确定大小-基于观察到的值。更改它们可能会产生不良影响,但如果您的群集非常小,则可能不会产生影响。
我们有一个开放问题(https://github.com/kubernetes/kubernetes/issues/13048),根据总群集大小调整kube-system请求,但是还没有实施。我们有另一个开放问题(https://github.com/kubernetes/kubernetes/issues/13695),也许对一些kube-system资源使用较低的QoS,但同样尚未实施。
其中,我认为#13048是实现您所要求的正确方式。目前,回答“是否有更好的方法”很遗憾是“没有”。我们选择了中等规模群集的默认值-对于非常小的群集,您可能需要做您正在做的事情。

5
根据@Tim Hockin的说法,插件的默认配置适用于典型的集群。但可以通过更改资源限制规范进行微调。
在进行插件调整之前,请记住您还可以禁用不必要的插件以供使用。这可能有所不同,具体取决于插件、其版本、Kubernetes版本和提供者。Google有一个页面涵盖了一些选项,其他提供者也可以使用相同的概念。

根据链接的问题的解决方案@Tim Hockin的回答,使用addon-resizer是目前最可行的方法。它可以找到最佳限制和要求,修补Deployment/Pod/DaemonSet并重新创建相关的Pod以匹配新的限制,但比手动完成所有这些工作要少得多。

然而,另一种更强大的实现方式是使用Vertical Pod Autoscaler,正如@Tim Smart的回答所述。VPA可以实现addon-resizer的功能,但有许多好处:

  • VPA是插件自定义资源定义,使您的代码比使用addon-resizer更加紧凑。
  • 作为自定义资源定义,它也更容易保持实现的最新状态。
  • 一些提供商(例如谷歌)在控制平面进程上运行VPA资源,而不是在您的工作节点上部署。这样即使addon-resizer更简单, VPA也不会使用任何资源,而addon-resizer则会。

更新后的模板如下:

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: <addon-name>-vpa
  namespace: kube-system
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       <addon-kind (Deployment/DaemonSet/Pod)>
    name:       <addon-name>
  updatePolicy:
    updateMode: "Auto"

重要的是要检查您当前集群中使用的插件,因为它们可能因提供商(AWS、Google等)和其Kubernetes实现版本而有很大差异。
请确保在您的集群中安装了VPA插件(大多数Kubernetes服务都将其作为一个简单选项来检查)。

更新策略可以是初始(只在创建新的 Pod 时应用新的限制),重新创建(强制不符合规范的 Pod 死亡并应用于新的 Pod),关闭(创建建议但不应用)或自动(目前与重新创建匹配,未来可能会更改

@Tim Smart的答案示例中唯一的区别是当前api版本为autoscaling.k8s.io/v1,目标的当前api版本为apps/v1,一些提供者的更新版本使用FluentBit代替Fluentd。他的答案可能更适用于早期的Kubernetes版本。

例如,如果您正在使用Google Kubernetes Engine,则当前某些“最重”要求的插件包括:

  • fluentbit-gke(DaemonSet)
  • gke-metadata-server(DaemonSet)
  • kube-proxy(DaemonSet)
  • kube-dns(Deployment)
  • stackdriver-metadata-agent-cluster-level(Deployment)

通过对其应用VPAs,我的插件资源需求从1.6降至0.4。


看起来不错,但仍然无法让 GKE 上的 kube-system pod 减少请求。有什么建议可以作为分析问题的起点吗? - mararn1618
(1) kube-dns和fluentbit-gke:看起来我需要强制删除这些Pod。 (2) kube-proxy:VPA无法选择该Pod,因为kube-proxy似乎是直接在节点上运行,而不是在DaemonSet中运行。 - mararn1618

1
顺便提一下,如果你想在Google Cloud GCE上尝试这个操作,如果你试图更改核心服务(如kube-dns)的CPU限制,则会收到以下错误:
spec:禁止:Pod更新不能更改除spec.containers [*] .image、spec.initContainers [*] .image、spec.activeDeadlineSeconds或spec.tolerations之外的字段(仅添加到现有容忍度)。
已在Kubernetes 1.8.7和1.9.4上尝试。
因此,此时您需要部署的最少节点是n1-standard-1。而且当您拥有几个pod和helm时,即使您没有运行任何重要负载,Kubernetes本身也会占用大约8%的CPU。我认为有很多轮询正在进行,并且为了确保集群响应,他们不断刷新一些统计数据。

1
那么我基本上需要至少一个 n1-standard-1 来专门管理我的 Kubernetes 吗? - Snowball
基本上,至少在谷歌上你不需要为主节点付费。但在AWS上,你必须自己支付主节点的费用。唉,有点遗憾。 - David Dehghan
我认为在谷歌上使用 Kubernetes 引擎时,你也需要支付主节点的费用。 - Snowball
不需要。你只需要为你的工作节点付费。他们一段时间前已经免费提供了主节点。 - David Dehghan
你说得对 - 谢谢。他们的定价页面没有很好地传达信息,但我找到了这篇博客文章:https://cloudplatform.googleblog.com/2017/11/Cutting-Cluster-Management-Fees-on-Google-Kubernetes-Engine.html 无论如何,即使你有大型节点,每个节点仍然限制在110个pod,似乎没有办法增加。所以对我来说还是不可行的 :( - Snowball
我怀疑Kubernetes在任何平台上都无法扩展到每个节点那么多的Pod。你必须拥有一个非常大的实例。它在小规模上管理资源的效率不高。我曾在AWS微实例上运行的负载现在转移到GKE上,可以在n1-standard-2上运行。 - David Dehghan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接