如何减少 kubernetes 系统资源的 CPU 限制?
How to reduce CPU limits of kubernetes system resources?
我想将我的 GKE 集群中的核心数保持在 3 以下。如果 K8s 复制控制器的 CPU 限制和 pods 从 100m 减少,这将变得更加可行至多 50m。否则,K8s pods 一个核心就占70%
我决定不增加节点的 CPU 能力。在我看来,这在概念上是错误的,因为 CPU 限制被定义为以内核为单位进行测量。相反,我做了以下事情:
- 将 limitranges/limits 替换为默认为“50m”的版本 CPU 限制(不需要,但我认为更清洁)
- 修补 kube-system 命名空间中的所有复制控制器以对所有容器使用 50m
- 正在删除他们的 pods
- 将 kube-system 命名空间中的所有非 rc pods 替换为对所有容器使用 50m 的版本
这是一项繁重的工作,而且可能很脆弱。即将推出的 K8s 版本的任何进一步更改,或 GKE 配置的更改,都可能会破坏它。
那么,有没有更好的方法呢?
更改默认命名空间的 LimitRange spec.limits.defaultRequest.cpu
应该是更改新 Pods 默认值的合法解决方案。请注意,LimitRange 对象是命名空间的,因此如果您使用额外的命名空间,您可能需要考虑它们的合理默认值。
正如您所指出的,这不会影响现有对象或 kube-system 命名空间中的对象。
kube-system 命名空间中的对象大多根据经验调整大小 - 基于观察值。更改这些可能会产生不利影响,但如果您的集群非常小,则可能不会。
我们有一个未解决的问题 (https://github.com/kubernetes/kubernetes/issues/13048) to adjust the kube-system requests based on total cluster size, but that is not is not implemented yet. We have another open issue (https://github.com/kubernetes/kubernetes/issues/13695),可能对某些 kube 系统资源使用较低的 QoS,但同样 - 尚未实现。
其中,我认为#13048 是实现您的要求的正确方法。目前,"is there a better way" 的答案很遗憾是 "no"。我们为中型集群选择了默认值 - 对于非常小的集群,您可能需要做您正在做的事情。
顺便说一下,以防万一你想在 Google Cloud GCE 上尝试这个。如果您尝试更改 kube-dns 等核心服务的 CPU 限制,您将收到类似这样的错误。
spec: Forbidden: pod updates may not change fields other than spec.containers[*].image
, spec.initContainers[*].image
, spec.activeDeadlineSeconds
or spec.tolerations
(only additions to existing tolerations
在 Kubernetes 1.8.7 和 1.9.4 上试过。
所以此时你需要部署的最小节点是n1-standard-1。此外,一旦您拥有多个 pods 和头盔,您的 cpu 中的大约 8% 就会几乎不断地被 Kubernetes 本身吃掉。即使您没有 运行 任何主要负载。我认为有很多轮询正在进行,为了确保集群响应,他们不断刷新一些统计数据。
我发现减少 GKE 集群上系统资源请求的最佳方法之一是使用 vertical autoscaler。
以下是我使用的 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"
Here is a screenshot of what it does to a kube-dns
deployment.
如@Tim Hockin所述,附加组件的默认配置适用于典型集群。但可以通过更改资源限制规范进行微调。
在调整加载项大小之前,请记住您也可以禁用不必要的加载项以供您使用。这可能会因附加组件、其版本、kubernetes 版本和提供商而略有不同。 Google has a page covering some options,其他提供商也可以使用相同的概念
从 @Tim Hockin 答案中链接 的问题的解决方案开始,第一个被接受的方法是使用 插件调整器。它基本上找出最佳限制和要求,修补 Deployment/Pod/DaemonSet 并重新创建关联的 pods 以匹配新限制,但比手动完成所有工作更省力。
但是,另一种更可靠的实现方法是使用 @Tim Smart 答案所述的 Vertical Pod Autoscaler。 VPA 完成了 addon-resizer 的功能,但它有很多好处:
- VPA 是插件本身的自定义资源定义,允许您的代码比使用插件调整器更紧凑。
- 通过自定义资源定义,使实现保持最新也变得容易得多。
- 一些提供商(as google) run VPA resources on control-plane processes, instead of deployments on your worker nodes. Making that, even if addon-resizer is simplier,VPA 使用您的 none 资源,而 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 服务都将其作为一个简单的选项来检查)
Update policy can be Initial (only applies new limits when new pods are created), Recreate (forces pods out of spec to die and applies to new pods), Off (create recommendations but don´t apply), or Auto (currently matches Recreate, can change in the future)
@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(守护进程)
- kube-dns(部署)
- stackdriver-metadata-agent-cluster-level(部署)
通过在其上应用 VPA,我的插件资源需求从 1.6 下降到 0.4。
我想将我的 GKE 集群中的核心数保持在 3 以下。如果 K8s 复制控制器的 CPU 限制和 pods 从 100m 减少,这将变得更加可行至多 50m。否则,K8s pods 一个核心就占70%
我决定不增加节点的 CPU 能力。在我看来,这在概念上是错误的,因为 CPU 限制被定义为以内核为单位进行测量。相反,我做了以下事情:
- 将 limitranges/limits 替换为默认为“50m”的版本 CPU 限制(不需要,但我认为更清洁)
- 修补 kube-system 命名空间中的所有复制控制器以对所有容器使用 50m
- 正在删除他们的 pods
- 将 kube-system 命名空间中的所有非 rc pods 替换为对所有容器使用 50m 的版本
这是一项繁重的工作,而且可能很脆弱。即将推出的 K8s 版本的任何进一步更改,或 GKE 配置的更改,都可能会破坏它。
那么,有没有更好的方法呢?
更改默认命名空间的 LimitRange spec.limits.defaultRequest.cpu
应该是更改新 Pods 默认值的合法解决方案。请注意,LimitRange 对象是命名空间的,因此如果您使用额外的命名空间,您可能需要考虑它们的合理默认值。
正如您所指出的,这不会影响现有对象或 kube-system 命名空间中的对象。
kube-system 命名空间中的对象大多根据经验调整大小 - 基于观察值。更改这些可能会产生不利影响,但如果您的集群非常小,则可能不会。
我们有一个未解决的问题 (https://github.com/kubernetes/kubernetes/issues/13048) to adjust the kube-system requests based on total cluster size, but that is not is not implemented yet. We have another open issue (https://github.com/kubernetes/kubernetes/issues/13695),可能对某些 kube 系统资源使用较低的 QoS,但同样 - 尚未实现。
其中,我认为#13048 是实现您的要求的正确方法。目前,"is there a better way" 的答案很遗憾是 "no"。我们为中型集群选择了默认值 - 对于非常小的集群,您可能需要做您正在做的事情。
顺便说一下,以防万一你想在 Google Cloud GCE 上尝试这个。如果您尝试更改 kube-dns 等核心服务的 CPU 限制,您将收到类似这样的错误。
spec: Forbidden: pod updates may not change fields other than
spec.containers[*].image
,spec.initContainers[*].image
,spec.activeDeadlineSeconds
orspec.tolerations
(only additions to existing tolerations
在 Kubernetes 1.8.7 和 1.9.4 上试过。
所以此时你需要部署的最小节点是n1-standard-1。此外,一旦您拥有多个 pods 和头盔,您的 cpu 中的大约 8% 就会几乎不断地被 Kubernetes 本身吃掉。即使您没有 运行 任何主要负载。我认为有很多轮询正在进行,为了确保集群响应,他们不断刷新一些统计数据。
我发现减少 GKE 集群上系统资源请求的最佳方法之一是使用 vertical autoscaler。
以下是我使用的 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"
Here is a screenshot of what it does to a kube-dns
deployment.
如@Tim Hockin所述,附加组件的默认配置适用于典型集群。但可以通过更改资源限制规范进行微调。
在调整加载项大小之前,请记住您也可以禁用不必要的加载项以供您使用。这可能会因附加组件、其版本、kubernetes 版本和提供商而略有不同。 Google has a page covering some options,其他提供商也可以使用相同的概念
从 @Tim Hockin 答案中链接 的问题的解决方案开始,第一个被接受的方法是使用 插件调整器。它基本上找出最佳限制和要求,修补 Deployment/Pod/DaemonSet 并重新创建关联的 pods 以匹配新限制,但比手动完成所有工作更省力。
但是,另一种更可靠的实现方法是使用 @Tim Smart 答案所述的 Vertical Pod Autoscaler。 VPA 完成了 addon-resizer 的功能,但它有很多好处:
- VPA 是插件本身的自定义资源定义,允许您的代码比使用插件调整器更紧凑。
- 通过自定义资源定义,使实现保持最新也变得容易得多。
- 一些提供商(as google) run VPA resources on control-plane processes, instead of deployments on your worker nodes. Making that, even if addon-resizer is simplier,VPA 使用您的 none 资源,而 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 服务都将其作为一个简单的选项来检查)
Update policy can be Initial (only applies new limits when new pods are created), Recreate (forces pods out of spec to die and applies to new pods), Off (create recommendations but don´t apply), or Auto (currently matches Recreate, can change in the future)
@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(守护进程)
- kube-dns(部署)
- stackdriver-metadata-agent-cluster-level(部署)
通过在其上应用 VPA,我的插件资源需求从 1.6 下降到 0.4。