一、背景引入

在咱们搞开发的圈子里,容器化技术那可是越来越火啦。Kubernetes 作为容器编排的一把好手,能帮咱们高效地管理和调度容器。不过呢,Kubernetes 默认的调度策略有时候就有点不太给力,会导致容器资源分配不合理。比如说,有些节点资源被过度占用,而有些节点却闲置着,这就造成了资源的浪费。下面咱就来好好聊聊怎么优化这个默认调度策略,解决容器资源分配的问题。

二、Kubernetes 默认调度策略的基本原理

2.1 调度流程

Kubernetes 的调度器就像一个聪明的小管家,它的工作流程大概是这样的。首先呢,它会从待调度的 Pod 列表里挑一个出来。然后,它会在所有的节点里筛选出符合这个 Pod 要求的节点,这一步叫做预选。预选完成后,还会对这些符合条件的节点进行打分,选出得分最高的节点,这就是优选。最后,把 Pod 调度到这个得分最高的节点上。

2.2 示例说明(Kubernetes YAML 技术栈)

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  containers:
  - name: example-container
    image: nginx:1.14.2
    resources:
      requests:
        memory: "64Mi"
        cpu: "250m"
      limits:
        memory: "128Mi"
        cpu: "500m"

在这个示例里,我们定义了一个 Pod,里面有一个容器。requests 是这个容器请求的资源,limits 是容器使用资源的上限。Kubernetes 调度器在调度这个 Pod 的时候,就会根据这些资源要求去筛选和选择合适的节点。

三、常见的容器资源分配问题

3.1 资源不均衡

有些节点上的 Pod 特别多,资源被大量占用,而有些节点却很空闲。比如说,有两个节点 A 和 B,节点 A 上运行了 10 个 Pod,CPU 和内存都快被占满了,而节点 B 上就只有 1 个 Pod,大部分资源都闲置着。这就造成了资源的不均衡,影响了整个集群的性能。

3.2 资源碎片化

当很多小的 Pod 被调度到一个节点上时,可能会出现资源碎片化的问题。比如,一个节点的内存总量是 1GB,有 10 个 Pod 每个请求 100MB 内存,虽然总量上看是够的,但这些小的内存块可能分布得很分散,导致后续一些需要连续大内存的 Pod 无法调度到这个节点上。

四、优化策略

4.1 节点亲和性和反亲和性

4.1.1 节点亲和性

节点亲和性可以让我们指定 Pod 更倾向于调度到某些节点上。比如说,我们有一些 Pod 需要运行在有 SSD 存储的节点上,就可以通过节点亲和性来实现。

apiVersion: v1
kind: Pod
metadata:
  name: ssd-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: disk-type
            operator: In
            values:
            - ssd
  containers:
  - name: ssd-container
    image: busybox:1.32

在这个示例中,nodeAffinity 部分指定了 Pod 必须调度到带有 disk-type: ssd 标签的节点上。

4.1.2 节点反亲和性

节点反亲和性则是让 Pod 尽量不要调度到某些节点上。比如,为了提高可用性,我们希望同一个应用的不同 Pod 不要都运行在同一个节点上。

apiVersion: v1
kind: Pod
metadata:
  name: anti-affinity-pod
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
              - key: app
                operator: In
                values:
                  - my-app
          topologyKey: "kubernetes.io/hostname"
  containers:
  - name: anti-affinity-container
    image: nginx:1.14.2

这里的 podAntiAffinity 表示同一个 app: my-app 的 Pod 不能调度到同一个节点上。

4.2 资源请求和限制的合理设置

我们要根据实际情况合理设置 Pod 的资源请求和限制。如果设置得太小,可能会导致 Pod 运行不稳定;如果设置得太大,又会造成资源浪费。 比如,一个简单的 Web 应用,它的 CPU 和内存需求可能不会太高,我们可以这样设置:

apiVersion: v1
kind: Pod
metadata:
  name: web-app-pod
spec:
  containers:
  - name: web-app-container
    image: my-web-app:1.0
    resources:
      requests:
        memory: "32Mi"
        cpu: "100m"
      limits:
        memory: "64Mi"
        cpu: "200m"

这样既保证了 Pod 有足够的资源运行,又不会浪费太多资源。

4.3 污点和容忍度

污点可以让节点拒绝某些 Pod 的调度,而容忍度则是让 Pod 可以容忍节点的污点。比如说,我们有一些节点专门用来运行一些特殊的任务,不希望其他普通 Pod 调度到这些节点上,就可以给这些节点添加污点。

# 给节点添加污点
kubectl taint nodes node1 special=true:NoSchedule

然后,对于那些可以运行在这些特殊节点上的 Pod,我们可以设置容忍度:

apiVersion: v1
kind: Pod
metadata:
  name: special-pod
spec:
  tolerations:
  - key: "special"
    operator: "Equal"
    value: "true"
    effect: "NoSchedule"
  containers:
  - name: special-container
    image: special-app:1.0

这样,只有带有容忍度的 Pod 才能调度到带有污点的节点上。

五、应用场景

5.1 多租户环境

在多租户的 Kubernetes 集群中,不同租户的 Pod 可能对资源的需求不同。通过优化调度策略,可以保证每个租户的资源分配合理,避免某个租户过度占用资源影响其他租户。比如说,租户 A 的应用需要大量的 CPU 资源,租户 B 的应用需要大量的内存资源,我们可以通过节点亲和性和资源请求设置,让租户 A 的 Pod 调度到 CPU 资源丰富的节点,租户 B 的 Pod 调度到内存资源丰富的节点。

5.2 高可用性场景

为了提高应用的可用性,我们可以利用节点反亲和性,让同一个应用的不同 Pod 分布在不同的节点上。这样,即使某个节点出现故障,也不会影响整个应用的正常运行。比如,一个分布式数据库应用,我们可以将它的不同副本 Pod 调度到不同的节点上,提高数据的可靠性。

六、技术优缺点

6.1 优点

  • 提高资源利用率:通过优化调度策略,可以让资源更加合理地分配,减少资源的浪费,提高整个集群的资源利用率。
  • 增强应用的稳定性:合理的资源分配可以保证 Pod 有足够的资源运行,减少因资源不足导致的应用崩溃等问题。
  • 提高集群的灵活性:可以根据不同的应用需求和节点特性,灵活地调整调度策略,满足多样化的业务场景。

6.2 缺点

  • 配置复杂:优化调度策略涉及到很多配置项,如节点亲和性、污点和容忍度等,对于新手来说可能比较难理解和配置。
  • 增加管理成本:需要对集群的资源使用情况进行实时监控和调整,增加了管理的工作量。

七、注意事项

7.1 合理评估资源需求

在设置 Pod 的资源请求和限制时,要充分考虑应用的实际需求,不能盲目设置。可以通过对应用的性能测试和监控,来确定合理的资源值。

7.2 定期检查和调整

集群的资源使用情况是动态变化的,所以要定期检查调度策略的效果,根据实际情况进行调整。比如,随着业务的发展,某些应用的资源需求可能会增加,这时就需要相应地调整 Pod 的资源配置。

7.3 避免过度配置

虽然我们希望通过优化调度策略来提高资源利用率,但也不能过度配置。比如,设置过高的资源限制可能会导致资源浪费,而设置过低的资源请求可能会影响应用的性能。

八、文章总结

通过对 Kubernetes 默认调度策略的优化,我们可以有效地解决容器资源分配的问题。我们介绍了节点亲和性、反亲和性、资源请求和限制的合理设置以及污点和容忍度等优化策略,这些策略可以让我们根据不同的应用场景和需求,灵活地调整 Pod 的调度。同时,我们也分析了这些技术的优缺点和注意事项,希望大家在实际应用中能够合理运用这些策略,提高 Kubernetes 集群的性能和资源利用率。