节点

OpenShift Container Platform 4.12

在 OpenShift Container Platform 中配置和管理节点

摘要

本文提供有关在集群中配置和管理节点、Pod 和容器的说明。它还提供有关配置 Pod 调度和放置、使用作业(job)和 DaemonSet 来自动执行操作,以及确保集群保持高效性的其他任务信息。

第 1 章 节点概述

1.1. 关于节点

节点是 Kubernetes 集群中的虚拟机或裸机。Worker 节点托管您的应用程序容器,分组为 pod。control plane 节点运行控制 Kubernetes 集群所需的服务。在 OpenShift Container Platform 中,control plane 节点不仅仅包含用于管理 OpenShift Container Platform 集群的 Kubernetes 服务。

在集群中运行稳定和健康的节点是基本运行托管应用程序的基本操作。在 OpenShift Container Platform 中,您可以通过代表节点的 Node 对象访问、管理和监控节点。使用 OpenShift CLI(oc)或 Web 控制台,您可以在节点上执行以下操作。

节点的以下组件负责维护运行 pod 并提供 Kubernetes 运行时环境。

  • 容器运行时:容器运行时负责运行容器。Kubernetes 提供多个运行时,如 containerd、cri-o、rktlet 和 Docker。
  • kubelet:: Kubelet 在节点上运行并读取容器清单。它确保定义的容器已启动且正在运行。kubelet 进程维护工作和节点服务器的状态。kubelet 管理网络流量和端口转发。kubelet 管理仅由 Kubernetes 创建的容器。
  • kube-proxy:: Kube-proxy 在集群的每个节点上运行,并维护 Kubernetes 资源之间的网络流量。Kube-proxy 可确保网络环境被隔离并可访问。
  • DNS:: 集群 DNS 是一个 DNS 服务器,它为 Kubernetes 服务提供 DNS 记录。由 Kubernetes 启动的容器会在其 DNS 搜索中自动包含此 DNS 服务器。
control plane 和 worker 节点概述

读取操作

通过读操作,管理员可以或开发人员获取 OpenShift Container Platform 集群中节点的信息。

管理操作

作为管理员,您可以通过几个任务轻松地在 OpenShift Container Platform 集群中管理节点:

增强操作

OpenShift Container Platform 不仅支持访问和管理节点;作为管理员,您可以在节点上执行以下任务,使集群更高效、应用程序友好,并为开发人员提供更好的环境。

1.2. 关于 pod

pod 是节点上共同部署的一个或多个容器。作为集群管理员,您可以定义 pod,为它分配在准备好调度和管理的健康节点上运行。只要容器正在运行,pod 就会运行。在 Pod 被定义并运行后,您无法更改它。使用 pod 时,您可以执行的一些操作包括:

读取操作

作为管理员,您可以通过以下任务来获取项目中的 pod 信息:

管理操作

以下任务列表概述了管理员如何在 OpenShift Container Platform 集群中管理 pod。

增强操作

您可以使用 OpenShift Container Platform 中提供的各种工具和功能,更轻松地使用 pod。以下操作涉及使用这些工具和功能来更好地管理 pod。

操作用户更多信息

创建并使用 pod 横向自动扩展。

开发者

您可以使用 pod 横向自动扩展来指定您要运行的 pod 的最小和最大数量,以及 pod 的目标 CPU 使用率或内存使用率。通过使用 pod 横向自动扩展,您可以自动扩展 pod

安装和使用垂直 pod 自动缩放器

管理员和开发人员

作为管理员,通过监控资源和资源要求,使用垂直 pod 自动扩展来更好地利用集群资源。

作为开发人员,使用垂直 pod 自动扩展来确保 pod 在高负载时可以继续工作,方法是将 pod 调度到具有每个 pod 充足资源的节点。

使用设备插件提供对外部资源的访问。

Administrator

设备插件是在节点(kubelet 的外部)上运行的 gRPC 服务,用于管理特定的硬件资源。您可以部署设备插件,以提供一致且可移植的解决方案,以便在集群中使用硬件设备。

使用 Secret 对象 向 pod 提供敏感数据。

Administrator

有些应用程序需要敏感信息,如密码和用户名。您可以使用 Secret 对象向应用程序 pod 提供此类信息。

1.3. 关于容器

容器是 OpenShift Container Platform 应用程序的基本单元,它由应用程序代码与其依赖项、库和二进制文件一起打包。容器提供不同环境间的一致性和多个部署目标:物理服务器、虚拟机 (VM) 和私有或公有云。

Linux 容器技术是一种轻量型机制,用于隔离运行中的进程,仅限制对指定的资源的访问。作为管理员,您可以在 Linux 容器上执行各种任务,例如:

OpenShift Container Platform 提供针对 Init 容器的专用容器。init 容器在应用程序容器之前运行,可以包含应用程序镜像中不存在的工具或设置脚本。您可以在部署 pod 的其余部分之前,使用 Init 容器执行任务。

除了在节点、Pod 和容器上执行特定任务外,您还可使用整个 OpenShift Container Platform 集群来使集群高效和应用程序 pod 具有高可用性。

1.4. OpenShift Container Platform 节点的常用术语表

该术语表定义了在节点内容中使用的常用术语。

Container
它是一个轻量级且可执行的镜像,它包括了软件及其所有依赖项。容器虚拟化操作系统,因此您可以在任意位置运行容器,包括数据中心到公共或私有云,甚至在开发人员笔记本电脑中运行。
守护进程集
确保 pod 副本在 OpenShift Container Platform 集群的合格节点上运行。
egress
通过来自 pod 的网络出站流量进行外部数据共享的过程。
垃圾回收
清理集群资源的过程,如终止的容器和未被任何正在运行的 Pod 引用的镜像。
横向 Pod 自动扩展 (HPA)
作为 Kubernetes API 资源和控制器实现。您可以使用 HPA 指定您要运行的 pod 的最小和最大数量。您还可以指定 pod 应该针对的 CPU 或内存使用率。当超过给定 CPU 或内存阈值时,HPA 会扩展或缩放 pod。
入口
到一个 pod 的传入流量。
作业
要完成的进程。作业创建一个或多个 pod 对象,并确保指定的 pod 成功完成。
标签
您可以使用标签(即键值对)来组织并选择对象子集,如 pod。
节点
OpenShift Container Platform 集群中的 worker 机器。节点可以是虚拟机 (VM) 或物理机器。
Node Tuning Operator
您可以使用 Node Tuning Operator,使用 TuneD 守护进程来管理节点级别的性能优化。它保证了自定义性能优化设置以可被守护进程支持的格式传递到在集群中运行的所有容器化的 TuneD 守护进程中。相应的守护进程会在集群的所有节点上运行,每个节点上运行一个。
自助服务修复 Operator
Operator 在集群节点上运行,并检测和重启不健康的节点。
Pod
一个或多个带有共享资源(如卷和 IP 地址)的容器,在 OpenShift Container Platform 集群中运行。pod 是定义、部署和管理的最小计算单元。
容限(toleration)
表示 pod 允许(但不需要)调度到具有匹配污点的节点组。您可以使用容限来启用调度程序来调度具有匹配污点的 pod。
污点(taint)
一个核心对象,由一个键、值和效果组成。污点和容限可以一起工作,以确保 pod 不会调度到不相关的节点上。

第 2 章 使用 pod

2.1. 使用 pod

pod 是共同部署在同一主机上的一个或多个容器,也是可被定义、部署和管理的最小计算单元。

2.1.1. 了解 pod

对容器而言,Pod 大致相当于一个机器实例(物理或虚拟)。每个 pod 分配有自己的内部 IP 地址,因此拥有完整的端口空间,并且 pod 内的容器可以共享其本地存储和网络。

Pod 有生命周期,它们经过定义后,被分配到某一节点上运行,然后持续运行,直到容器退出或它们因为其他原因被删除为止。根据策略和退出代码,Pod 可在退出后删除,或被保留下来以启用对容器日志的访问。

OpenShift Container Platform 将 pod 基本上视为不可变;在运行期间无法更改 pod 定义。OpenShift Container Platform 通过终止现有的 pod,再利用修改后的配置和/或基础镜像重新创建 pod,从而实现更改。Pod 也被视为是可抛弃的,不会在重新创建时保持原来的状态。因此,pod 通常应通过更高级别的控制器来管理,而不直接由用户管理。

注意

如需了解每个 OpenShift Container Platform 节点主机的最大 pod 数,请参阅“集群限制”。

警告

不受复制控制器管理的裸机 pod 不能在节点中断时重新调度。

2.1.2. pod 配置示例

OpenShift Container Platform 使用 Kubernetes 的 pod 概念,它是共同部署在同一主机上的一个或多个容器,也是可被定义、部署和管理的最小计算单元。

以下是来自 Rails 应用的容器集定义示例。它展示了 pod 的许多特性,其中大多数已在其他主题中阐述,因此这里仅简略提及:

Pod 对象定义(YAML)

kind: Pod
apiVersion: v1
metadata:
  name: example
  namespace: default
  selfLink: /api/v1/namespaces/default/pods/example
  uid: 5cc30063-0265780783bc
  resourceVersion: '165032'
  creationTimestamp: '2019-02-13T20:31:37Z'
  labels:
    app: hello-openshift 1
  annotations:
    openshift.io/scc: anyuid
spec:
  restartPolicy: Always 2
  serviceAccountName: default
  imagePullSecrets:
    - name: default-dockercfg-5zrhb
  priority: 0
  schedulerName: default-scheduler
  terminationGracePeriodSeconds: 30
  nodeName: ip-10-0-140-16.us-east-2.compute.internal
  securityContext: 3
    seLinuxOptions:
      level: 's0:c11,c10'
  containers: 4
    - resources: {}
      terminationMessagePath: /dev/termination-log
      name: hello-openshift
      securityContext:
        capabilities:
          drop:
            - MKNOD
        procMount: Default
      ports:
        - containerPort: 8080
          protocol: TCP
      imagePullPolicy: Always
      volumeMounts: 5
        - name: default-token-wbqsl
          readOnly: true
          mountPath: /var/run/secrets/kubernetes.io/serviceaccount 6
      terminationMessagePolicy: File
      image: registry.redhat.io/openshift4/ose-ogging-eventrouter:v4.3 7
  serviceAccount: default 8
  volumes: 9
    - name: default-token-wbqsl
      secret:
        secretName: default-token-wbqsl
        defaultMode: 420
  dnsPolicy: ClusterFirst
status:
  phase: Pending
  conditions:
    - type: Initialized
      status: 'True'
      lastProbeTime: null
      lastTransitionTime: '2019-02-13T20:31:37Z'
    - type: Ready
      status: 'False'
      lastProbeTime: null
      lastTransitionTime: '2019-02-13T20:31:37Z'
      reason: ContainersNotReady
      message: 'containers with unready status: [hello-openshift]'
    - type: ContainersReady
      status: 'False'
      lastProbeTime: null
      lastTransitionTime: '2019-02-13T20:31:37Z'
      reason: ContainersNotReady
      message: 'containers with unready status: [hello-openshift]'
    - type: PodScheduled
      status: 'True'
      lastProbeTime: null
      lastTransitionTime: '2019-02-13T20:31:37Z'
  hostIP: 10.0.140.16
  startTime: '2019-02-13T20:31:37Z'
  containerStatuses:
    - name: hello-openshift
      state:
        waiting:
          reason: ContainerCreating
      lastState: {}
      ready: false
      restartCount: 0
      image: openshift/hello-openshift
      imageID: ''
  qosClass: BestEffort

1
pod 可以被“标上”一个或多个标签,然后使用这些标签在一个操作中选择和管理多组 pod。标签以键/值格式保存在 metadata 散列中。
2
pod 重启策略,可能的值有 AlwaysOnFailureNever。默认值为 Always
3
OpenShift Container Platform 为容器定义了一个安全上下文,指定是否允许其作为特权容器来运行,或者以所选用户身份运行,等等。默认上下文的限制性比较强,但管理员可以根据需要进行修改。
4
containers 指定包括一个或多个容器定义的数组。
5
容器指定在容器中挂载外部存储卷的位置。在本例中,有一个卷可用来存储对凭证的访问,该卷是根据 registry 对 OpenShift Container Platform API 发出请求所需的。
6
指定要为 pod 提供的卷。卷挂载在指定路径上。不要挂载到容器 root、/ 或主机和容器中相同的任何路径。如果容器有足够权限,可能会损坏您的主机系统(如主机的 /dev/pts 文件)。使用 /host 挂载主机是安全的。
7
pod 中的每个容器使用自己的容器镜像进行实例化。
8
pod 对 OpenShift Container Platform API 发出请求是一种比较常见的模式,利用一个 serviceAccount 字段指定 pod 在发出请求时使用哪个服务帐户用户来进行身份验证。这可以为自定义基础架构组件提供精细的访问控制。
9
pod 定义了可供其容器使用的存储卷。在本例中,它为包含默认服务帐户令牌的 secret 卷提供一个临时卷。

如果将具有高文件数的持久性卷附加到 pod,则这些 pod 可能会失败,或者可能需要很长时间才能启动。如需更多信息,请参阅在 OpenShift 中使用具有高文件计数的持久性卷时,为什么 pod 无法启动或占用大量时间来实现"Ready"状态?

注意

此 pod 定义不包括 OpenShift Container Platform 在 pod 创建并开始其生命周期后自动填充的属性。Kubernetes pod 文档详细介绍了 pod 的功能和用途。

2.1.3. 其它资源

2.2. 查看 pod

作为管理员,您可以查看集群中的 pod,并确定这些 pod 和整个集群的健康状态。

2.2.1. 关于 pod

OpenShift Container Platform 使用 Kubernetes 的 pod 概念,它是共同部署在同一主机上的一个或多个容器,也是可被定义、部署和管理的最小计算单元。对容器而言,Pod 大致相当于机器实例(物理或虚拟)。

您可以查看与特定项目关联的 pod 列表,或者查看 pod 的使用情况统计。

2.2.2. 查看项目中的 pod

您可以查看与当前项目关联的 pod 列表,包括副本数、当前状态、重启次数和 pod 的年龄。

流程

查看项目中的 pod:

  1. 切换到对应项目:

    $ oc project <project-name>
  2. 运行以下命令:

    $ oc get pods

    例如:

    $ oc get pods -n openshift-console

    输出示例

    NAME                       READY   STATUS    RESTARTS   AGE
    console-698d866b78-bnshf   1/1     Running   2          165m
    console-698d866b78-m87pm   1/1     Running   2          165m

    添加 -o wide 标记来查看 pod IP 地址和 pod 所在的节点。

    $ oc get pods -o wide

    输出示例

    NAME                       READY   STATUS    RESTARTS   AGE    IP            NODE                           NOMINATED NODE
    console-698d866b78-bnshf   1/1     Running   2          166m   10.128.0.24   ip-10-0-152-71.ec2.internal    <none>
    console-698d866b78-m87pm   1/1     Running   2          166m   10.129.0.23   ip-10-0-173-237.ec2.internal   <none>

2.2.3. 查看 pod 用量统计

您可以显示 pod 的用量统计,这些统计信息为容器提供了运行时环境。这些用量统计包括 CPU、内存和存储的消耗。

先决条件

  • 您必须有 cluster-reader 权限才能查看用量统计。
  • 必须安装 Metrics 才能查看用量统计。

流程

查看用量统计:

  1. 运行以下命令:

    $ oc adm top pods

    例如:

    $ oc adm top pods -n openshift-console

    输出示例

    NAME                         CPU(cores)   MEMORY(bytes)
    console-7f58c69899-q8c8k     0m           22Mi
    console-7f58c69899-xhbgg     0m           25Mi
    downloads-594fcccf94-bcxk8   3m           18Mi
    downloads-594fcccf94-kv4p6   2m           15Mi

  2. 运行以下命令,以查看带有标签的 pod 用量统计:

    $ oc adm top pod --selector=''

    您必须选择过滤所基于的选择器(标签查询)。支持 ===!=

2.2.4. 查看资源日志

您可以在 OpenShift CLI(oc)和 Web 控制台中查看各种资源的日志。日志从日志的尾部或末尾读取。

先决条件

  • 访问 OpenShift CLI(oc)。

流程 (UI)

  1. 在 OpenShift Container Platform 控制台中,导航到 WorkloadsPods,或通过您要调查的资源导航到 pod。

    注意

    有些资源(如构建)没有直接查询的 pod。在这种情况下,您可以在资源的 Details 页面中找到 Logs 链接。

  2. 从下拉菜单中选择一个项目。
  3. 点您要调查的 pod 的名称。
  4. Logs

流程 (CLI)

  • 查看特定 pod 的日志:

    $ oc logs -f <pod_name> -c <container_name>

    其中:

    -f
    可选:指定输出是否遵循要写到日志中的内容。
    <pod_name>
    指定 pod 的名称。
    <container_name>
    可选:指定容器的名称。当 pod 具有多个容器时,您必须指定容器名称。

    例如:

    $ oc logs ruby-58cd97df55-mww7r
    $ oc logs -f ruby-57f7f4855b-znl92 -c ruby

    输出的日志文件内容。

  • 查看特定资源的日志:

    $ oc logs <object_type>/<resource_name> 1
    1
    指定资源类型和名称。

    例如:

    $ oc logs deployment/ruby

    输出的日志文件内容。

2.3. 为 pod 配置 OpenShift Container Platform 集群

作为管理员,您可以为 pod 创建和维护高效的集群。

通过确保集群高效运行,您可以使用一些工具为开发人员提供更好的环境,例如,pod 退出时的行为,确保始终有所需数量的 pod 在运行,何时重启设计为只运行一次的 pod,限制 pod 可以使用的带宽,以及如何在中断时让 pod 保持运行。

2.3.1. 配置 pod 重启后的行为

pod 重启策略决定了 OpenShift Container Platform 在该 pod 中的容器退出时作出何种响应。该策略适用于 pod 中的所有容器。

可能的值有:

  • Always - 在 pod 被重启之前,按规定的延时值(10s,20s,40s)不断尝试重启 pod 中成功退出的容器(最长为 5 分钟)。默认值为 Always
  • OnFailure - 按规定的延时值(10s,20s,40s)不断尝试重启 pod 中失败的容器,上限为 5 分钟。
  • Never - 不尝试重启 pod 中已退出或失败的容器。Pod 立即失败并退出。

在 pod 绑定到某个节点后,该 pod 永远不会绑定到另一个节点。这意味着,需要一个控制器才能使 pod 在节点失败后存活:

状况控制器类型重启策略

应该终止的 Pod(例如,批量计算)

作业

OnFailureNever

不应该终止的 Pod(例如,Web 服务器)

复制控制器

Always

每台机器必须运行一个的 Pod

守护进程集

任意

如果 pod 上的容器失败且重启策略设为 OnFailure,则 pod 会保留在该节点上并重新启动容器。如果您不希望容器重新启动,请使用 Never 重启策略。

如果整个 pod 失败,OpenShift Container Platform 会启动一个新 pod。开发人员必须解决应用程序可能会在新 pod 中重启的情况。特别是,应用程序必须处理由以往运行产生的临时文件、锁定、不完整输出等结果。

注意

Kubernetes 架构需要来自云提供商的可靠端点。当云提供商停机时,kubelet 会防止 OpenShift Container Platform 重启。

如果底层云提供商端点不可靠,请不要使用云提供商集成来安装集群。应像在非云环境中一样安装集群。不建议在已安装的集群中打开或关闭云提供商集成。

如需详细了解 OpenShift Container Platform 如何使用与失败容器相关的重启策略,请参阅 Kubernetes 文档中的示例状态

2.3.2. 限制可供 pod 使用的带宽

您可以对 pod 应用服务质量流量控制,有效限制其可用带宽。出口流量(从 pod 传出)按照策略来处理,仅在超出配置的速率时丢弃数据包。入口流量(传入 pod 中)通过控制已排队数据包进行处理,以便有效地处理数据。您对 pod 应用的限制不会影响其他 pod 的带宽。

流程

限制 pod 的带宽:

  1. 编写对象定义 JSON 文件,并使用 kubernetes.io/ingress-bandwidthkubernetes.io/egress-bandwidth 注解指定数据流量速度。例如,将 pod 出口和入口带宽限制为 10M/s:

    受限 Pod 对象定义

    {
        "kind": "Pod",
        "spec": {
            "containers": [
                {
                    "image": "openshift/hello-openshift",
                    "name": "hello-openshift"
                }
            ]
        },
        "apiVersion": "v1",
        "metadata": {
            "name": "iperf-slow",
            "annotations": {
                "kubernetes.io/ingress-bandwidth": "10M",
                "kubernetes.io/egress-bandwidth": "10M"
            }
        }
    }

  2. 使用对象定义创建 pod:

    $ oc create -f <file_or_dir_path>

2.3.3. 了解如何使用 pod 中断预算来指定必须在线的 pod 数量

pod 中断预算Kubernetes API 的一部分,可以像其他对象类型一样通过 oc 命令进行管理。它们允许在操作过程中指定 pod 的安全约束,比如为维护而清空节点。

PodDisruptionBudget 是一个 API 对象,用于指定在某一时间必须保持在线的副本的最小数量或百分比。在项目中进行这些设置对节点维护(比如缩减集群或升级集群)有益,而且仅在自愿驱除(而非节点失败)时遵从这些设置。

PodDisruptionBudget 对象的配置由以下关键部分组成:

  • 标签选择器,即一组 pod 的标签查询。
  • 可用性级别,用来指定必须同时可用的最少 pod 的数量:

    • minAvailable 是必须始终可用的 pod 的数量,即使在中断期间也是如此。
    • maxUnavailable 是中断期间可以无法使用的 pod 的数量。
注意

允许 maxUnavailable0%0minAvailable100% 或等于副本数,但这样设置可能会阻止节点排空操作。

您可以使用以下命令来检查所有项目的 pod 中断预算:

$ oc get poddisruptionbudget --all-namespaces

输出示例

NAMESPACE         NAME          MIN-AVAILABLE   SELECTOR
another-project   another-pdb   4               bar=foo
test-project      my-pdb        2               foo=bar

如果系统中至少有 minAvailable 个 pod 正在运行,则 PodDisruptionBudget 被视为是健康的。超过这一限制的每个 pod 都可被驱除。

注意

根据您的 pod 优先级与抢占设置,可能会无视 pod 中断预算要求而移除较低优先级 pod。

2.3.3.1. 使用 pod 中断预算指定必须在线的 pod 数量

您可以使用 PodDisruptionBudget 对象来指定某一时间必须保持在线的副本的最小数量或百分比。

流程

配置 pod 中断预算:

  1. 使用类似以下示例的对象定义来创建 YAML 文件:

    apiVersion: policy/v1 1
    kind: PodDisruptionBudget
    metadata:
      name: my-pdb
    spec:
      minAvailable: 2  2
      selector:  3
        matchLabels:
          foo: bar
    1
    PodDisruptionBudgetpolicy/v1 API 组的一部分。
    2
    必须同时可用的最小 pod 数量。这可以是整数,也可以是指定百分比的字符串(如 20%)。
    3
    对一组资源进行的标签查询。matchLabelsmatchExpressions 的结果在逻辑上是联合的。将此参数留空,如 selector {},以选择项目中的所有 pod。

    或者:

    apiVersion: policy/v1 1
    kind: PodDisruptionBudget
    metadata:
      name: my-pdb
    spec:
      maxUnavailable: 25% 2
      selector: 3
        matchLabels:
          foo: bar
    1
    PodDisruptionBudgetpolicy/v1 API 组的一部分。
    2
    同时不能使用的最多的 pod 数量。这可以是整数,也可以是指定百分比的字符串(如 20%)。
    3
    对一组资源进行的标签查询。matchLabelsmatchExpressions 的结果在逻辑上是联合的。将此参数留空,如 selector {},以选择项目中的所有 pod。
  2. 运行以下命令,将对象添加到项目中:

    $ oc create -f </path/to/file> -n <project_name>

2.3.4. 使用关键 pod 防止删除 pod

有不少核心组件对于集群完全正常工作而言至关重要,但它们在常规集群节点而非主节点上运行。如果一个关键附加组件被驱除,集群可能会停止正常工作。

标记为关键 (critical) 的 Pod 不允许被驱除。

流程

使 pod 成为关键 pod:

  1. 创建 Pod spec 或编辑现有的 pod,使其包含 system-cluster-critical 优先级类:

    spec:
      template:
        metadata:
          name: critical-pod
        priorityClassName: system-cluster-critical 1
    1
    绝不可从节点驱除的 pod 的默认优先级类。

    此外,对于对集群而言很重要但可在必要时移除的 pod,可以指定 system-node-critical

  2. 创建 pod:

    $ oc create -f <file-name>.yaml

2.4. 使用 pod 横向自动扩展自动扩展 pod

作为开发人员,您可以使用 pod 横向自动扩展 (HPA) 来指定 OpenShift Container Platform 如何根据从属于某复制控制器或部署配置的 pod 收集的指标来自动增加或缩小该复制控制器或部署配置的规模。您可以为任何部署、部署配置、副本集、复制控制器或有状态集创建 HPA。

有关根据自定义指标缩放 pod 的信息,请参阅基于自定义指标自动扩展 pod

注意

除非需要特定功能或由其他对象提供的行为,否则建议使用 Deployment 对象或 ReplicaSet 对象。如需有关这些对象的更多信息,请参阅了解 Deployment 和 DeploymentConfig 对象

2.4.1. 了解 pod 横向自动扩展

您可以创建一个 pod 横向自动扩展来指定您要运行的 pod 的最小和最大数量,以及 pod 的目标 CPU 使用率或内存使用率。

在创建了 pod 横向自动扩展后,OpenShift Container Platform 会开始查询 pod 上的 CPU 和/或内存资源指标。当这些指标可用时,pod 横向自动扩展会计算当前指标使用率与所需指标使用率的比率,并相应地扩展或缩减。查询和缩放是定期进行的,但可能需要一到两分钟时间才会有可用指标。

对于复制控制器,这种缩放直接与复制控制器的副本对应。对于部署配置,缩放直接与部署配置的副本计数对应。注意,自动缩放仅应用到 Complete 阶段的最新部署。

OpenShift Container Platform 会自动考虑资源情况,并防止在资源激增期间进行不必要的自动缩放,比如在启动过程中。处于 unready 状态的 pod 在扩展时具有 0 CPU 用量,自动扩展在缩减时会忽略这些 pod。没有已知指标的 Pod 在扩展时具有 0% CPU 用量,在缩减时具有 100% CPU 用量。这在 HPA 决策过程中提供更高的稳定性。要使用这个功能,您必须配置就绪度检查来确定新 pod 是否准备就绪。

要使用 pod 横向自动扩展,您的集群管理员必须已经正确配置了集群指标。

2.4.1.1. 支持的指标

pod 横向自动扩展支持以下指标:

表 2.1. 指标

指标描述API 版本

CPU 使用率

已用的 CPU 内核数。可以用来计算 pod 的已请求 CPU 百分比。

autoscaling/v1, autoscaling/v2

内存使用率

已用内存量。可以用来计算 pod 的已请求内存百分比。

autoscaling/v2

重要

对于基于内存的自动缩放,内存用量必须与副本数呈正比增大和减小。平均而言:

  • 增加副本数一定会导致每个 pod 的内存(工作集)用量总体降低。
  • 减少副本数一定会导致每个 pod 的内存用量总体增高。

使用 OpenShift Container Platform Web 控制台检查应用程序的内存行为,并确保应用程序在使用基于内存的自动缩放前满足这些要求。

以下示例显示了 image-registry Deployment 对象的自动扩展。初始部署需要 3 个 pod。HPA 对象将最小值增加到 5。如果 pod 的 CPU 用量达到 75%,pod 会增加到 7:

$ oc autoscale deployment/image-registry --min=5 --max=7 --cpu-percent=75

输出示例

horizontalpodautoscaler.autoscaling/image-registry autoscaled

image-registry Deployment 对象的 HPA 示例,其中 minReplicas 被设置为 3

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: image-registry
  namespace: default
spec:
  maxReplicas: 7
  minReplicas: 3
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: image-registry
  targetCPUUtilizationPercentage: 75
status:
  currentReplicas: 5
  desiredReplicas: 0

  1. 查看部署的新状态:

    $ oc get deployment image-registry

    部署中现在有 5 个 pod:

    输出示例

    NAME             REVISION   DESIRED   CURRENT   TRIGGERED BY
    image-registry   1          5         5         config

2.4.2. HPA 的工作原理?

pod 横向自动扩展(HPA)扩展了 pod 自动扩展的概念。HPA 允许您创建和管理一组负载均衡的节点。当给定的 CPU 或内存阈值被超过时,HPA 会自动增加或减少 pod 数量。

图 2.1. HPA 的高级别工作流

工作流

HPA 是 Kubernetes 自动扩展 API 组中的 API 资源。自动扩展器充当控制循环,在同步周期内默认为 15 秒。在此期间,控制器管理器会根据 HPA 的 YAML 文件中定义的 CPU、内存使用率或两者查询 CPU、内存使用或两者。控制器管理器为 HPA 为目标的每个 pod 来获取来自每个 pod 资源指标(如 CPU 或内存)的资源指标的利用率指标。

如果设置了使用值目标,控制器会将利用率值视为各个 pod 中容器对等资源请求的百分比。然后,控制器需要所有目标 pod 的平均利用率,并生成一个用于缩放所需副本数的比率。HPA 配置为从 metrics.k8s.io 获取指标(由 metrics 服务器提供)。由于指标评估的动态性质,副本的数量在扩展一组副本期间会波动。

注意

要实现 HPA,所有目标 pod 都必须在其容器上设置了一个资源请求。

2.4.3. 关于请求和限制

调度程序使用您为 pod 中容器指定的资源请求,来确定要将 pod 放置到哪个节点。kubelet 强制执行您为容器指定的资源限值,以确保容器不允许使用超过指定的限制。kubelet 还保留针对该容器使用的系统资源的请求数量。

如何使用资源指标?

在 pod 规格中,您必须指定资源请求,如 CPU 和内存。HPA 使用此规范来确定资源利用率,然后扩展目标或缩减。

例如,HPA 对象使用以下指标源:

type: Resource
resource:
  name: cpu
  target:
    type: Utilization
    averageUtilization: 60

在本例中,HPA 将 pod 的平均利用率保持在 scale 目标为 60%。使用率是当前资源使用量与 pod 请求的资源之间的比率。

2.4.4. 最佳实践

所有 pod 都必须配置资源请求

HPA 根据 OpenShift Container Platform 集群中观察的 pod 或内存使用率值做出缩放决定。利用率值计算为各个容器集的资源请求的百分比。缺少资源请求值可能会影响 HPA 的最佳性能。

配置冷却期

在横向 pod 自动扩展过程中,可能会快速扩展事件,而不会造成时间差。配置 cool down 周期,以防止频繁的副本波动。您可以通过配置 stabilizationWindowSeconds 字段指定 cool down period。当用于扩展的指标保持波动时,stabilization 窗口用于限制副本数的波动。自动扩展算法使用这个窗口来推断以前的预期状态,并避免对工作负载扩展不需要的更改。

例如,为 scaleDown 字段指定了 stabilization 窗口:

behavior:
  scaleDown:
    stabilizationWindowSeconds: 300

在上例中,过去 5 分钟的所有所需状态都被视为。此近似滚动的最大值,避免让扩展算法频繁删除 pod,仅在稍后触发同等的 pod 重新创建。

2.4.4.1. 扩展策略

autoscaling/v2 API 允许您为 pod 横向自动扩展添加扩展策略。扩展策略用于控制 OpenShift Container Platform 横向自动扩展(HPA)如何扩展 pod。扩展策略允许您通过设置在指定时间段内扩展的特定数量或特定百分比来限制 HPA 扩展或缩减的速率。您还可以定义一个稳定化窗口(stabilization window),在指标有较大波动时,使用之前计算出的期望状态来控制扩展。您可以为相同的扩展方向创建多个策略,并根据更改的大小决定使用哪些策略。您还可以通过计时的迭代限制缩放。HPA 在迭代过程中扩展 pod,然后在以后的迭代中执行扩展(如果需要)。

带有扩展策略的 HPA 对象示例

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-resource-metrics-memory
  namespace: default
spec:
  behavior:
    scaleDown: 1
      policies: 2
      - type: Pods 3
        value: 4 4
        periodSeconds: 60 5
      - type: Percent
        value: 10 6
        periodSeconds: 60
      selectPolicy: Min 7
      stabilizationWindowSeconds: 300 8
    scaleUp: 9
      policies:
      - type: Pods
        value: 5 10
        periodSeconds: 70
      - type: Percent
        value: 12 11
        periodSeconds: 80
      selectPolicy: Max
      stabilizationWindowSeconds: 0
...

1
指定扩展策略的方向,可以是 scaleDownscaleUp。本例为缩减创建一个策略。
2
定义扩展策略。
3
决定策略是否在每次迭代过程中根据特定的 pod 数量或 pod 百分比进行扩展。默认值为 pod
4
决定在每次迭代过程中缩放数量(pod 数量或 pod 的百分比)。在按 pod 数量进行缩减时没有默认的值。
5
决定扩展迭代的长度。默认值为 15 秒。
6
按百分比缩减的默认值为 100%。
7
如果定义了多个策略,则决定首先使用哪个策略。指定 Max 使用允许最多更改的策略,Min 使用允许最小更改的策略,或者 Disabled 阻止 HPA 在策略方向进行扩展。默认值为 Max
8
决定 HPA 应该重新查看所需状态的时间周期。默认值为 0
9
本例为扩展创建了策略。
10
根据 pod 数量进行扩展的数量。扩展 pod 数量的默认值为 4%。
11
按 pod 百分比扩展的数量。按百分比扩展的默认值为 100%。

缩减策略示例

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-resource-metrics-memory
  namespace: default
spec:
...
  minReplicas: 20
...
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Pods
        value: 4
        periodSeconds: 30
      - type: Percent
        value: 10
        periodSeconds: 60
      selectPolicy: Max
    scaleUp:
      selectPolicy: Disabled

在本例中,当 pod 的数量大于 40 时,则使用基于百分比的策略进行缩减。这个策略会产生较大变化,这是 selectPolicy 需要的。

如果有 80 个 pod 副本,在第一次迭代时 HPA 会将 pod 减少 8 个,即 80 个 pod 的 10%(根据 type: Percentvalue: 10 参数),持续一分钟(periodSeconds: 60)。对于下一个迭代,pod 的数量为 72。HPA 计算剩余 pod 的 10% 为 7.2,这个数值被舍入到 8,这会缩减 8 个 pod。在每一后续迭代中,将根据剩余的 pod 数量重新计算要缩放的 pod 数量。当 pod 的数量低于 40 时,基于 pod 的策略会被应用,因为基于 pod 的数值会大于基于百分比的数值。HPA 每次减少 4 个 pod(type: Podvalue: 4),持续 30 秒(periodSeconds: 30),直到剩余 20 个副本(minReplicas)。

selectPolicy: Disabled 参数可防止 HPA 扩展 pod。如果需要,可以通过调整副本集或部署集中的副本数来手动扩展。

如果设置,您可以使用 oc edit 命令查看扩展策略:

$ oc edit hpa hpa-resource-metrics-memory

输出示例

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  annotations:
    autoscaling.alpha.kubernetes.io/behavior:\
'{"ScaleUp":{"StabilizationWindowSeconds":0,"SelectPolicy":"Max","Policies":[{"Type":"Pods","Value":4,"PeriodSeconds":15},{"Type":"Percent","Value":100,"PeriodSeconds":15}]},\
"ScaleDown":{"StabilizationWindowSeconds":300,"SelectPolicy":"Min","Policies":[{"Type":"Pods","Value":4,"PeriodSeconds":60},{"Type":"Percent","Value":10,"PeriodSeconds":60}]}}'
...

2.4.5. 使用 Web 控制台创建 pod 横向自动扩展

在 web 控制台中,您可以创建一个 pod 横向自动扩展(HPA),用于指定要在 DeploymentDeploymentConfig 对象上运行的 pod 的最小和最大数量。您还可以定义 pod 的目标 CPU 或内存用量。

注意

HPA 不能添加到作为 Operator 支持服务、Knative 服务或 Helm chart 一部分的部署中。

流程

在 web 控制台中创建 HPA:

  1. Topology 视图中,点击节点公开侧面板。
  2. Actions 下拉列表中,选择 Add HorizontalPodAutoscaler 来打开 Add HorizontalPodAutoscaler 表单。

    图 2.2. 添加 HorizontalPodAutoscaler

    Add HorizontalPodAutoscaler 表单
  3. Add HorizontalPodAutoscaler 表单中,定义名称、最小和最大 pod 限值、CPU 和内存用量,并点 Save

    注意

    如果缺少 CPU 和内存用量的值,则会显示警告。

在 web 控制台中编辑 HPA:

  1. Topology 视图中,点击节点公开侧面板。
  2. Actions 下拉列表中,选择 Edit HorizontalPodAutoscaler 来打开 Edit Horizontal Pod Autoscaler 表单。
  3. Edit Horizontal Pod Autoscaler 表单中,编辑最小和最大 pod 限值以及 CPU 和内存用量,然后点 Save
注意

在 web 控制台中创建或编辑 pod 横向自动扩展时,您可以从 Form 视图切换到 YAML 视图

在 web 控制台中删除 HPA:

  1. Topology 视图中,点击节点公开侧面板。
  2. Actions 下拉列表中,选择 Remove HorizontalPodAutoscaler
  3. 在确认弹出窗口中点击 Remove 删除 HPA。

2.4.6. 使用 CLI 根据 CPU 使用率创建 pod 横向自动扩展

使用 OpenShift Container Platform CLI,您可以创建一个 pod 横向自动扩展(HPA)来自动扩展现有的 DeploymentDeploymentConfigReplicaSetReplicationControllerStatefulSet 对象。HPA 扩展与该对象关联的 pod,以维护您指定的 CPU 用量。

注意

除非需要特定功能或由其他对象提供的行为,否则建议使用 Deployment 对象或 ReplicaSet 对象。

HPA 会在最小和最大数量之间增加和减少副本数,以保持所有 pod 的指定 CPU 使用率。

为 CPU 使用率自动扩展时,您可以使用 oc autoscale 命令,并指定要在任意给定时间运行的 pod 的最小和最大数量,以及 pod 的目标平均 CPU 使用率。如果未指定最小值,则 OpenShift Container Platform 服务器会为 pod 赋予一个默认值。

要自动缩放特定 CPU 值,创建一个带有目标 CPU 和 pod 限制的 HorizontalPodAutoscaler 对象。

先决条件

要使用 pod 横向自动扩展,您的集群管理员必须已经正确配置了集群指标。您可以使用 oc describe PodMetrics <pod-name> 命令来判断是否已配置了指标。如果配置了指标,输出类似于以下示例,其中 Usage 下列出了 CpuMemory

$ oc describe PodMetrics openshift-kube-scheduler-ip-10-0-135-131.ec2.internal

输出示例

Name:         openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
Namespace:    openshift-kube-scheduler
Labels:       <none>
Annotations:  <none>
API Version:  metrics.k8s.io/v1beta1
Containers:
  Name:  wait-for-host-port
  Usage:
    Memory:  0
  Name:      scheduler
  Usage:
    Cpu:     8m
    Memory:  45440Ki
Kind:        PodMetrics
Metadata:
  Creation Timestamp:  2019-05-23T18:47:56Z
  Self Link:           /apis/metrics.k8s.io/v1beta1/namespaces/openshift-kube-scheduler/pods/openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
Timestamp:             2019-05-23T18:47:56Z
Window:                1m0s
Events:                <none>

流程

为 CPU 使用率创建 pod 横向自动扩展:

  1. 执行以下之一:

    • 要根据 CPU 使用率百分比来缩放,请为现有对象创建一个 HorizontalPodAutoscaler 对象:

      $ oc autoscale <object_type>/<name> \1
        --min <number> \2
        --max <number> \3
        --cpu-percent=<percent> 4
      1
      指定要自动扩展的对象类型和名称。对象必须存在,并需要是 Deployment, DeploymentConfig/dc, ReplicaSet/rs, ReplicationController/rc, 或 StatefulSet
      2
      另外,还可以指定缩减时的最小副本数量。
      3
      指定扩展时的最大副本数量。
      4
      指定所有 pod 的目标平均 CPU 使用率(以请求 CPU 的百分比表示)。如果未指定或为负数,则会使用默认的自动缩放策略。

      例如,以下命令显示 image-registry Deployment 对象的自动扩展。初始部署需要 3 个 pod。HPA 对象将最小值增加到 5。如果 pod 的 CPU 用量达到 75%,pod 将增加到 7:

      $ oc autoscale deployment/image-registry --min=5 --max=7 --cpu-percent=75
    • 要扩展特定 CPU 值,请为现有对象创建类似如下的 YAML 文件:

      1. 创建一个类似以下示例的 YAML 文件:

        apiVersion: autoscaling/v2 1
        kind: HorizontalPodAutoscaler
        metadata:
          name: cpu-autoscale 2
          namespace: default
        spec:
          scaleTargetRef:
            apiVersion: apps/v1 3
            kind: Deployment 4
            name: example 5
          minReplicas: 1 6
          maxReplicas: 10 7
          metrics: 8
          - type: Resource
            resource:
              name: cpu 9
              target:
                type: AverageValue 10
                averageValue: 500m 11
        1
        使用 autoscaling/v2 API。
        2
        指定此 pod 横向自动扩展对象的名称。
        3
        指定要缩放对象的 API 版本:
        • 对于 DeploymentReplicaSetStatefulset 对象,使用 apps/v1
        • 对于 ReplicationController,使用 v1
        • 对于 DeploymentConfig,使用 apps.openshift.io/v1
        4
        指定对象类型。对象需要是 Deployment, DeploymentConfig/dc, ReplicaSet/rs, ReplicationController/rc, 或 StatefulSet.
        5
        指定要缩放的对象名称。对象必须存在。
        6
        指定缩减时的最小副本数量。
        7
        指定扩展时的最大副本数量。
        8
        对于内存使用率,使用 metrics 参数。
        9
        为 CPU 使用率指定 cpu
        10
        设置为 AverageValue
        11
        使用目标 CPU 值设置为 averageValue
      2. 创建 Pod 横向自动扩展:

        $ oc create -f <file-name>.yaml
  2. 验证 pod 横向自动扩展是否已创建:

    $ oc get hpa cpu-autoscale

    输出示例

    NAME            REFERENCE            TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
    cpu-autoscale   Deployment/example   173m/500m       1         10        1          20m

2.4.7. 使用 CLI 根据内存使用率创建 pod 横向自动扩展对象

使用 OpenShift Container Platform CLI,您可以创建一个 pod 横向自动扩展(HPA)来自动扩展现有的 DeploymentDeploymentConfigReplicaSetReplicationControllerStatefulSet 对象。HPA 扩展与该对象关联的 pod,以维护您指定的平均内存使用率(可以是直接值,也可以是请求的内存百分比)。

注意

除非需要特定功能或由其他对象提供的行为,否则建议使用 Deployment 对象或 ReplicaSet 对象。

HPA 增加和减少最小和最大数量之间的副本数量,以维护所有 pod 的指定内存使用率。

对于内存使用率,您可以指定 pod 的最小和最大数量,以及 pod 的目标平均内存使用率。如果未指定最小值,则 OpenShift Container Platform 服务器会为 pod 赋予一个默认值。

先决条件

要使用 pod 横向自动扩展,您的集群管理员必须已经正确配置了集群指标。您可以使用 oc describe PodMetrics <pod-name> 命令来判断是否已配置了指标。如果配置了指标,输出类似于以下示例,其中 Usage 下列出了 CpuMemory

$ oc describe PodMetrics openshift-kube-scheduler-ip-10-0-129-223.compute.internal -n openshift-kube-scheduler

输出示例

Name:         openshift-kube-scheduler-ip-10-0-129-223.compute.internal
Namespace:    openshift-kube-scheduler
Labels:       <none>
Annotations:  <none>
API Version:  metrics.k8s.io/v1beta1
Containers:
  Name:  wait-for-host-port
  Usage:
    Cpu:     0
    Memory:  0
  Name:      scheduler
  Usage:
    Cpu:     8m
    Memory:  45440Ki
Kind:        PodMetrics
Metadata:
  Creation Timestamp:  2020-02-14T22:21:14Z
  Self Link:           /apis/metrics.k8s.io/v1beta1/namespaces/openshift-kube-scheduler/pods/openshift-kube-scheduler-ip-10-0-129-223.compute.internal
Timestamp:             2020-02-14T22:21:14Z
Window:                5m0s
Events:                <none>

流程

根据内存使用率创建 pod 横向自动扩展:

  1. 为以下之一创建一个 YAML 文件:

    • 要扩展特定内存值,请为现有对象创建类似如下的 HorizontalPodAutoscaler 对象:

      apiVersion: autoscaling/v2 1
      kind: HorizontalPodAutoscaler
      metadata:
        name: hpa-resource-metrics-memory 2
        namespace: default
      spec:
        scaleTargetRef:
          apiVersion: apps/v1 3
          kind: Deployment 4
          name: example 5
        minReplicas: 1 6
        maxReplicas: 10 7
        metrics: 8
        - type: Resource
          resource:
            name: memory 9
            target:
              type: AverageValue 10
              averageValue: 500Mi 11
        behavior: 12
          scaleDown:
            stabilizationWindowSeconds: 300
            policies:
            - type: Pods
              value: 4
              periodSeconds: 60
            - type: Percent
              value: 10
              periodSeconds: 60
            selectPolicy: Max
      1
      使用 autoscaling/v2 API。
      2
      指定此 pod 横向自动扩展对象的名称。
      3
      指定要缩放对象的 API 版本:
      • 对于 DeploymentReplicaSetStatefulset 对象,请使用 apps/v1
      • 对于 ReplicationController,使用 v1
      • 对于 DeploymentConfig,使用 apps.openshift.io/v1
      4
      指定对象类型。对象必须是 DeploymentDeploymentConfigReplicaSetReplicationControllerStatefulSet
      5
      指定要缩放的对象名称。对象必须存在。
      6
      指定缩减时的最小副本数量。
      7
      指定扩展时的最大副本数量。
      8
      对于内存使用率,使用 metrics 参数。
      9
      为内存使用率指定 memory
      10
      将类型设置为 AverageValue
      11
      指定 averageValue 和一个特定的内存值。
      12
      可选:指定一个扩展策略来控制扩展或缩减率。
    • 要缩放一个百分比,请为现有对象创建一个类似如下的 HorizontalPodAutoscaler 对象:

      apiVersion: autoscaling/v2 1
      kind: HorizontalPodAutoscaler
      metadata:
        name: memory-autoscale 2
        namespace: default
      spec:
        scaleTargetRef:
          apiVersion: apps/v1 3
          kind: Deployment 4
          name: example 5
        minReplicas: 1 6
        maxReplicas: 10 7
        metrics: 8
        - type: Deployment
          resource:
            name: memory 9
            target:
              type: Utilization 10
              averageUtilization: 50 11
        behavior: 12
          scaleUp:
            stabilizationWindowSeconds: 180
            policies:
            - type: Pods
              value: 6
              periodSeconds: 120
            - type: Percent
              value: 10
              periodSeconds: 120
            selectPolicy: Max
      1
      使用 autoscaling/v2 API。
      2
      指定此 pod 横向自动扩展对象的名称。
      3
      指定要缩放对象的 API 版本:
      • 对于 ReplicationController,使用 v1
      • 对于 DeploymentConfig,使用 apps.openshift.io/v1
      • 对于 Deployment、ReplicaSet 和 Statefulset 对象,使用 apps/v1
      4
      指定对象类型。对象必须是 DeploymentDeploymentConfigReplicaSetReplicationControllerStatefulSet
      5
      指定要缩放的对象名称。对象必须存在。
      6
      指定缩减时的最小副本数量。
      7
      指定扩展时的最大副本数量。
      8
      对于内存使用率,使用 metrics 参数。
      9
      为内存使用率指定 memory
      10
      设置 Utilization
      11
      为所有 pod 指定 averageUtilization 和一个目标平均内存利用率,以请求内存的百分比表示。目标 pod 必须配置内存请求。
      12
      可选:指定一个扩展策略来控制扩展或缩减率。
  2. 创建 Pod 横向自动扩展:

    $ oc create -f <file-name>.yaml

    例如:

    $ oc create -f hpa.yaml

    输出示例

    horizontalpodautoscaler.autoscaling/hpa-resource-metrics-memory created

  3. 验证 pod 横向自动扩展是否已创建:

    $ oc get hpa hpa-resource-metrics-memory

    输出示例

    NAME                          REFERENCE            TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
    hpa-resource-metrics-memory   Deployment/example   2441216/500Mi   1         10        1          20m

    $ oc describe hpa hpa-resource-metrics-memory

    输出示例

    Name:                        hpa-resource-metrics-memory
    Namespace:                   default
    Labels:                      <none>
    Annotations:                 <none>
    CreationTimestamp:           Wed, 04 Mar 2020 16:31:37 +0530
    Reference:                   Deployment/example
    Metrics:                     ( current / target )
      resource memory on pods:   2441216 / 500Mi
    Min replicas:                1
    Max replicas:                10
    ReplicationController pods:  1 current / 1 desired
    Conditions:
      Type            Status  Reason              Message
      ----            ------  ------              -------
      AbleToScale     True    ReadyForNewScale    recommended size matches current size
      ScalingActive   True    ValidMetricFound    the HPA was able to successfully calculate a replica count from memory resource
      ScalingLimited  False   DesiredWithinRange  the desired count is within the acceptable range
    Events:
      Type     Reason                   Age                 From                       Message
      ----     ------                   ----                ----                       -------
      Normal   SuccessfulRescale        6m34s               horizontal-pod-autoscaler  New size: 1; reason: All metrics below target

2.4.8. 使用 CLI 了解 pod 横向自动扩展状态条件

您可以使用设置的状态条件来判断 pod 横向自动扩展 (HPA) 是否能够缩放,以及目前是否受到某种方式的限制。

HPA 状态条件可通过 v2 版的自动扩展 API 使用。

HPA 可以通过下列状态条件给予响应:

  • AbleToScale 条件指示 HPA 是否能够获取和更新指标,以及是否有任何与退避相关的条件阻碍了缩放。

    • True 条件表示允许缩放。
    • False 条件表示因为指定原因不允许缩放。
  • ScalingActive 条件指示 HPA 是否已启用(例如,目标的副本数不为零),并且可以计算所需的指标。

    • True 条件表示指标工作正常。
    • False 条件通常表示获取指标时出现问题。
  • ScalingLimited 条件表示所需的规模由 pod 横向自动扩展限定最大或最小限制。

    • True 条件表示您需要提高或降低最小或最大副本数才能进行缩放。
    • False 条件表示允许请求的缩放。

      $ oc describe hpa cm-test

      输出示例

      Name:                           cm-test
      Namespace:                      prom
      Labels:                         <none>
      Annotations:                    <none>
      CreationTimestamp:              Fri, 16 Jun 2017 18:09:22 +0000
      Reference:                      ReplicationController/cm-test
      Metrics:                        ( current / target )
        "http_requests" on pods:      66m / 500m
      Min replicas:                   1
      Max replicas:                   4
      ReplicationController pods:     1 current / 1 desired
      Conditions: 1
        Type              Status    Reason              Message
        ----              ------    ------              -------
        AbleToScale       True      ReadyForNewScale    the last scale time was sufficiently old as to warrant a new scale
        ScalingActive     True      ValidMetricFound    the HPA was able to successfully calculate a replica count from pods metric http_request
        ScalingLimited    False     DesiredWithinRange  the desired replica count is within the acceptable range
      Events:

      1
      pod 横向自动扩展状态消息。

下例中是一个无法缩放的 pod:

输出示例

Conditions:
  Type         Status  Reason          Message
  ----         ------  ------          -------
  AbleToScale  False   FailedGetScale  the HPA controller was unable to get the target's current scale: no matches for kind "ReplicationController" in group "apps"
Events:
  Type     Reason          Age               From                       Message
  ----     ------          ----              ----                       -------
  Warning  FailedGetScale  6s (x3 over 36s)  horizontal-pod-autoscaler  no matches for kind "ReplicationController" in group "apps"

下例中是一个无法获得缩放所需指标的 pod:

输出示例

Conditions:
  Type                  Status    Reason                    Message
  ----                  ------    ------                    -------
  AbleToScale           True     SucceededGetScale          the HPA controller was able to get the target's current scale
  ScalingActive         False    FailedGetResourceMetric    the HPA was unable to compute the replica count: failed to get cpu utilization: unable to get metrics for resource cpu: no metrics returned from resource metrics API

下例中是一个请求的自动缩放低于所需下限的 pod:

输出示例

Conditions:
  Type              Status    Reason              Message
  ----              ------    ------              -------
  AbleToScale       True      ReadyForNewScale    the last scale time was sufficiently old as to warrant a new scale
  ScalingActive     True      ValidMetricFound    the HPA was able to successfully calculate a replica count from pods metric http_request
  ScalingLimited    False     DesiredWithinRange  the desired replica count is within the acceptable range

2.4.8.1. 使用 CLI 查看 pod 横向自动扩展状态条件

您可以查看 pod 横向自动扩展 (HPA) 对 pod 设置的状态条件。

注意

pod 横向自动扩展状态条件可通过 v2 版本的自动扩展 API 使用。

先决条件

要使用 pod 横向自动扩展,您的集群管理员必须已经正确配置了集群指标。您可以使用 oc describe PodMetrics <pod-name> 命令来判断是否已配置了指标。如果配置了指标,输出类似于以下示例,其中 Usage 下列出了 CpuMemory

$ oc describe PodMetrics openshift-kube-scheduler-ip-10-0-135-131.ec2.internal

输出示例

Name:         openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
Namespace:    openshift-kube-scheduler
Labels:       <none>
Annotations:  <none>
API Version:  metrics.k8s.io/v1beta1
Containers:
  Name:  wait-for-host-port
  Usage:
    Memory:  0
  Name:      scheduler
  Usage:
    Cpu:     8m
    Memory:  45440Ki
Kind:        PodMetrics
Metadata:
  Creation Timestamp:  2019-05-23T18:47:56Z
  Self Link:           /apis/metrics.k8s.io/v1beta1/namespaces/openshift-kube-scheduler/pods/openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
Timestamp:             2019-05-23T18:47:56Z
Window:                1m0s
Events:                <none>

流程

要查看 pod 上的状态条件,请使用以下命令并提供 pod 的名称:

$ oc describe hpa <pod-name>

例如:

$ oc describe hpa cm-test

这些条件会出现在输出中的 Conditions 字段里。

输出示例

Name:                           cm-test
Namespace:                      prom
Labels:                         <none>
Annotations:                    <none>
CreationTimestamp:              Fri, 16 Jun 2017 18:09:22 +0000
Reference:                      ReplicationController/cm-test
Metrics:                        ( current / target )
  "http_requests" on pods:      66m / 500m
Min replicas:                   1
Max replicas:                   4
ReplicationController pods:     1 current / 1 desired
Conditions: 1
  Type              Status    Reason              Message
  ----              ------    ------              -------
  AbleToScale       True      ReadyForNewScale    the last scale time was sufficiently old as to warrant a new scale
  ScalingActive     True      ValidMetricFound    the HPA was able to successfully calculate a replica count from pods metric http_request
  ScalingLimited    False     DesiredWithinRange  the desired replica count is within the acceptable range

2.4.9. 其他资源

2.5. 根据自定义指标自动扩展 pod

作为开发人员,您可以使用自定义指标自动扩展来指定 OpenShift Container Platform 如何根据不基于 CPU 或内存的自定义指标自动增加或减少部署、有状态集、自定义资源或作业的数量。

Custom Metrics Autoscaler Operator for Red Hat OpenShift 是一个可选的 operator,它基于 Kubernetes Event Driven Autoscaler (KEDA),它允许使用 pod 指标以外的其他指标源进行扩展工作负载。

注意

自定义指标自动扩展目前仅支持 Prometheus、CPU、内存和 Apache Kafka 指标。

重要

自定义指标自动扩展只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围

2.5.1. 自定义 Metrics Autoscaler Operator 发行注记

Red Hat Openshift 的自定义 Metrics Autoscaler Operator 发行注记介绍了新的功能和增强功能、已弃用的功能以及已知的问题。

Custom Metrics Autoscaler Operator 使用基于 Kubernetes 的 Event Driven Autoscaler (KEDA),并基于 OpenShift Container Platform 横向自动扩展(HPA)构建。

注意

Custom Metrics Autoscaler Operator for Red Hat OpenShift 作为可安装的组件提供,它与 OpenShift Container Platform 核心不同。Red Hat OpenShift Container Platform 生命周期政策概述了发行版本兼容性。

2.5.1.1. 支持的版本

下表为每个 OpenShift Container Platform 版本定义自定义 Metrics Autoscaler Operator 版本。

版本OpenShift Container Platform 版本公开发行(GA)

2.8.2

4.13

技术预览

2.8.2

4.12

技术预览

2.8.2

4.11

技术预览

2.8.2

4.10

技术预览

2.5.1.2. 自定义 Metrics Autoscaler Operator 2.8.2 发行注记

此自定义 Metrics Autoscaler Operator 2.8.2 发行版本为在 OpenShift Container Platform 集群中运行的 Operator 提供了新功能和程序错误修复。自定义 Metrics Autoscaler Operator 2.8.2 组件在 RHSA-2023:1042 中发布。

重要

自定义 Metrics Autoscaler Operator 目前是一个技术预览功能。

新功能及功能增强

2.5.1.2.1. 审计日志记录

现在,您可以收集并查看自定义 Metrics Autoscaler Operator 及其相关组件的审计日志。审计日志是安全相关的按时间排序的记录,记录各个用户、管理员或其他系统组件影响系统的一系列活动。

2.5.1.2.2. 基于 Apache Kafka 指标扩展应用程序

现在,您可以使用 KEDA Apache kafka 触发器/scaler 根据 Apache Kafka 主题扩展部署。

2.5.1.2.3. 根据 CPU 指标扩展应用程序

现在,您可以使用 KEDA CPU 触发器/scaler 根据 CPU 指标扩展部署。

2.5.1.2.4. 根据内存指标扩展应用程序

现在,您可以使用 KEDA 内存触发器/scaler 根据内存指标扩展部署。

2.5.2. 了解自定义指标自动扩展

Custom Metrics Autoscaler Operator 根据特定应用程序的自定义外部指标扩展 pod。您的其他应用程序继续使用其他扩展方法。您可以配置 触发器 (也称为 scaler),这是自定义指标自动扩展器用来决定如何扩展的事件和指标的来源。自定义指标自动扩展使用 metrics API 将外部指标转换为 OpenShift Container Platform 可以使用的形式。自定义指标自动扩展会创建一个执行实际缩放的 pod 横向自动扩展(HPA)。

要使用自定义指标自动扩展,您可以创建一个 ScaledObjectScaledJob 对象,这是定义扩展元数据的自定义资源 (CR)。您可以指定要缩放的部署或作业、要缩放的指标源 (trigger) 以及其他参数,如允许的最小和最大副本数。

注意

您只能为每个您要扩展的工作负载创建一个扩展对象或扩展作业。另外,您不能在同一工作负载中使用扩展的对象或扩展作业以及 pod 横向自动扩展 (HPA)。

自定义指标自动扩展与 HPA 不同,可以缩减为零。如果将自定义指标自动扩展 CR 中的 minReplicaCount 值设置为 0,自定义指标自动扩展会将工作负载从 1 缩减到 0 个副本或从 0 个副本扩展到 1。这称为 激活阶段。扩展至 1 个副本后,HPA 会控制扩展。这称为 扩展阶段

某些触发器允许您更改由集群指标自动扩展扩展的副本数量。在所有情况下,配置激活阶段的参数始终使用相同的短语,前缀为 激活。例如,如果 threshold 参数配置缩放,则 activationThreshold 将配置激活。通过配置激活和扩展阶段,您可以提高扩展策略的灵活性。例如,您可以配置更高的激活阶段,以便在指标特别低时防止扩展或缩减。

当每个决策不同时,激活值的优先级高于扩展值。例如,如果 threshold 被设置为 10,并且 activationThreshold50,如果指标报告 40,则缩放器不会激活,并且 pod 缩减为零,即使 HPA 需要 4 个实例。

您可以通过查看自定义资源中的 pod 数量或查看自定义 Metrics Autoscaler Operator 日志来验证自动扩展是否已发生:

Successfully set ScaleTarget replica count
Successfully updated ScaleTarget

如果需要,您可以临时暂停工作负载对象的自动扩展。例如,您可以在执行集群维护前暂停自动扩展。

2.5.3. 安装自定义指标自动扩展

您可以使用 OpenShift Container Platform Web 控制台安装自定义 Metrics Autoscaler Operator。

安装会创建五个 CRD:

  • ClusterTriggerAuthentication
  • KedaController
  • ScaledJob
  • ScaledObject
  • TriggerAuthentication

先决条件

  • 如果您使用社区 KEDA:

    • 卸载社区 KEDA。您不能在同一 OpenShift Container Platform 集群中运行 KEDA 和自定义指标自动扩展。
    • 运行以下命令来删除 KEDA 1.x 自定义资源定义:

      $ oc delete crd scaledobjects.keda.k8s.io
      $ oc delete crd triggerauthentications.keda.k8s.io

流程

  1. 在 OpenShift Container Platform Web 控制台中,点击 OperatorsOperatorHub
  2. 从可用的 Operator 列表中选择 Custom Metrics Autoscaler,然后点 Install
  3. Install Operator 页面中,确保为 Installation Mode 选择 All namespaces on the cluster(default) 选项。这会在所有命名空间中安装 Operator。
  4. 确保为 Installed Namespace 选择了 openshift-keda 命名空间。如果集群中不存在命名空间,OpenShift Container Platform 会创建命名空间。
  5. Install
  6. 列出自定义 Metrics Autoscaler Operator 组件来验证安装:

    1. 导航到 WorkloadsPods
    2. 从下拉菜单中选择 openshift-keda 项目,并验证 custom-metrics-autoscaler-operator-* pod 正在运行。
    3. 进入到 WorkloadsDeployments 以验证 custom-metrics-autoscaler-operator 部署是否正在运行。
  7. 可选:使用以下命令在 OpenShift CLI 中验证安装:

    $ oc get all -n openshift-keda

    输出结果类似如下:

    输出示例

    NAME                                                      READY   STATUS    RESTARTS   AGE
    pod/custom-metrics-autoscaler-operator-5fd8d9ffd8-xt4xp   1/1     Running   0          18m
    
    NAME                                                 READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/custom-metrics-autoscaler-operator   1/1     1            1           18m
    
    NAME                                                            DESIRED   CURRENT   READY   AGE
    replicaset.apps/custom-metrics-autoscaler-operator-5fd8d9ffd8   1         1         1       18m

  8. 安装 KedaController 自定义资源,该资源创建所需的 CRD:

    1. 在 OpenShift Container Platform web 控制台中,点击 OperatorsInstalled Operators
    2. Custom Metrics Autoscaler
    3. Operator Details 页面中,点 KedaController 选项卡。
    4. KedaController 选项卡中,点 Create KedaController 并编辑文件。

      kind: KedaController
      apiVersion: keda.sh/v1alpha1
      metadata:
        name: keda
        namespace: openshift-keda
      spec:
        watchNamespace: '' 1
        operator:
          logLevel: info 2
          logEncoder: console 3
        metricsServer:
          logLevel: '0' 4
          auditConfig: 5
            logFormat: "json"
            logOutputVolumeClaim: "persistentVolumeClaimName"
            policy:
              rules:
              - level: Metadata
              omitStages: "RequestReceived"
              omitManagedFields: false
            lifetime:
              maxAge: "2"
              maxBackup: "1"
              maxSize: "50"
        serviceAccount: {}
      1 1
      指定自定义自动扩展应该监视的命名空间。在以逗号分隔的列表中输入名称。省略或设置空以监视所有命名空间。默认值为空。
      2
      指定自定义 Metrics Autoscaler Operator 日志消息的详细程度。允许的值有 debuginfoerror。默认为 info
      3
      指定 Custom Metrics Autoscaler Operator 日志消息的日志记录格式。允许的值是 consolejson。默认为 console
      4
      指定自定义 Metrics Autoscaler Metrics 服务器的日志记录级别。允许的值是 0(用于 info)和 4(用于 debug )。默认值为 0
      5
      激活自定义 Metrics Autoscaler Operator 的审计日志记录,并指定要使用的审计策略,如"配置审计日志记录"部分中所述。
    5. Create 创建 KEDAController。

2.5.4. 了解自定义指标自动扩展触发器

触发器(也称为 scalers)提供自定义 Metrics Autoscaler Operator 用来扩展 pod 的指标。

注意

自定义指标自动扩展目前只支持 Prometheus、CPU、内存和 Apache Kafka 触发器。

您可以使用 ScaledObjectScaledJob 自定义资源为特定对象配置触发器,如后面的章节中所述。

2.5.4.1. 了解 Prometheus 触发器

您可以基于 Prometheus 指标扩展 pod,该指标可以使用已安装的 OpenShift Container Platform 监控或外部 Prometheus 服务器作为指标源。如需有关使用 OpenShift Container Platform 监控作为指标源所需的配置的信息,请参阅附加资源

注意

如果 Prometheus 从自定义指标自动扩展器扩展的应用程序中获取指标,请不要在自定义资源中将最小副本数设置为 0。如果没有应用程序 pod,自定义指标自动扩展没有任何要缩放的指标。

带有 Prometheus 目标的扩展对象示例

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: prom-scaledobject
  namespace: my-namespace
spec:
 ...
  triggers:
  - type: prometheus 1
    metadata:
      serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9092 2
      namespace: kedatest 3
      metricName: http_requests_total 4
      threshold: '5' 5
      query: sum(rate(http_requests_total{job="test-app"}[1m])) 6
      authModes: "basic" 7
      cortexOrgID: my-org 8
      ignoreNullValues: false 9
      unsafeSsl: "false" 10

1
将 Prometheus 指定为 scaler/trigger 类型。
2
指定 Prometheus 服务器的地址。本例使用 OpenShift Container Platform 监控。
3
可选:指定您要缩放的对象的命名空间。如果 OpenShift Container Platform 监控作为指标的源,则需要此参数。
4
指定在 external.metrics.k8s.io API 中标识指标的名称。如果您使用的是多个触发器,则所有指标名称都必须是唯一的。
5
指定开始缩放的值。
6
指定要使用的 Prometheus 查询。
7
指定要使用的身份验证方法。Prometheus scalers 支持 bearer 身份验证、基本身份验证或 TLS 身份验证。您可以在触发器身份验证中配置特定的身份验证参数,如以下部分所述。根据需要,您还可以使用 secret。
8
可选:将 X-Scope-OrgID 标头传递给多租户 Cortex 或 Prometheus 的 Mimir 存储。这个参数只需要带有多租户 Prometheus 存储,以指示 Prometheus 应该返回哪些数据。
9
可选:指定在 Prometheus 目标丢失时触发器应如何进行操作。
  • 如果为 true,当 Prometheus 目标丢失时触发器将继续操作。这是默认值。
  • 如果为 false,当 Prometheus 目标丢失时触发器会返回错误。
10
可选:指定是否应跳过证书检查。例如,如果在 Prometheus 端点中使用自签名证书,您可以跳过检查。
  • 如果为 true,则执行证书检查。
  • 如果为 false,则不会执行证书检查。这是默认值。

2.5.4.2. 了解 CPU 触发器

您可以根据 CPU 指标扩展 pod。此触发器使用集群指标作为指标的源。

自定义指标自动扩展扩展与对象关联的 pod,以维护您指定的 CPU 用量。自动缩放器增加或减少最小和最大数量之间的副本数量,以维护所有 pod 的指定 CPU 使用率。内存触发器考虑整个 pod 的内存使用率。如果 pod 有多个容器,则内存使用率是所有容器的总和。

注意
  • 此触发器不能与 ScaledJob 自定义资源一起使用。
  • 当使用内存触发器扩展对象时,对象不会扩展到 0,即使您使用多个触发器。

使用 CPU 目标扩展对象示例

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: cpu-scaledobject
  namespace: my-namespace
spec:

 ...

  triggers:
  - type: cpu 1
    metricType: Utilization 2
    metadata:
      value: "60" 3
      containerName: "api" 4

1
将 CPU 指定为 scaler/trigger 类型。
2
指定要使用的指标类型,可以是 UtilizationAverageValue
3
指定触发扩展操作的值:
  • 在使用 Utilization 时,target 值是所有相关 pod 中资源指标的平均值,以 pod 资源请求的值的百分比表示。
  • 使用 AverageValue 时,target 值是所有相关 Pod 的指标平均值。
4
可选。根据该容器的内存使用率,而不是整个 pod,指定要缩放的独立容器。在这里,只有名为 api 的容器才会扩展。

2.5.4.3. 了解内存触发器

您可以根据内存指标扩展 pod。此触发器使用集群指标作为指标的源。

自定义指标自动扩展扩展与对象关联的 pod,以维护您指定的平均内存用量。自动缩放器会增加和减少最小和最大数量之间的副本数量,以维护所有 pod 的指定内存使用率。内存触发器考虑整个 pod 的内存使用率。如果 pod 有多个容器,则内存使用率是所有容器的总和。

注意
  • 此触发器不能与 ScaledJob 自定义资源一起使用。
  • 当使用内存触发器扩展对象时,对象不会扩展到 0,即使您使用多个触发器。

使用内存目标扩展对象示例

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: memory-scaledobject
  namespace: my-namespace
spec:

 ...

  triggers:
  - type: memory 1
    metricType: Utilization 2
    metadata:
      value: "60" 3
      containerName: "api" 4

1
将 memory 指定为 scaler/trigger 类型。
2
指定要使用的指标类型,可以是 UtilizationAverageValue
3
指定触发以下的扩展操作的值:
  • 在使用 Utilization 时,target 值是所有相关 pod 中资源指标的平均值,以 pod 资源请求的值的百分比表示。
  • 使用 AverageValue 时,target 值是所有相关 Pod 的指标平均值。
4
可选。根据该容器的内存使用率,而不是整个 pod,指定要缩放的独立容器。在这里,只有名为 api 的容器才会扩展。

2.5.4.4. 了解 Kafka 触发器

您可以根据 Apache Kafka 主题或支持 Kafka 协议的其他服务扩展 pod。自定义指标自动扩展不会缩放 Kafka 分区数量,除非在扩展的对象或扩展任务中将 allowIdleConsumers 参数设置为 true

注意

如果消费者组数量超过主题中的分区数量,则额外的消费者组处于闲置状态。

要避免这种情况,默认情况下副本数不会超过:

  • 如果指定了主题,则主题上的分区数量。
  • 如果没有指定主题,则消费者组中的所有主题的分区数量。
  • 在扩展对象或扩展作业 CR 中指定的 maxReplicaCount

您可以使用 allowIdleConsumers 参数禁用这些默认行为。

使用 Kafka 目标扩展对象示例

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: kafka-scaledobject
  namespace: my-namespace
spec:
 ...
  triggers:
  - type: kafka 1
    metadata:
      topic: my-topic 2
      bootstrapServers: my-cluster-kafka-bootstrap.openshift-operators.svc:9092 3
      consumerGroup: my-group 4
      lagThreshold: '10' 5
      activationLagThreshold 6
      offsetResetPolicy: 'latest' 7
      allowIdleConsumers: true 8
      scaleToZeroOnInvalidOffset: false 9
      excludePersistentLag: false 10
      version: 1.0.0 11
      partitionLimitation: '1,2,10-20,31' 12

1
指定 Kafka 作为 scaler/trigger 类型。
2
指定 Kafka 在处理偏移滞后的 Kafka 主题的名称。
3
指定要连接的 Kafka 代理的逗号分隔列表。
4
指定用于检查主题上的偏移以及处理相关滞后的 Kafka 消费者组的名称。
5
可选:指定触发扩展操作的平均目标值。默认值为 5
6
可选:指定激活阶段的目标值。
7
可选:为 Kafka 使用者指定 Kafka 偏移重置策略。可用值包括:latestearliest。默认为 latest
8
可选:指定 Kafka 副本数是否可以超过主题中的分区数量。
  • 如果为 true,则 Kafka 副本数可能会超过主题上的分区数量。这允许闲置 Kafka 用户。
  • 如果为 false,则 Kafka 副本数不能超过主题上的分区数量。这是默认值。
9
指定当 Kafka 分区没有有效偏移时触发器的行为方式。
  • 如果为 true,则该分区的用户将缩减为零。
  • 如果为 false,则 scaler 为该分区保留单个消费者。这是默认值。
10
可选:指定触发器是否为当前偏移与之前轮询周期的当前偏移量相同或排除分区滞后。
  • 如果为 true,则扩展程序会排除这些分区中的分区滞后。
  • 如果为 false,则触发器在所有分区中包含所有消费者滞后。这是默认值。
11
可选:指定 Kafka 代理的版本。默认值为 1.0.0
12
可选:指定一个以逗号分隔的分区 ID 列表来限制缩放。如果设置,则仅考虑计算滞后列出的 ID。默认为考虑所有分区。

2.5.5. 了解自定义指标自动扩展触发器身份验证

触发器身份验证允许您在扩展对象或可供关联容器使用的扩展作业中包含身份验证信息。您可以使用触发器身份验证来传递 OpenShift Container Platform secret、平台原生 Pod 验证机制、环境变量等。

您可以在与您要缩放的对象相同的命名空间中定义一个 TriggerAuthentication 对象。该触发器身份验证只能由该命名空间中的对象使用。

另外,要在多个命名空间中对象间共享凭证,您可以创建一个可在所有命名空间中使用的 ClusterTriggerAuthentication 对象。

触发验证和集群触发器身份验证使用相同的配置。但是,集群触发器身份验证需要在扩展对象的验证引用中有一个额外的 kind 参数。

使用 secret 的触发器验证示例

kind: TriggerAuthentication
apiVersion: keda.sh/v1alpha1
metadata:
  name: secret-triggerauthentication
  namespace: my-namespace 1
spec:
  secretTargetRef: 2
  - parameter: user-name 3
    name: my-secret 4
    key: USER_NAME 5
  - parameter: password
    name: my-secret
    key: PASSWORD

1
指定您要缩放的对象的命名空间。
2
指定此触发器身份验证使用 secret 进行授权。
3
使用 secret 指定提供的身份验证参数。
4
指定要使用的 secret 的名称。
5
指定 secret 中与指定参数一起使用的密钥。

使用 secret 的集群触发器身份验证示例

kind: ClusterTriggerAuthentication
apiVersion: keda.sh/v1alpha1
metadata: 1
  name: secret-cluster-triggerauthentication
spec:
  secretTargetRef: 2
  - parameter: user-name 3
    name: secret-name 4
    key: user-name 5
  - parameter: password
    name: secret-name
    key: user-name

1
请注意,没有命名空间用于集群触发器身份验证。
2
指定此触发器身份验证使用 secret 进行授权。
3
使用 secret 指定提供的身份验证参数。
4
指定要使用的 secret 的名称。
5
指定 secret 中与指定参数一起使用的密钥。

使用令牌进行触发器身份验证示例

kind: TriggerAuthentication
apiVersion: keda.sh/v1alpha1
metadata:
  name: token-triggerauthentication
  namespace: my-namespace 1
spec:
  secretTargetRef: 2
  - parameter: bearerToken 3
    name: my-token-2vzfq 4
    key: token 5
  - parameter: ca
    name: my-token-2vzfq
    key: ca.crt

1
指定您要缩放的对象的命名空间。
2
指定此触发器身份验证使用 secret 进行授权。
3
使用令牌指定要提供的身份验证参数。
4
指定要使用的令牌名称。
5
指定令牌中用于指定参数的密钥。

使用环境变量的触发器身份验证示例

kind: TriggerAuthentication
apiVersion: keda.sh/v1alpha1
metadata:
  name: env-var-triggerauthentication
  namespace: my-namespace 1
spec:
  env: 2
  - parameter: access_key 3
    name: ACCESS_KEY 4
    containerName: my-container 5

1
指定您要缩放的对象的命名空间。
2
指定此触发器身份验证使用环境变量进行授权。
3
指定要使用此变量设置的参数。
4
指定环境变量的名称。
5
可选:指定需要身份验证的容器。容器必须与扩展对象中的 scaleTargetRef 引用的资源相同。

使用 pod 验证供应商的触发器身份验证示例

kind: TriggerAuthentication
apiVersion: keda.sh/v1alpha1
metadata:
  name: pod-id-triggerauthentication
  namespace: my-namespace 1
spec:
  podIdentity: 2
    provider: aws-eks 3

1
指定您要缩放的对象的命名空间。
2
指定此触发器身份验证使用平台原生 Pod 验证方法进行授权。
3
指定 pod 身份。支持的值为 none, azure, aws-eks, 或 aws-kiam。默认为 none

其它资源

2.5.5.1. 使用触发器身份验证

您可以使用触发器验证和集群触发器身份验证,方法是使用自定义资源来创建身份验证,然后添加对扩展对象或扩展任务的引用。

先决条件

  • 必须安装 Custom Metrics Autoscaler Operator。
  • 如果使用 secret,Secret 对象必须存在,例如:

    secret 示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: my-secret
    data:
      user-name: <base64_username>
      password: <base64_password>

流程

  1. 创建 TriggerAuthenticationClusterTriggerAuthentication 对象。

    1. 创建定义对象的 YAML 文件:

      使用 secret 的触发器验证示例

      kind: TriggerAuthentication
      apiVersion: keda.sh/v1alpha1
      metadata:
        name: prom-triggerauthentication
        namespace: my-namespace
      spec:
        secretTargetRef:
        - parameter: user-name
          name: my-secret
          key: USER_NAME
        - parameter: password
          name: my-secret
          key: PASSWORD

    2. 创建 TriggerAuthentication 对象:

      $ oc create -f <file-name>.yaml
  2. 创建或编辑 ScaledObject YAML 文件:

    缩放对象示例

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: scaledobject
      namespace: my-namespace
    spec:
      scaleTargetRef:
        name: example-deployment
      maxReplicaCount: 100
      minReplicaCount: 0
      pollingInterval: 30
      triggers:
      - authenticationRef:
        type: prometheus
        metadata:
          serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9092
          namespace: kedatest # replace <NAMESPACE>
          metricName: http_requests_total
          threshold: '5'
          query: sum(rate(http_requests_total{job="test-app"}[1m]))
          authModes: "basic"
        - authenticationRef: 1
            name: prom-triggerauthentication
          metadata:
            name: prom-triggerauthentication
          type: object
        - authenticationRef: 2
            name: prom-cluster-triggerauthentication
            kind: ClusterTriggerAuthentication
          metadata:
            name: prom-cluster-triggerauthentication
          type: object

    1
    可选:指定一个触发器验证。
    2
    可选:指定一个集群触发器身份验证。您必须包含 kind: ClusterTriggerAuthentication 参数。
    注意

    不需要同时指定命名空间触发器身份验证和集群触发器身份验证。

  3. 创建对象。例如:

    $ oc apply -f <file-name>

2.5.6. 配置自定义指标自动扩展以使用 OpenShift Container Platform 监控

您可以使用已安装的 OpenShift Container Platform Prometheus 监控作为自定义指标自动扩展使用的指标的来源。但是,需要执行一些额外的配置。

注意

外部 Prometheus 源不需要这些步骤。

您必须执行以下任务,如本节所述:

  • 创建服务帐户以获取令牌。
  • 创建角色。
  • 将该角色添加到服务帐户。
  • 在 Prometheus 使用的触发器验证对象中引用令牌。

先决条件

  • 必须安装 OpenShift Container Platform 监控。
  • OpenShift Container Platform 监控中必须启用对用户定义的工作负载的监控监控,如创建用户定义的工作负载监控配置映射部分所述。
  • 必须安装 Custom Metrics Autoscaler Operator。

流程

  1. 使用您要缩放的对象切换到项目:

    $ oc project my-project
  2. 如果您的集群没有服务帐户,请使用以下命令来创建服务帐户:

    $ oc create serviceaccount <service_account>

    其中:

    <service_account>
    指定服务帐户的名称。
  3. 使用以下命令查找分配给服务帐户的令牌:

    $ oc describe serviceaccount <service_account>

    其中:

    <service_account>
    指定服务帐户的名称。

    输出示例

    Name:                thanos
    Namespace:           my-project
    Labels:              <none>
    Annotations:         <none>
    Image pull secrets:  thanos-dockercfg-nnwgj
    Mountable secrets:   thanos-dockercfg-nnwgj
    Tokens:              thanos-token-9g4n5 1
    Events:              <none>

    1
    在触发器身份验证中使用此令牌。
  4. 使用服务帐户令牌创建触发器身份验证:

    1. 创建一个类似以下示例的 YAML 文件:

      apiVersion: keda.sh/v1alpha1
      kind: TriggerAuthentication
      metadata:
        name: keda-trigger-auth-prometheus
      spec:
        secretTargetRef: 1
        - parameter: bearerToken 2
          name: thanos-token-9g4n5 3
          key: token 4
        - parameter: ca
          name: thanos-token-9g4n5
          key: ca.crt
      1
      指定此对象使用 secret 进行授权。
      2
      使用令牌指定要提供的身份验证参数。
      3
      指定要使用的令牌名称。
      4
      指定令牌中用于指定参数的密钥。
    2. 创建 CR 对象:

      $ oc create -f <file-name>.yaml
  5. 创建用于读取 Thanos 指标的角色:

    1. 使用以下参数创建 YAML 文件:

      apiVersion: rbac.authorization.k8s.io/v1
      kind: Role
      metadata:
        name: thanos-metrics-reader
      rules:
      - apiGroups:
        - ""
        resources:
        - pods
        verbs:
        - get
      - apiGroups:
        - metrics.k8s.io
        resources:
        - pods
        - nodes
        verbs:
        - get
        - list
        - watch
    2. 创建 CR 对象:

      $ oc create -f <file-name>.yaml
  6. 创建用于读取 Thanos 指标的角色绑定:

    1. 创建一个类似以下示例的 YAML 文件:

      apiVersion: rbac.authorization.k8s.io/v1
      kind: RoleBinding
      metadata:
        name: thanos-metrics-reader 1
        namespace: my-project 2
      roleRef:
        apiGroup: rbac.authorization.k8s.io
        kind: Role
        name: thanos-metrics-reader
      subjects:
      - kind: ServiceAccount
        name: thanos 3
        namespace: my-project 4
      1
      指定您创建的角色的名称。
      2
      指定您要缩放的对象的命名空间。
      3
      指定要绑定到角色的服务帐户的名称。
      4
      指定您要缩放的对象的命名空间。
    2. 创建 CR 对象:

      $ oc create -f <file-name>.yaml

现在,您可以部署扩展的对象或扩展作业来为应用程序启用自动扩展,如以下部分所述。要将 OpenShift Container Platform 监控用作源,在触发器或 scaler 中指定 prometheus 类型,并使用 https://thanos-querier.openshift-monitoring.svc.cluster.local:9092 作为 serverAddress

其它资源

2.5.7. 暂停工作负载的自定义指标自动扩展

您可以通过在该工作负载的自定义指标自动扩展中添加 autoscaling.keda.sh/paused-replicas 注解来暂停工作负载的自动扩展。自定义指标自动扩展将该工作负载的副本扩展到指定的值,并暂停自动扩展,直到注解被删除为止。

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  annotations:
    autoscaling.keda.sh/paused-replicas: "4"
...

要重启自动扩展,请编辑 ScaledObject CR 以删除注解。

例如,您可能想要在执行集群维护前暂停自动扩展,或通过删除非传输工作负载来避免资源不足。

流程

  1. 使用以下命令编辑工作负载的 ScaledObject CR:

    $ oc edit ScaledObject scaledobject
  2. 使用任何值添加 autoscaling.keda.sh/paused-replicas 注解:

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      annotations:
        autoscaling.keda.sh/paused-replicas: "4" 1
      creationTimestamp: "2023-02-08T14:41:01Z"
      generation: 1
      name: scaledobject
      namespace: my-project
      resourceVersion: "65729"
      uid: f5aec682-acdf-4232-a783-58b5b82f5dd0
    1
    指定自定义 Metrics Autoscaler Operator 将副本扩展到指定的值,并停止自动扩展。

2.5.8. 配置审计日志记录

您可以收集审计日志,它们是与安全相关的按时间排序的记录,记录各个用户、管理员或其他系统组件影响系统的一系列活动。

例如,审计日志可帮助您了解自动扩展请求来自哪里。当后端因为用户应用程序发出的请求造成过载时,这个信息非常重要,您需要确定哪个是有问题的应用程序。您可以通过编辑 KedaController 自定义资源来为自定义 Metrics Autoscaler Operator 配置审计。日志通过 KedaController CR 中的持久性卷声明发送到卷的审计日志文件。

先决条件

  • 必须安装 Custom Metrics Autoscaler Operator。

流程

  1. 编辑 KedaController 自定义资源以添加 auditConfig 小节:

    kind: KedaController
    apiVersion: keda.sh/v1alpha1
    metadata:
      name: keda
      namespace: openshift-keda
    spec:
     ...
      metricsServer:
     ...
        auditConfig:
          logFormat: "json" 1
          logOutputVolumeClaim: "pvc-audit-log" 2
          policy:
            rules: 3
            - level: Metadata
            omitStages: "RequestReceived" 4
            omitManagedFields: false 5
          lifetime: 6
            maxAge: "2"
            maxBackup: "1"
            maxSize: "50"
    1
    指定审计日志的输出格式,可以是 legacyjson
    2
    指定用于存储日志数据的现有持久性卷声明。所有来自 API 服务器的请求都会记录到此持久性卷声明。如果将此字段留空,日志数据将发送到 stdout。
    3
    指定应记录哪些事件及其应包含哪些数据:
    • None :不记录事件。
    • Metadata :仅记录请求的元数据,如用户、时间戳等。不要记录请求文本和响应文本。这是默认值。
    • Request :仅记录元数据和请求文本,而不记录响应文本。这个选项不适用于非资源请求。
    • RequestResponse :日志事件元数据、请求文本和响应文本。这个选项不适用于非资源请求。
    4
    指定没有创建事件的阶段。
    5
    指定是否省略请求的 managed 字段,并从写入 API 审计日志的响应正文,可以是 true 来省略字段,或 false 包含字段。
    6
    指定审计日志的大小和生命周期。
    • MaxAge :根据文件名中编码的时间戳,保留审计日志文件的最大天数。
    • maxBackup :要保留的审计日志文件的最大数量。设置为 0 以保留所有审计日志文件。
    • maxsize :在轮转审计日志文件前以 MB 为单位的最大大小。

验证

  1. 直接查看审计日志文件:

    1. 获取 keda-metrics-apiserver the pod 的名称:

      oc get pod -n openshift-keda

      输出示例

      NAME                                                  READY   STATUS    RESTARTS   AGE
      custom-metrics-autoscaler-operator-5cb44cd75d-9v4lv   1/1     Running   0          8m20s
      keda-metrics-apiserver-65c7cc44fd-rrl4r               1/1     Running   0          2m55s
      keda-operator-776cbb6768-zpj5b                        1/1     Running   0          2m55s

    2. 使用类似如下的命令查看日志数据:

      $ oc logs keda-metrics-apiserver-<hash>|grep -i metadata 1
      1
      可选: 您可以使用 grep 命令指定要显示的日志级别: MetadataRequestRequestResponse

      例如:

      $ oc logs keda-metrics-apiserver-65c7cc44fd-rrl4r|grep -i metadata

      输出示例

       ...
      {"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"4c81d41b-3dab-4675-90ce-20b87ce24013","stage":"ResponseComplete","requestURI":"/healthz","verb":"get","user":{"username":"system:anonymous","groups":["system:unauthenticated"]},"sourceIPs":["10.131.0.1"],"userAgent":"kube-probe/1.26","responseStatus":{"metadata":{},"code":200},"requestReceivedTimestamp":"2023-02-16T13:00:03.554567Z","stageTimestamp":"2023-02-16T13:00:03.555032Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":""}}
       ...

  2. 另外,您可以查看特定的日志:

    1. 使用类似如下的命令登录到 keda-metrics-apiserver the pod:

      $ oc rsh pod/keda-metrics-apiserver-<hash> -n openshift-keda

      例如:

      $ oc rsh pod/keda-metrics-apiserver-65c7cc44fd-rrl4r -n openshift-keda
    2. 进入 /var/audit-policy/ 目录:

      sh-4.4$ cd /var/audit-policy/
    3. 列出可用的日志:

      sh-4.4$ ls

      输出示例

      log-2023.02.17-14:50  policy.yaml

    4. 根据需要查看日志:

      sh-4.4$ cat <log_name>/<pvc_name>|grep -i <log_level> 1
      1
      可选: 您可以使用 grep 命令指定要显示的日志级别: MetadataRequestRequestResponse

      例如:

      sh-4.4$ cat log-2023.02.17-14:50/pvc-audit-log|grep -i Request

      输出示例

       ...
      {"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Request","auditID":"63e7f68c-04ec-4f4d-8749-bf1656572a41","stage":"ResponseComplete","requestURI":"/openapi/v2","verb":"get","user":{"username":"system:aggregator","groups":["system:authenticated"]},"sourceIPs":["10.128.0.1"],"responseStatus":{"metadata":{},"code":304},"requestReceivedTimestamp":"2023-02-17T13:12:55.035478Z","stageTimestamp":"2023-02-17T13:12:55.038346Z","annotations":{"authorization.k8s.io/decision":"allow","authorization.k8s.io/reason":"RBAC: allowed by ClusterRoleBinding \"system:discovery\" of ClusterRole \"system:discovery\" to Group \"system:authenticated\""}}
       ...

2.5.9. 了解如何添加自定义指标自动扩展

要添加自定义指标自动扩展,请为部署、有状态集或自定义资源创建 ScaledObject 自定义资源。为作业创建 ScaledJob 自定义资源。

您只能为每个您要扩展的工作负载创建一个扩展对象或扩展作业。另外,您不能在同一工作负载中使用扩展的对象或扩展作业以及 pod 横向自动扩展 (HPA)。

2.5.9.1. 在工作负载中添加自定义指标自动扩展

您可以为 DeploymentStatefulSetcustom resource 对象创建的工作负载创建自定义指标自动扩展。

先决条件

  • 必须安装 Custom Metrics Autoscaler Operator。
  • 如果您使用自定义指标自动扩展来根据 CPU 或内存进行扩展:

    • 您的集群管理员必须已配置了集群指标。您可以使用 oc describe PodMetrics <pod-name> 命令来判断是否已配置了指标。如果配置了指标,输出将类似以下示例,CPU 和 Memory 在 Usage 下显示。

      $ oc describe PodMetrics openshift-kube-scheduler-ip-10-0-135-131.ec2.internal

      输出示例

      Name:         openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
      Namespace:    openshift-kube-scheduler
      Labels:       <none>
      Annotations:  <none>
      API Version:  metrics.k8s.io/v1beta1
      Containers:
        Name:  wait-for-host-port
        Usage:
          Memory:  0
        Name:      scheduler
        Usage:
          Cpu:     8m
          Memory:  45440Ki
      Kind:        PodMetrics
      Metadata:
        Creation Timestamp:  2019-05-23T18:47:56Z
        Self Link:           /apis/metrics.k8s.io/v1beta1/namespaces/openshift-kube-scheduler/pods/openshift-kube-scheduler-ip-10-0-135-131.ec2.internal
      Timestamp:             2019-05-23T18:47:56Z
      Window:                1m0s
      Events:                <none>

    • 与您要缩放的对象关联的 pod 必须包含指定的内存和 CPU 限值。例如:

      pod 规格示例

      apiVersion: v1
      kind: Pod
       ...
      spec:
        containers:
        - name: app
          image: images.my-company.example/app:v4
          resources:
            limits:
              memory: "128Mi"
              cpu: "500m"

流程

  1. 创建一个类似如下的 YAML 文件:只有名称 <2>, 对象名称 <4>, 和对象类型 <5> 是必需的。

    缩放对象示例

    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      annotations:
        autoscaling.keda.sh/paused-replicas: "0" 1
      name: scaledobject 2
      namespace: my-namespace
    spec:
      scaleTargetRef:
        api: apps/v1 3
        name: example-deployment 4
        kind: Deployment 5
        envSourceContainerName: .spec.template.spec.containers[0] 6
      cooldownPeriod:  200 7
      maxReplicaCount: 100 8
      minReplicaCount: 0 9
      metricsServer: 10
        auditConfig:
          logFormat: "json"
          logOutputVolumeClaim: "persistentVolumeClaimName"
          policy:
            rules:
            - level: Metadata
            omitStages: "RequestReceived"
            omitManagedFields: false
          lifetime:
            maxAge: "2"
            maxBackup: "1"
            maxSize: "50"
      fallback: 11
        failureThreshold: 3
        replicas: 6
      pollingInterval: 30 12
      advanced:
        restoreToOriginalReplicaCount: false 13
        horizontalPodAutoscalerConfig:
          name: keda-hpa-scale-down 14
          behavior: 15
            scaleDown:
              stabilizationWindowSeconds: 300
              policies:
              - type: Percent
                value: 100
                periodSeconds: 15
      triggers:
      - type: prometheus 16
        metadata:
          serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9092
          namespace: kedatest
          metricName: http_requests_total
          threshold: '5'
          query: sum(rate(http_requests_total{job="test-app"}[1m]))
          authModes: "basic"
      - authenticationRef: 17
          name: prom-triggerauthentication
        metadata:
          name: prom-triggerauthentication
        type: object
      - authenticationRef: 18
          name: prom-cluster-triggerauthentication
        metadata:
          name: prom-cluster-triggerauthentication
        type: object

    1
    可选:指定自定义 Metrics Autoscaler Operator 将副本扩展到指定的值和停止自动扩展,如 "Pausing the custom metrics autoscaler for a workload" 部分所述。
    2
    指定此自定义指标自动扩展的名称。
    3
    可选:指定目标资源的 API 版本。默认为 apps/v1
    4
    指定要缩放的对象名称。
    5
    指定 kindDeployment, StatefulSetCustomResource
    6
    可选:指定目标资源中的容器的名称,其中的自定义自动扩展器获取包含 secret 的环境变量等。默认为 .spec.template.spec.containers[0]
    7
    可选。指定一个在最后的触发器报告后等待的时间(以秒为单位),在经过这个时间后才会将部署缩减为 0(如果 minReplicaCount 设置为 0)。默认值为 300
    8
    可选:指定扩展时的最大副本数量。默认值为 100
    9
    可选:指定缩减时的最小副本数量。
    10
    可选:指定审计日志的参数。如"配置审计日志记录"部分中所述。
    11
    可选:指定在扩展程序无法从源中获取由 failureThreshold 参数定义的次数时回退到的副本数。有关回退行为的更多信息,请参阅 KEDA 文档
    12
    可选:指定检查每个触发器的时间间隔(以秒为单位)。默认值为 30
    13
    可选:指定是否在删除扩展对象后将目标资源扩展为原始副本数。默认为 false,这会在删除扩展对象时保留副本数。
    14
    可选:指定 pod 横向自动扩展的名称。默认为 keda-hpa-{scaled-object-name}
    15
    可选:指定一个扩展策略来控制用来扩展或缩减 pod 的速度,如"扩展策略"部分中所述。
    16
    指定用作扩展基础的触发器,如"识别自定义指标自动扩展触发器"部分中所述。本例使用 OpenShift Container Platform 监控。
    17
    可选:指定触发器身份验证,如 "Creating a custom metrics autoscaler trigger authentication" 部分所述。
    18
    可选:指定集群触发器身份验证,如 "Creating a custom metrics autoscaler trigger authentication" 部分所述。
    注意

    不需要同时指定命名空间触发器身份验证和集群触发器身份验证。

  2. 创建自定义指标自动扩展:

    $ oc create -f <file-name>.yaml

验证

  • 查看命令输出,以验证是否已创建自定义指标自动扩展:

    $ oc get scaledobject <scaled_object_name>

    输出示例

    NAME            SCALETARGETKIND      SCALETARGETNAME        MIN   MAX   TRIGGERS     AUTHENTICATION               READY   ACTIVE   FALLBACK   AGE
    scaledobject    apps/v1.Deployment   example-deployment     0     50    prometheus   prom-triggerauthentication   True    True     True       17s

    请注意输出中的以下字段:

  • TRIGGERS :指示正在使用的触发器或缩放器。
  • AUTHENTICATION :指示所使用的任何触发器身份验证的名称。
  • READY :指示扩展对象是否准备好启动缩放:

    • 如果为 True,则扩展的对象已就绪。
    • 如果 False,由于您创建的对象中的一个或多个对象有问题,扩展的对象将不可用。
  • ACTIVE :指示扩展是否发生:

    • 如果为 True,则会进行缩放。
    • 如果 False,则不会发生缩放,因为您创建的一个或多个对象中没有指标或多个问题。
  • FALLBACK :指示自定义指标自动扩展是否能够从源获取指标

    • 如果 False,自定义指标自动扩展器会获取指标。
    • 如果为 True,自定义指标自动扩展会获取指标,因为您创建的一个或多个对象中没有指标或多个问题。

2.5.9.2. 在作业中添加自定义指标自动扩展

您可以为任何作业对象创建自定义指标自动扩展。

先决条件

  • 必须安装 Custom Metrics Autoscaler Operator。

流程

  1. 创建一个类似以下示例的 YAML 文件:

    kind: ScaledJob
    apiVersion: keda.sh/v1alpha1
    metadata:
      name: scaledjob
      namespace: my-namespace
    spec:
      failedJobsHistoryLimit: 5
      jobTargetRef:
        activeDeadlineSeconds: 600 1
        backoffLimit: 6 2
        parallelism: 1 3
        completions: 1 4
        template:  5
          metadata:
            name: pi
          spec:
            containers:
            - name: pi
              image: perl
              command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      maxReplicaCount: 100 6
      pollingInterval: 30 7
      successfulJobsHistoryLimit: 5 8
      failedJobsHistoryLimit: 5 9
      envSourceContainerName: 10
      rolloutStrategy: gradual 11
      scalingStrategy: 12
        strategy: "custom"
        customScalingQueueLengthDeduction: 1
        customScalingRunningJobPercentage: "0.5"
        pendingPodConditions:
          - "Ready"
          - "PodScheduled"
          - "AnyOtherCustomPodCondition"
        multipleScalersCalculation : "max"
      triggers:
      - type: prometheus 13
        metadata:
          serverAddress: https://thanos-querier.openshift-monitoring.svc.cluster.local:9092
          namespace: kedatest
          metricName: http_requests_total
          threshold: '5'
          query: sum(rate(http_requests_total{job="test-app"}[1m]))
          authModes: "bearer"
      - authenticationRef: 14
          name: prom-triggerauthentication
        metadata:
          name: prom-triggerauthentication
         type: object
      - authenticationRef: 15
          name: prom-cluster-triggerauthentication
        metadata:
          name: prom-cluster-triggerauthentication
        type: object
    1
    指定作业可以运行的最长持续时间。
    2
    指定作业的重试次数。默认值为 6
    3
    可选:指定作业应并行运行多少个 pod 副本;默认为 1
    • 对于非并行作业,请保留未设置。如果未设置,则默认值为 1
    4
    可选:指定标记作业完成需要成功完成多少个 pod。
    • 对于非并行作业,请保留未设置。如果未设置,则默认值为 1
    • 对于具有固定完成计数的并行作业,请指定完成数。
    • 对于带有工作队列的并行作业,请保留 unset。当取消设置默认值时,默认值为 parallelism 参数的值。
    5
    指定控制器创建的 pod 模板。
    6
    可选:指定扩展时的最大副本数量。默认值为 100
    7
    可选:指定检查每个触发器的时间间隔(以秒为单位)。默认值为 30
    8
    可选:指定成功完成作业的数量。默认值为 100
    9
    可选:指定应保留多少个失败作业。默认值为 100
    10
    可选:指定目标资源中的容器的名称,其中的自定义自动扩展器获取包含 secret 的环境变量等。默认为 .spec.template.spec.containers[0]
    11
    可选:指定在更新扩展作业时是否被终止现有作业:
    • default :如果关联的扩展作业被更新,则自动扩展器会终止一个现有作业。自动扩展会使用最新的 specs 重新创建作业。
    • gradual :如果关联的扩展作业被更新,则自动扩展不会终止现有的作业。自动缩放器使用最新的 specs 创建新作业。
    12
    可选:指定一个扩展策略: defaultcustomaccurate。默认为 default。如需更多信息,请参阅下面的"添加资源"部分中的链接。
    13
    指定用作扩展基础的触发器,如"识别自定义指标自动扩展触发器"部分中所述。
    14
    可选:指定触发器身份验证,如 "Creating a custom metrics autoscaler trigger authentication" 部分所述。
    15
    可选:指定集群触发器身份验证,如 "Creating a custom metrics autoscaler trigger authentication" 部分所述。
    注意

    不需要同时指定命名空间触发器身份验证和集群触发器身份验证。

  2. 创建自定义指标自动扩展:

    $ oc create -f <file-name>.yaml

验证

  • 查看命令输出,以验证是否已创建自定义指标自动扩展:

    $ oc get scaledjob <scaled_job_name>

    输出示例

    NAME        MAX   TRIGGERS     AUTHENTICATION              READY   ACTIVE    AGE
    scaledjob   100   prometheus   prom-triggerauthentication  True    True      8s

    请注意输出中的以下字段:

  • TRIGGERS :指示正在使用的触发器或缩放器。
  • AUTHENTICATION :指示所使用的任何触发器身份验证的名称。
  • READY :指示扩展对象是否准备好启动缩放:

    • 如果为 True,则扩展的对象已就绪。
    • 如果 False,由于您创建的对象中的一个或多个对象有问题,扩展的对象将不可用。
  • ACTIVE :指示扩展是否发生:

    • 如果为 True,则会进行缩放。
    • 如果 False,则不会发生缩放,因为您创建的一个或多个对象中没有指标或多个问题。

2.5.10. 卸载自定义 Metrics Autoscaler Operator

您可以从 OpenShift Container Platform 集群中删除自定义指标自动扩展。删除自定义 Metrics Autoscaler Operator 后,删除与 Operator 相关的其他组件以避免出现潜在的问题。

注意

您应该首先删除 KedaController 自定义资源 (CR)。如果您没有特别删除 CR,OpenShift Container Platform 会在删除 openshift-keda 项目时挂起。如果在删除 CR 前删除了自定义 Metrics Autoscaler Operator,您将无法删除 CR。

先决条件

  • 必须安装 Custom Metrics Autoscaler Operator。

流程

  1. 在 OpenShift Container Platform web 控制台中,点击 OperatorsInstalled Operators
  2. 切换到 openshift-keda 项目。
  3. 删除 KedaController 自定义资源。

    1. 找到 CustomMetricsAutoscaler Operator 并点 KedaController 选项卡。
    2. 找到自定义资源,然后点 Delete KedaController
    3. Uninstall
  4. 删除自定义 Metrics Autoscaler Operator:

    1. OperatorsInstalled Operators
    2. 找到 CustomMetricsAutoscaler Operator 并点 Options 菜单 kebab 并选择 Uninstall Operator
    3. Uninstall
  5. 可选: 使用 OpenShift CLI 删除自定义指标自动扩展组件:

    1. 删除自定义指标自动扩展 CRD:

      • clustertriggerauthentications.keda.sh
      • kedacontrollers.keda.sh
      • scaledjobs.keda.sh
      • scaledobjects.keda.sh
      • triggerauthentications.keda.sh
      $ oc delete crd clustertriggerauthentications.keda.sh kedacontrollers.keda.sh scaledjobs.keda.sh scaledobjects.keda.sh triggerauthentications.keda.sh

      删除 CRD 会删除关联的角色、集群角色和角色绑定。但是,可能存在一些必须手动删除的集群角色。

    2. 列出任何自定义指标自动扩展集群角色:

      $ oc get clusterrole | grep keda.sh
    3. 删除列出的自定义指标自动扩展集群角色。例如:

      $ oc delete clusterrole.keda.sh-v1alpha1-admin
    4. 列出任何自定义指标自动扩展集群角色绑定:

      $ oc get clusterrolebinding | grep keda.sh
    5. 删除列出的自定义指标自动扩展集群角色绑定。例如:

      $ oc delete clusterrolebinding.keda.sh-v1alpha1-admin
  6. 删除自定义指标自动扩展项目:

    $ oc delete project openshift-keda
  7. 删除 Cluster Metric Autoscaler Operator:

    $ oc delete operator/openshift-custom-metrics-autoscaler-operator.openshift-keda

2.6. 使用垂直 pod 自动扩展自动调整 pod 资源级别

OpenShift Container Platform Vertical Pod Autoscaler Operator(VPA)会自动检查 pod 中容器的运行状况和当前的 CPU 和内存资源,并根据它所了解的用量值更新资源限值和请求。VPA 使用单独的自定义资源(CR)来更新与工作负载对象关联的所有 Pod,如 DeploymentDeployment ConfigStatefulSetJobDaemonSetReplicaSetReplicationController

VPA 可帮助您了解 Pod 的最佳 CPU 和内存使用情况,并可以通过 pod 生命周期自动维护 pod 资源。

2.6.1. 关于 Vertical Pod Autoscaler Operator

Vertical Pod Autoscaler Operator(VPA)作为 API 资源和自定义资源(CR)实现。CR 决定 Vertical Pod Autoscaler Operator 对与特定工作负载对象(如守护进程集、复制控制器等)关联的 pod 执行的操作。

您可以使用默认推荐程序,或使用您自己的备选推荐程序根据您自己的算法自动扩展。

默认推荐器会自动计算这些 pod 中容器的流程以及当前的 CPU 和内存使用情况,并使用这些数据来决定优化的资源限制和请求,以确保这些 pod 始终高效操作。例如,默认推荐器会建议,减少请求资源超过使用资源的 pod 的资源,并为没有请求充足资源的 pod 增加资源。

VPA 每次自动删除任何与建议不兼容的 pod,以便您的应用程序可以在不需要停机的情况下继续满足请求。然后,工作负载对象使用原始资源限制和请求重新部署 pod。VPA 使用一个变异准入 webhook 来更新 pod,在 pod 被允许到节点前,具有优化的资源限制和请求。如果您不希望 VPA 删除 pod,可以查看 VPA 资源限制和请求,并根据需要手动更新 pod。

注意

默认情况下,工作负载对象必须至少指定两个副本,以便 VPA 自动删除其 pod。指定了比这个最小值更少的副本数的工作负载对象不会被删除。如果您手动删除这些 pod,当工作负载对象重新部署 pod 时,VPA 会使用其建议更新新的 pod。您可以通过修改 VerticalPodAutoscalerController 对象来更改这个最小值,如更改 VPA 最小值所示。

例如,您有一个 pod 使用了 CPU 的 50%,但只请求 10%。VPA 会认定该 pod 消耗的 CPU 多于请求的 CPU,并删除 pod。工作负载对象(如副本集)会重启 pod,VPA 使用推荐的资源更新新 pod。

对于开发人员,您可以使用 VPA 来帮助确保 pod 在高负载时可以继续工作,具体方法是将 pod 调度到每个 pod 具有适当资源的节点上。

管理员可以使用 VPA 来更好地利用集群资源,例如防止 pod 保留比所需的 CPU 资源更多的资源。VPA 监控实际使用的工作负载,并对资源进行调整,以确保可以满足其他工作负载的需要。VPA 还维护初始容器配置中指定的限值和请求之间的比例。

注意

如果您停止在集群中运行 VPA,或删除特定的 VPA CR,则已由 VPA 修改的 pod 的资源请求不会改变。任何新 pod 都会根据工作负载对象中的定义获得资源,而不是之前由 VPA 提供的的建议。

2.6.2. 安装 Vertical Pod Autoscaler Operator

您可以使用 OpenShift Container Platform web 控制台安装 Vertical Pod Autoscaler Operator(VPA)。

流程

  1. 在 OpenShift Container Platform Web 控制台中,点击 OperatorsOperatorHub
  2. 从可用 Operator 列表中选择 VerticalPodAutoscaler,点 Install
  3. Install Operator 页面中,确保选择了 Operator 推荐的命名空间 选项。这会在 openshift-vertical-pod-autoscaler 命名空间中创建 Operator。如果这个命名空间还没有存在,会自动创建它。
  4. Install
  5. 列出 VPA Operator 组件来验证安装:

    1. 导航到 WorkloadsPods
    2. 从下拉菜单中选择 openshift-vertical-pod-autoscaler 项目,并验证是否运行了四个 pod。
    3. 进入 WorkloadsDeployments 以验证运行了四个部署。
  6. 可选。使用以下命令在 OpenShift Container Platform CLI 中验证安装:

    $ oc get all -n openshift-vertical-pod-autoscaler

    输出显示四个 pod 和四个部署:

    输出示例

    NAME                                                    READY   STATUS    RESTARTS   AGE
    pod/vertical-pod-autoscaler-operator-85b4569c47-2gmhc   1/1     Running   0          3m13s
    pod/vpa-admission-plugin-default-67644fc87f-xq7k9       1/1     Running   0          2m56s
    pod/vpa-recommender-default-7c54764b59-8gckt            1/1     Running   0          2m56s
    pod/vpa-updater-default-7f6cc87858-47vw9                1/1     Running   0          2m56s
    
    NAME                  TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    service/vpa-webhook   ClusterIP   172.30.53.206   <none>        443/TCP   2m56s
    
    NAME                                               READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/vertical-pod-autoscaler-operator   1/1     1            1           3m13s
    deployment.apps/vpa-admission-plugin-default       1/1     1            1           2m56s
    deployment.apps/vpa-recommender-default            1/1     1            1           2m56s
    deployment.apps/vpa-updater-default                1/1     1            1           2m56s
    
    NAME                                                          DESIRED   CURRENT   READY   AGE
    replicaset.apps/vertical-pod-autoscaler-operator-85b4569c47   1         1         1       3m13s
    replicaset.apps/vpa-admission-plugin-default-67644fc87f       1         1         1       2m56s
    replicaset.apps/vpa-recommender-default-7c54764b59            1         1         1       2m56s
    replicaset.apps/vpa-updater-default-7f6cc87858                1         1         1       2m56s

2.6.3. 关于使用 Vertical Pod Autoscaler Operator

要使用 Vertical Pod Autoscaler Operator(vpa),您需要为集群中的工作负载对象创建 VPA 自定义资源(CR)。VPA 学习并应用与该工作负载对象关联的 pod 的最佳 CPU 和内存资源。您可以使用 VPA 与部署、有状态集、作业、守护进程集、副本集或复制控制器工作负载对象一起使用。VPA CR 必须与您要监控的 pod 位于同一个项目中。

您可以使用 VPA CR 关联一个工作负载对象,并指定 VPA 使用什么模式运行:

  • AutoRecreate 模式会在 pod 生命周期内自动应用 VPA 对 CPU 和内存建议。VPA 会删除项目中任何与建议不兼容的 pod。当由工作负载对象重新部署时,VPA 会在其建议中更新新 pod。
  • Initial 模式仅在创建 pod 时自动应用 VPA 建议。
  • Off 模式只提供推荐的资源限制和请求信息,用户可以手动应用其中的建议。off 模式不会更新 pod。

您还可以使用 CR 使特定容器不受 VPA 评估和更新的影响。

例如,pod 具有以下限制和请求:

resources:
  limits:
    cpu: 1
    memory: 500Mi
  requests:
    cpu: 500m
    memory: 100Mi

在创建了一个设置为 auto 的 VPA 后,VPA 会了解资源使用情况并删除 pod。重新部署时,pod 会使用新的资源限值和请求:

resources:
  limits:
    cpu: 50m
    memory: 1250Mi
  requests:
    cpu: 25m
    memory: 262144k

您可以使用以下命令查看 VPA 建议:

$ oc get vpa <vpa-name> --output yaml

几分钟后,输出显示 CPU 和内存请求的建议,如下所示:

输出示例

...
status:
...
  recommendation:
    containerRecommendations:
    - containerName: frontend
      lowerBound:
        cpu: 25m
        memory: 262144k
      target:
        cpu: 25m
        memory: 262144k
      uncappedTarget:
        cpu: 25m
        memory: 262144k
      upperBound:
        cpu: 262m
        memory: "274357142"
    - containerName: backend
      lowerBound:
        cpu: 12m
        memory: 131072k
      target:
        cpu: 12m
        memory: 131072k
      uncappedTarget:
        cpu: 12m
        memory: 131072k
      upperBound:
        cpu: 476m
        memory: "498558823"
...

输出显示推荐的资源、目标、最低推荐资源、lowerBound、最高推荐资源、upperBound、以及最新资源建议和 uncappedTarget

VPA 使用 lessBoundupperBound 值来确定一个 pod 是否需要更新。如果 pod 的资源请求低于 lowerBound 值,或高于 upperBound 值,则 VPA 会终止 pod,并使用 target 值重新创建 pod。

2.6.3.1. 更改 VPA 最小值

默认情况下,工作负载对象必须至少指定两个副本,以便 VPA 自动删除和更新其 pod。因此,VPA 不会自动执行指定少于两个副本的工作负载对象。如果 pod 由 VPA 外部的一些进程重启,VPA 会从这些工作负载对象更新的新 pod。您可以通过修改 VerticalPodAutoscalerController 自定义资源(CR)中的 minReplicas 参数来更改此集群范围的最小值。

例如,如果您将 minReplicas 设置为 3,则 VPA 不会为指定少于三个副本的工作负载对象删除和更新 pod。

注意

如果将 minReplicas 设置为 1,则 VPA 可以为只指定一个副本的工作负载对象删除唯一的 pod。只有在 VPA 删除 pod 以调整其资源时,您的工作负载可以允许停机时,才应使用此设置来使用一个副本对象。为了避免使用一个副本的对象出现不必要的停机时间,将带有 podUpdatePolicy 设置的 VPA CR 配置为 Initial,这只有在 VPA 外部的一些进程重启时,或状态为 Off 时才重启。这可让您在适合的时间手动更新 pod。

VerticalPodAutoscalerController 对象示例

apiVersion: autoscaling.openshift.io/v1
kind: VerticalPodAutoscalerController
metadata:
  creationTimestamp: "2021-04-21T19:29:49Z"
  generation: 2
  name: default
  namespace: openshift-vertical-pod-autoscaler
  resourceVersion: "142172"
  uid: 180e17e9-03cc-427f-9955-3b4d7aeb2d59
spec:
  minReplicas: 3 1
  podMinCPUMillicores: 25
  podMinMemoryMb: 250
  recommendationOnly: false
  safetyMarginFraction: 0.15

1
指定 VPA 中要操作的工作负载对象中的最小副本数。VPA 不会自动删除任何小于最小副本的对象。

2.6.3.2. 自动应用 VPA 建议

要使用 VPA 来自动更新 pod,为特定工作负载对象创建一个 VPA CR,并将 updateMode 设置为 AutoRecreate

当为工作复杂对象创建 pod 时,VPA 会持续监控容器以分析其 CPU 和内存需求。VPA 会删除任何不满足 VPA 对 CPU 和内存的建议的 pod。重新部署后,pod 根据 VPA 建议使用新的资源限值和请求,并遵循您的应用程序的 pod 中断预算。建议被添加到 VPA CR 的 status 字段中以进行引用。

注意

默认情况下,工作负载对象必须至少指定两个副本,以便 VPA 自动删除其 pod。指定了比这个最小值更少的副本数的工作负载对象不会被删除。如果您手动删除这些 pod,当工作负载对象重新部署 pod 时,VPA 会使用其建议更新新的 pod。您可以通过修改 VerticalPodAutoscalerController 对象来更改这个最小值,如更改 VPA 最小值所示。

Auto 模式的 VPA CR 示例

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vpa-recommender
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment 1
    name:       frontend 2
  updatePolicy:
    updateMode: "Auto" 3

1
您希望此 VPA CR 管理的工作负载对象类型。
2
您希望此 VPA CR 管理的工作负载对象名称。
3
将模式设置为 AutoRecreate:
  • Auto.VPA 分配创建 pod 的资源请求,并在请求的资源与新建议有很大不同时终止这些 Pod 来更新现存的 pod。
  • Recreate。VPA 分配创建 pod 的资源请求,并在请求的资源与新建议有很大不同时终止这些 Pod 来更新现存的 pod。这个模式应该很少使用,只有在需要确保每当资源请求改变时 pod 就需要重启时才使用。
注意

在 VPA 可以决定推荐的资源并对新 pod 应用推荐前,pod 必须已在运行。

2.6.3.3. 在创建 pod 时自动应用 VPA 建议

要仅在 pod 首次部署时使用 VPA 来应用推荐的资源,为特定的工作负载对象创建一个 VPA CR,将 updateMode 设置为 Initial

然后,手动删除与您要使用 VPA 建议的工作负载对象关联的 pod。在 Initial 模式中,VPA 不会删除 pod,也不会更新 pod,它会学习新的资源建议。

Initial 模式的 VPA CR 示例

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vpa-recommender
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment 1
    name:       frontend 2
  updatePolicy:
    updateMode: "Initial" 3

1
您希望此 VPA CR 管理的工作负载对象类型。
2
您希望此 VPA CR 管理的工作负载对象名称。
3
将模式设置为 Initial。VPA 在 pod 创建时分配资源,在 pod 生命周期中不会更改资源。
注意

在 VPA 可以决定推荐的资源并对新 pod 应用推荐前,项目中必须已有已在运行的 pod。

2.6.3.4. 手动应用 VPA 建议

要使用 VPA 来仅决定推荐的 CPU 和内存值而不进行实际的应用,对特定的工作负载创建一个 VPA CR,把 updateMode 设置为 off

当为该工作负载对象创建 pod 时, VPA 会分析容器的 CPU 和内存需求,并在 VPA CR 的 status 字段中记录推荐。VPA 会提供新的资源建议,但不会更新 pod。

使用 Off 模式的 VPA CR 示例

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vpa-recommender
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment 1
    name:       frontend 2
  updatePolicy:
    updateMode: "Off" 3

1
您希望此 VPA CR 管理的工作负载对象类型。
2
您希望此 VPA CR 管理的工作负载对象名称。
3
将模式设置为 Off

您可以使用以下命令查看建议。

$ oc get vpa <vpa-name> --output yaml

根据建议,您可以编辑工作负载对象以添加 CPU 和内存请求,然后删除 pod 并使用推荐的资源重新部署 pod。

注意

在 VPA 可以决定推荐的资源前,pod 必须已在运行。

2.6.3.5. 阻止容器特定容器应用 VPA 建议

如果您的工作负载对象有多个容器,且您不希望 VPA 对所有容器进行评估并进行操作,请为特定工作负载对象创建一个 VPA CR,添加一个 resourcePolicy 已使特定容器不受 VPA 的影响。

当 VPA 使用推荐的资源更新 pod 时,任何带有 resourcePolicy 的容器都不会被更新,且 VPA 不会对这些 pod 中的容器提供建议。

apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: vpa-recommender
spec:
  targetRef:
    apiVersion: "apps/v1"
    kind:       Deployment 1
    name:       frontend 2
  updatePolicy:
    updateMode: "Auto" 3
  resourcePolicy: 4
    containerPolicies:
    - containerName: my-opt-sidecar
      mode: "Off"
1
您希望此 VPA CR 管理的工作负载对象类型。
2
您希望此 VPA CR 管理的工作负载对象名称。
3
将模式设置为 AutoRecreateOffRecreate 模式应该很少使用,只有在需要确保每当资源请求改变时 pod 就需要重启时才使用。
4
指定不受 VPA 影响的容器,将 mode 设置为 Off

例如,一个 pod 有两个容器,它们有相同的资源请求和限值:

# ...
spec:
  containers:
  - name: frontend
    resources:
      limits:
        cpu: 1
        memory: 500Mi
      requests:
        cpu: 500m
        memory: 100Mi
  - name: backend
    resources:
      limits:
        cpu: "1"
        memory: 500Mi
      requests:
        cpu: 500m
        memory: 100Mi
# ...

在启用一个带有 backend 排除容器设置的 VPA CR 后,VPA 终止并使用推荐的资源重新创建 pod 的行为只适用于 frontend 容器:

...
spec:
  containers:
    name: frontend
    resources:
      limits:
        cpu: 50m
        memory: 1250Mi
      requests:
        cpu: 25m
        memory: 262144k
...
    name: backend
    resources:
      limits:
        cpu: "1"
        memory: 500Mi
      requests:
        cpu: 500m
        memory: 100Mi
...

2.6.3.6. 使用一个替代推荐器

您可以根据自己的算法使用自己的推荐器来自动扩展。如果您没有指定替代的推荐器,OpenShift Container Platform 会使用默认的推荐器,它会根据历史使用情况推荐 CPU 和内存请求。因为没有适用于所有工作负载的通用推荐策略,您可能需要为特定工作负载创建和部署不同的推荐器。

例如,当容器出现某些资源行为时,默认的推荐器可能无法准确预测将来的资源使用量,例如,在监控应用程序使用的使用量高峰和闲置间交替的模式,或者重复与深度学习应用程序使用的模式。将默认推荐器用于这些使用行为可能会导致应用程序的过度置备和内存不足(OOM)终止。

注意

有关如何创建推荐器的说明超出了本文档的范围,

流程

为 pod 使用替代推荐器:

  1. 为替代推荐器创建服务帐户,并将该服务帐户绑定到所需的集群角色:

    apiVersion: v1 1
    kind: ServiceAccount
    metadata:
      name: alt-vpa-recommender-sa
      namespace: <namespace_name>
    ---
    apiVersion: rbac.authorization.k8s.io/v1 2
    kind: ClusterRoleBinding
    metadata:
      name: system:example-metrics-reader
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:metrics-reader
    subjects:
    - kind: ServiceAccount
      name: alt-vpa-recommender-sa
      namespace: <namespace_name>
    ---
    apiVersion: rbac.authorization.k8s.io/v1 3
    kind: ClusterRoleBinding
    metadata:
      name: system:example-vpa-actor
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:vpa-actor
    subjects:
    - kind: ServiceAccount
      name: alt-vpa-recommender-sa
      namespace: <namespace_name>
    ---
    apiVersion: rbac.authorization.k8s.io/v1 4
    kind: ClusterRoleBinding
    metadata:
      name: system:example-vpa-target-reader-binding
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: system:vpa-target-reader
    subjects:
    - kind: ServiceAccount
      name: alt-vpa-recommender-sa
      namespace: <namespace_name>
    1
    在部署了推荐器的命名空间中为推荐器创建一个服务账户。
    2
    将推进器服务帐户绑定到 metrics-reader 角色。指定要部署推进器的命名空间。
    3
    将推进器服务帐户绑定到 vpa-actor 角色。指定要部署推进器的命名空间。
    4
    将推进器服务帐户绑定到 vpa-target-reader 角色。指定要部署推进器的命名空间。
  2. 要在集群中添加备选推荐程序,请创建一个类似如下的 Deployment 对象:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: alt-vpa-recommender
      namespace: <namespace_name>
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: alt-vpa-recommender
      template:
        metadata:
          labels:
            app: alt-vpa-recommender
        spec:
          containers: 1
          - name: recommender
            image: quay.io/example/alt-recommender:latest 2
            imagePullPolicy: Always
            resources:
              limits:
                cpu: 200m
                memory: 1000Mi
              requests:
                cpu: 50m
                memory: 500Mi
            ports:
            - name: prometheus
              containerPort: 8942
            securityContext:
              allowPrivilegeEscalation: false
              capabilities:
                drop:
                  - ALL
              seccompProfile:
                type: RuntimeDefault
          serviceAccountName: alt-vpa-recommender-sa 3
          securityContext:
            runAsNonRoot: true
    1
    为您的备选推荐程序创建容器。
    2
    指定您的推荐镜像。
    3
    关联您为推荐器创建的服务帐户。

    为同一命名空间中的备选推荐器创建新 pod。

    $ oc get pods

    输出示例

    NAME                                        READY   STATUS    RESTARTS   AGE
    frontend-845d5478d-558zf                    1/1     Running   0          4m25s
    frontend-845d5478d-7z9gx                    1/1     Running   0          4m25s
    frontend-845d5478d-b7l4j                    1/1     Running   0          4m25s
    vpa-alt-recommender-55878867f9-6tp5v        1/1     Running   0          9s

  3. 配置包含替代推荐器 Deployment 对象名称的 VPA CR。

    VPA CR 示例,使其包含替代的推荐程序

    apiVersion: autoscaling.k8s.io/v1
    kind: VerticalPodAutoscaler
    metadata:
      name: vpa-recommender
      namespace: <namespace_name>
    spec:
      recommenders:
        - name: alt-vpa-recommender 1
      targetRef:
        apiVersion: "apps/v1"
        kind:       Deployment 2
        name:       frontend

    1
    指定替代推荐器部署的名称。
    2
    指定您希望此 VPA 管理的现有工作负载对象的名称。

2.6.4. 使用 Vertical Pod Autoscaler Operator

您可以通过创建 VPA 自定义资源(CR)来使用 Vertical Pod Autoscaler Operator(VPA)。CR 指明应分析哪些 pod,并决定 VPA 应该对这些 pod 执行的操作。

先决条件

  • 要自动扩展的工作负载对象必须存在。
  • 如果要使用替代的推荐器,则必须存在包括那个推进器的部署。

流程

为特定工作负载对象创建 VPA CR:

  1. 切换到您要缩放的工作负载对象所在的项目。

    1. 创建一个 VPA CR YAML 文件:

      apiVersion: autoscaling.k8s.io/v1
      kind: VerticalPodAutoscaler
      metadata:
        name: vpa-recommender
      spec:
        targetRef:
          apiVersion: "apps/v1"
          kind:       Deployment 1
          name:       frontend 2
        updatePolicy:
          updateMode: "Auto" 3
        resourcePolicy: 4
          containerPolicies:
          - containerName: my-opt-sidecar
            mode: "Off"
        recommenders: 5
          - name: my-recommender
      1
      指定您需要这个 VPA 管理的工作负载对象类型: DeploymentStatefulSetJobDaemonSetReplicaSetReplicationController
      2
      指定您希望此 VPA 管理的现有工作负载对象的名称。
      3
      指定 VPA 模式:
      • auto 会在与控制器关联的 pod 上自动应用推荐的资源。VPA 会终止现有的 pod,并使用推荐的资源限制和请求创建新 pod。
      • recreate 会在与工作负载对象关联的 pod 上自动应用推荐的资源。VPA 会终止现有的 pod,并使用推荐的资源限制和请求创建新 pod。recreate 模式应该很少使用,只有在需要确保每当资源请求改变时 pod 就需要重启时才使用。
      • Initial 在创建与工作负载对象关联的 pod 时自动应用推荐的资源。VPA 会学习新的资源建议,但不会更新 pod。
      • off 仅为与工作负载对象关联的 pod 生成资源建议。VPA 不会更新 pod,它只会学习新的资源建议,且不会将建议应用到新 pod。
      4
      可选。指定不需要受 VPA 影响的容器,将模式设置为 Off
      5
      可选。指定替代的推荐器。
    2. 创建 VPA CR:

      $ oc create -f <file-name>.yaml

      在一段短暂的时间后,VPA 会了解与工作负载对象关联的 pod 中容器的资源使用情况。

      您可以使用以下命令查看 VPA 建议:

      $ oc get vpa <vpa-name> --output yaml

      输出显示 CPU 和内存请求的建议,如下所示:

      输出示例

      ...
      status:
      
      ...
      
        recommendation:
          containerRecommendations:
          - containerName: frontend
            lowerBound: 1
              cpu: 25m
              memory: 262144k
            target: 2
              cpu: 25m
              memory: 262144k
            uncappedTarget: 3
              cpu: 25m
              memory: 262144k
            upperBound: 4
              cpu: 262m
              memory: "274357142"
          - containerName: backend
            lowerBound:
              cpu: 12m
              memory: 131072k
            target:
              cpu: 12m
              memory: 131072k
            uncappedTarget:
              cpu: 12m
              memory: 131072k
            upperBound:
              cpu: 476m
              memory: "498558823"
      
      ...

      1
      lowerBound 是最低的推荐资源级别。
      2
      target是推荐的资源级别。
      3
      upperBound 是最高的推荐资源级别。
      4
      uncappedTarget 是最新资源建议。

2.6.5. 卸载 Vertical Pod Autoscaler Operator

您可以从 OpenShift Container Platform 集群中删除 Vertical Pod Autoscaler Operator(VPA)。卸载后,已由现有 VPA CR 修改的 pod 的资源请求不会改变。任何新 pod 都会根据工作负载对象中的定义获得资源,而不是之前由 VPA 提供的的建议。

注意

您可以使用 oc delete vpa <vpa-name> 命令删除特定的 VPA CR。在卸载垂直 pod 自动扩展时,同样的操作适用于资源请求。

删除 VPA Operator 后,建议您删除与 Operator 相关的其他组件,以避免潜在的问题。

先决条件

  • 已安装 Vertical Pod Autoscaler Operator。

流程

  1. 在 OpenShift Container Platform web 控制台中,点击 OperatorsInstalled Operators
  2. 切换到 openshift-vertical-pod-autoscaler 项目。
  3. 对于 VerticalPodAutoscaler Operator,点 Options 菜单 kebab 并选择 Uninstall Operator
  4. 可选: 要删除与 Operator 关联的所有操作对象,请在对话框中选择 Delete all operand instance for this operator 复选框。
  5. Uninstall
  6. 可选: 使用 OpenShift CLI 删除 VPA 组件:

    1. 删除 VPA 命名空间:

      $ oc delete namespace openshift-vertical-pod-autoscaler
    2. 删除 VPA 自定义资源定义 (CRD) 对象:

      $ oc delete crd verticalpodautoscalercheckpoints.autoscaling.k8s.io
      $ oc delete crd verticalpodautoscalercontrollers.autoscaling.openshift.io
      $ oc delete crd verticalpodautoscalers.autoscaling.k8s.io

      删除 CRD 会删除关联的角色、集群角色和角色绑定。

      注意

      此操作会从集群中移除,集群中的所有用户创建的 VPA CR。如果重新安装 VPA,您必须再次创建这些对象。

    3. 删除 VPA Operator:

      $ oc delete operator/vertical-pod-autoscaler.openshift-vertical-pod-autoscaler

2.7. 为 pod 提供敏感数据

有些应用程序需要密码和用户名等敏感信息,但您不希望开发人员持有这些信息。

作为管理员,您可以使用 Secret 对象在不以明文方式公开的前提下提供此类信息。

2.7.1. 了解 secret

Secret 对象类型提供了一种机制来保存敏感信息,如密码、OpenShift Container Platform 客户端配置文件和私有源存储库凭证等。secret 将敏感内容与 Pod 分离。您可以使用卷插件将 secret 信息挂载到容器中,系统也可以使用 secret 代表 Pod 执行操作。

主要属性包括:

  • Secret 数据可以独立于其定义来引用。
  • Secret 数据卷由临时文件工具 (tmpfs) 支持,永远不会停留在节点上。
  • secret 数据可以在命名空间内共享。

YAML Secret 对象定义

apiVersion: v1
kind: Secret
metadata:
  name: test-secret
  namespace: my-namespace
type: Opaque 1
data: 2
  username: dmFsdWUtMQ0K 3
  password: dmFsdWUtMg0KDQo=
stringData: 4
  hostname: myapp.mydomain.com 5

1
指示 secret 的键和值的结构。
2
data 字段中允许的键格式必须符合 Kubernetes 标识符术语表DNS_SUBDOMAIN 值的规范。
3
data 映射中键关联的值必须采用 base64 编码。
4
stringData 映射中的条目将转换为 base64,然后该条目将自动移动到 data 映射中。此字段是只写的;其值仅通过 data 字段返回。
5
stringData 映射中键关联的值由纯文本字符串组成。

您必须先创建 secret,然后创建依赖于此 secret 的 Pod。

在创建 secret 时:

  • 使用 secret 数据创建 secret 对象。
  • 更新 pod 的服务帐户以允许引用该 secret。
  • 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod。

2.7.1.1. secret 的类型

type 字段中的值指明 secret 的键名称和值的结构。此类型可用于强制使 secret 对象中存在用户名和密钥。如果您不想进行验证,请使用 opaque 类型,这也是默认类型。

指定以下一种类型来触发最小服务器端验证,确保 secret 数据中存在特定的键名称:

  • kubernetes.io/service-account-token。使用服务帐户令牌。
  • kubernetes.io/basic-auth。搭配基本身份验证使用。
  • kubernetes.io/ssh-auth。搭配 SSH 密钥身份验证使用。
  • kubernetes.io/tls。搭配 TLS 证书颁发机构使用。

如果您不想要验证,请指定 type: Opaque,即 secret 没有声明键名称或值需要符合任何约定。opaque secret 允许使用无结构 key:value 对,可以包含任意值。

注意

您可以指定其他任意类型,如 example.com/my-secret-type。这些类型不是在服务器端强制执行,而是表明 secret 的创建者意在符合该类型的键/值要求。

如需不同 secret 类型的示例,请参阅使用 secret 中的代码示例。

2.7.1.2. Secret 数据密钥

Secret 密钥必须在 DNS 子域中。

2.7.1.3. 关于自动生成的服务帐户令牌 secret

在 4.12 中,OpenShift Container Platform 基于上游社区的 Kubernetes ,它默认启用 LegacyServiceAccountTokenNoAutoGeneration 功能。因此,在创建新服务帐户(SA)时,服务帐户令牌 secret 不再自动生成。在以前的版本中,OpenShift Container Platform 会自动将服务帐户令牌添加到每个新 SA 的 secret 中。

但是,一些功能和工作负载需要服务帐户令牌 secret 与 Kubernetes API 服务器通信,例如,OpenShift Controller Manager。虽然这个要求将在以后的发行版本中改变,但它保留在 OpenShift Container Platform 4.12 中。因此,如果需要服务帐户令牌 secret,您必须手动使用 TokenRequest API 来请求绑定的服务帐户令牌或创建服务帐户令牌 secret。

升级到 4.12 后,现有服务帐户令牌 secret 不会被删除,并可以继续按预期工作。

注意

在 4.12 中,服务帐户令牌 secret 仍然会自动生成。OpenShift Container Platform 现在只创建一个服务帐户,而不是为每个服务帐户创建两个 secret。在以后的发行版本中,这个数字会进一步减少为零。请注意,dockercfg secret 仍然会被生成,在升级过程中不会删除任何 secret。

其它资源

2.7.2. 了解如何创建 secret

作为管理员,您必须先创建 secret,然后开发人员才能创建依赖于该 secret 的 pod。

在创建 secret 时:

  1. 创建包含您要保留 secret 的数据的 secret 对象。在以下部分中取消每个 secret 类型所需的特定数据。

    创建不透明 secret 的 YAML 对象示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: test-secret
    type: Opaque 1
    data: 2
      username: dmFsdWUtMQ0K
      password: dmFsdWUtMQ0KDQo=
    stringData: 3
      hostname: myapp.mydomain.com
      secret.properties: |
        property1=valueA
        property2=valueB

    1
    指定 secret 的类型。
    2
    指定编码的字符串和数据。
    3
    指定解码的字符串和数据。

    使用 datastringdata 字段,不能同时使用这两个字段。

  2. 更新 pod 的服务帐户以引用 secret:

    使用 secret 的服务帐户的 YAML

    apiVersion: v1
    kind: ServiceAccount
     ...
    secrets:
    - name: test-secret

  3. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod:

    pod 的 YAML 使用 secret 数据填充卷中的文件

    apiVersion: v1
    kind: Pod
    metadata:
      name: secret-example-pod
    spec:
      containers:
        - name: secret-test-container
          image: busybox
          command: [ "/bin/sh", "-c", "cat /etc/secret-volume/*" ]
          volumeMounts: 1
              - name: secret-volume
                mountPath: /etc/secret-volume 2
                readOnly: true 3
      volumes:
        - name: secret-volume
          secret:
            secretName: test-secret 4
      restartPolicy: Never

    1
    为每个需要 secret 的容器添加 volumeMounts 字段。
    2
    指定您希望显示 secret 的未使用目录名称。secret 数据映射中的每个密钥都将成为 mountPath 下的文件名。
    3
    设置为 true。如果为 true,这指示驱动程序提供只读卷。
    4
    指定 secret 的名称。

    pod 的 YAML 使用 secret 数据填充环境变量

    apiVersion: v1
    kind: Pod
    metadata:
      name: secret-example-pod
    spec:
      containers:
        - name: secret-test-container
          image: busybox
          command: [ "/bin/sh", "-c", "export" ]
          env:
            - name: TEST_SECRET_USERNAME_ENV_VAR
              valueFrom:
                secretKeyRef: 1
                  name: test-secret
                  key: username
      restartPolicy: Never

    1
    指定消耗 secret 密钥的环境变量。

    构建配置的 YAML 使用 secret 数据填充环境变量

    apiVersion: build.openshift.io/v1
    kind: BuildConfig
    metadata:
      name: secret-example-bc
    spec:
      strategy:
        sourceStrategy:
          env:
          - name: TEST_SECRET_USERNAME_ENV_VAR
            valueFrom:
              secretKeyRef: 1
                name: test-secret
                key: username

    1
    指定消耗 secret 密钥的环境变量。

2.7.2.1. Secret 创建限制

若要使用 secret,pod 需要引用该 secret。可以通过三种方式将 secret 用于 Pod:

  • 为容器产生环境变量。
  • 作为挂载到一个或多个容器上的卷中的文件。
  • 在拉取 Pod 的镜像时通过 kubelet 使用。

卷类型 secret 使用卷机制将数据作为文件写入到容器中。镜像拉取 secret 使用服务帐户,将 secret 自动注入到命名空间中的所有 pod。

当模板包含 secret 定义时,模板使用提供的 secret 的唯一方法是确保验证 secret 卷源通过验证,并且指定的对象引用实际指向 Secret 类型的对象。因此,secret 需要在依赖它的任何 Pod 之前创建。确保这一点的最有效方法是通过使用服务帐户自动注入。

Secret API 对象驻留在命名空间中。它们只能由同一命名空间中的 pod 引用。

每个 secret 的大小限制为 1MB。这是为了防止创建可能会耗尽 apiserver 和 kubelet 内存的大型 secret。不过,创建许多较小的 secret 也可能会耗尽内存。

2.7.2.2. 创建不透明 secret

作为管理员,您可以创建一个不透明 secret,它允许您存储包含任意值的无结构 key:value 对。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象。

    例如:

    apiVersion: v1
    kind: Secret
    metadata:
      name: mysecret
    type: Opaque 1
    data:
      username: dXNlci1uYW1l
      password: cGFzc3dvcmQ=
    1
    指定不透明 secret。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其它资源

2.7.2.3. 创建服务帐户令牌 secret

作为管理员,您可以创建一个服务帐户令牌 secret,该 secret 允许您将服务帐户令牌分发到必须通过 API 进行身份验证的应用程序。

注意

建议使用 TokenRequest API 获取绑定的服务帐户令牌,而不使用服务帐户令牌 secret。从 TokenRequest API 获取的令牌比存储在 secret 中的令牌更安全,因为它们具有绑定的生命周期,且不能被其他 API 客户端读取。

只有在无法使用 TokenRequest API 且在可读的 API 对象中存在非过期令牌时,才应创建服务帐户令牌 secret。

有关创建绑定服务帐户令牌的详情,请参考下面的其他参考资料部分。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象:

    secret 对象示例:

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-sa-sample
      annotations:
        kubernetes.io/service-account.name: "sa-name" 1
    type: kubernetes.io/service-account-token 2

    1
    指定一个现有服务帐户名称。如果您要同时创建 ServiceAccountSecret 对象,请首先创建 ServiceAccount 对象。
    2
    指定服务帐户令牌 secret。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其它资源

2.7.2.4. 创建基本身份验证 secret

作为管理员,您可以创建一个基本身份验证 secret,该 secret 允许您存储基本身份验证所需的凭证。在使用此 secret 类型时,Secret 对象的 data 参数必须包含以下密钥,采用 base64 格式编码:

  • 用户名 :用于身份验证的用户名
  • 密码 :用于身份验证的密码或令牌
注意

您可以使用 stringData 参数使用明文内容。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象:

    secret 对象示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-basic-auth
    type: kubernetes.io/basic-auth 1
    data:
    stringData: 2
      username: admin
      password: t0p-Secret

    1
    指定基本身份验证 secret。
    2
    指定要使用的基本身份验证值。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其它资源

2.7.2.5. 创建 SSH 身份验证 secret

作为管理员,您可以创建一个 SSH 验证 secret,该 secret 允许您存储用于 SSH 验证的数据。在使用此 secret 类型时,Secret 对象的 data 参数必须包含要使用的 SSH 凭证。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象:

    secret 对象示例:

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-ssh-auth
    type: kubernetes.io/ssh-auth 1
    data:
      ssh-privatekey: | 2
              MIIEpQIBAAKCAQEAulqb/Y ...

    1
    指定 SSH 身份验证 secret。
    2
    指定 SSH 密钥/值对,作为要使用的 SSH 凭据。
  2. 使用以下命令来创建 Secret 对象:

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其它资源

2.7.2.6. 创建 Docker 配置 secret

作为管理员,您可以创建一个 Docker 配置 secret,该 secret 允许您存储用于访问容器镜像 registry 的凭证。

  • kubernetes.io/dockercfg。使用此机密类型存储本地 Docker 配置文件。secret 对象的 data 参数必须包含以 base64 格式编码的 .dockercfg 文件的内容。
  • kubernetes.io/dockerconfigjson。使用此机密类型存储本地 Docker 配置 JSON 文件。secret 对象的 data 参数必须包含以 base64 格式编码的 .docker/config.json 文件的内容。

流程

  1. 在控制平面节点上的 YAML 文件中创建 Secret 对象。

    Docker 配置 secret 对象示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-docker-cfg
      namespace: my-project
    type: kubernetes.io/dockerconfig 1
    data:
      .dockerconfig:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2

    1
    指定该 secret 使用 Docker 配置文件。
    2
    base64 编码的 Docker 配置文件

    Docker 配置 JSON secret 对象示例

    apiVersion: v1
    kind: Secret
    metadata:
      name: secret-docker-json
      namespace: my-project
    type: kubernetes.io/dockerconfig 1
    data:
      .dockerconfigjson:bm5ubm5ubm5ubm5ubm5ubm5ubm5ubmdnZ2dnZ2dnZ2dnZ2dnZ2dnZ2cgYXV0aCBrZXlzCg== 2

    1
    指定该 secret 使用 Docker 配置 JSONfile。
    2
    base64 编码的 Docker 配置 JSON 文件
  2. 使用以下命令来创建 Secret 对象

    $ oc create -f <filename>.yaml
  3. 在 pod 中使用该 secret:

    1. 更新 pod 的服务帐户以引用 secret,如 "Understanding how to create secrets" 部分所示。
    2. 创建以环境变量或文件(使用 secret 卷)形式消耗 secret 的 pod,如"创建 secret"部分所示。

其它资源

2.7.3. 了解如何更新 secret

修改 secret 值时,值(由已在运行的 pod 使用)不会动态更改。若要更改 secret,您必须删除原始 pod 并创建一个新 pod(可能具有相同的 PodSpec)。

更新 secret 遵循与部署新容器镜像相同的工作流程。您可以使用 kubectl rolling-update 命令。

secret 中的 resourceVersion 值不在引用时指定。因此,如果在 pod 启动的同时更新 secret,则将不能定义用于 pod 的 secret 版本。

注意

目前,无法检查 Pod 创建时使用的 secret 对象的资源版本。按照计划 Pod 将报告此信息,以便控制器可以重启使用旧 resourceVersion 的 Pod。在此期间,请勿更新现有 secret 的数据,而应创建具有不同名称的新数据。

2.7.4. 创建和使用 secret

作为管理员,您可以创建一个服务帐户令牌 secret。这可让您将服务帐户令牌分发到必须通过 API 进行身份验证的应用程序。

流程

  1. 运行以下命令,在命名空间中创建服务帐户:

    $ oc create sa <service_account_name> -n <your_namespace>
  2. 将以下 YAML 示例保存到名为 service-account-token-secret.yaml 的文件中。这个示例包括可用于生成服务帐户令牌的 Secret 对象配置:

    apiVersion: v1
    kind: Secret
    metadata:
      name: <secret_name> 1
      annotations:
        kubernetes.io/service-account.name: "sa-name" 2
    type: kubernetes.io/service-account-token 3
    1
    <secret_name> 替换为服务帐户令牌 secret 的名称。
    2
    指定一个现有服务帐户名称。如果您要同时创建 ServiceAccountSecret 对象,请首先创建 ServiceAccount 对象。
    3
    指定服务帐户令牌 secret 类型。
  3. 通过应用文件来生成服务帐户令牌:

    $ oc apply -f service-account-token-secret.yaml
  4. 运行以下命令,从 secret 获取服务帐户令牌:

    $ oc get secret <sa_token_secret> -o jsonpath='{.data.token}' | base64 --decode) 1

    输出示例

    ayJhbGciOiJSUzI1NiIsImtpZCI6IklOb2dtck1qZ3hCSWpoNnh5YnZhSE9QMkk3YnRZMVZoclFfQTZfRFp1YlUifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImJ1aWxkZXItdG9rZW4tdHZrbnIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiYnVpbGRlciIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjNmZGU2MGZmLTA1NGYtNDkyZi04YzhjLTNlZjE0NDk3MmFmNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmJ1aWxkZXIifQ.OmqFTDuMHC_lYvvEUrjr1x453hlEEHYcxS9VKSzmRkP1SiVZWPNPkTWlfNRp6bIUZD3U6aN3N7dMSN0eI5hu36xPgpKTdvuckKLTCnelMx6cxOdAbrcw1mCmOClNscwjS1KO1kzMtYnnq8rXHiMJELsNlhnRyyIXRTtNBsy4t64T3283s3SLsancyx0gy0ujx-Ch3uKAKdZi5iT-I8jnnQ-ds5THDs2h65RJhgglQEmSxpHrLGZFmyHAQI-_SjvmHZPXEc482x3SkaQHNLqpmrpJorNqh1M8ZHKzlujhZgVooMvJmWPXTb2vnvi3DGn2XI-hZxl1yD2yGH1RBpYUHA

    1
    将 <sa_token_secret> 替换为服务帐户令牌 secret 的名称。
  5. 使用您的服务帐户令牌与集群的 API 进行身份验证:

    $ curl -X GET <openshift_cluster_api> --header "Authorization: Bearer <token>" 1 2
    1
    <openshift_cluster_api> 替换为 OpenShift 集群 API。
    2
    <token> 替换为上一命令输出的服务帐户令牌。

2.7.5. 关于将签名证书与 secret 搭配使用

若要与服务进行安全通信,您可以配置 OpenShift Container Platform,以生成一个签名的服务用证书/密钥对,再添加到项目中的 secret 里。

服务用证书 secret 旨在支持需要开箱即用证书的复杂中间件应用程序。它的设置与管理员工具为节点和 master 生成的服务器证书相同。

为服务用证书 secret 配置的服务 Pod 规格。

apiVersion: v1
kind: Service
metadata:
  name: registry
  annotations:
    service.beta.openshift.io/serving-cert-secret-name: registry-cert1
# ...

1
指定证书的名称

其他 pod 可以信任集群创建的证书(仅对内部 DNS 名称进行签名),方法是使用 pod 中自动挂载的 /var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt 文件中的 CA 捆绑。

此功能的签名算法是 x509.SHA256WithRSA。要手动轮转,请删除生成的 secret。这会创建新的证书。

2.7.5.1. 生成签名证书以便与 secret 搭配使用

要将签名的服务用证书/密钥对用于 pod,请创建或编辑服务以添加到 service.beta.openshift.io/serving-cert-secret-name 注解,然后将 secret 添加到该 pod。

流程

创建服务用证书 secret

  1. 编辑服务的 Pod spec。
  2. 使用您要用于 secret 的名称,添加 service.beta.openshift.io/serving-cert-secret-name 注解。

    kind: Service
    apiVersion: v1
    metadata:
      name: my-service
      annotations:
          service.beta.openshift.io/serving-cert-secret-name: my-cert 1
    spec:
      selector:
        app: MyApp
      ports:
      - protocol: TCP
        port: 80
        targetPort: 9376

    证书和密钥采用 PEM 格式,分别存储在 tls.crttls.key 中。

  3. 创建服务:

    $ oc create -f <file-name>.yaml
  4. 查看 secret 以确保已成功创建:

    1. 查看所有 secret 列表:

      $ oc get secrets

      输出示例

      NAME                     TYPE                                  DATA      AGE
      my-cert                  kubernetes.io/tls                     2         9m

    2. 查看您的 secret 详情:

      $ oc describe secret my-cert

      输出示例

      Name:         my-cert
      Namespace:    openshift-console
      Labels:       <none>
      Annotations:  service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z
                    service.beta.openshift.io/originating-service-name: my-service
                    service.beta.openshift.io/originating-service-uid: 640f0ec3-afc2-4380-bf31-a8c784846a11
                    service.beta.openshift.io/expiry: 2023-03-08T23:22:40Z
      
      Type:  kubernetes.io/tls
      
      Data
      ====
      tls.key:  1679 bytes
      tls.crt:  2595 bytes

  5. 编辑与该 secret 搭配的 Pod spec。

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-service-pod
    spec:
      containers:
      - name: mypod
        image: redis
        volumeMounts:
        - name: foo
          mountPath: "/etc/foo"
      volumes:
      - name: foo
        secret:
          secretName: my-cert
          items:
          - key: username
            path: my-group/my-username
            mode: 511

    当它可用时,您的 Pod 就可运行。该证书对内部服务 DNS 名称 <service.name>.<service.namespace>.svc 有效。

    证书/密钥对在接近到期时自动替换。在 secret 的 service.beta.openshift.io/expiry 注解中查看过期日期,其格式为 RFC3339。

    注意

    在大多数情形中,服务 DNS 名称 <service.name>.<service.namespace>.svc 不可从外部路由。<service.name>.<service.namespace>.svc 的主要用途是集群内或服务内通信,也用于重新加密路由。

2.7.6. secret 故障排除

如果服务证书生成失败并显示以下信息( 服务的 service.beta.openshift.io/serving-cert-generation-error 注解包含):

secret/ssl-key references serviceUID 62ad25ca-d703-11e6-9d6f-0e9c0057b608, which does not match 77b6dd80-d716-11e6-9d6f-0e9c0057b60

生成证书的服务不再存在,或者具有不同的 serviceUID 。您必须删除旧 secret 并清除服务上的以下注解 service.beta.openshift.io/serving-cert-generation-error, service.beta.openshift.io/serving-cert-generation-error-num 以强制重新生成证书:

  1. 删除 secret:

    $ oc delete secret <secret_name>
  2. 清除注解:

    $ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-
    $ oc annotate service <service_name> service.beta.openshift.io/serving-cert-generation-error-num-
注意

在用于移除注解的命令中,要移除的注解后面有一个 -

2.8. 创建和使用配置映射

以下部分定义配置映射以及如何创建和使用它们。

2.8.1. 了解配置映射

许多应用程序需要使用配置文件、命令行参数和环境变量的某些组合来进行配置。在 OpenShift Container Platform 中,这些配置工件与镜像内容分离,以便使容器化应用程序可以移植。

ConfigMap 对象提供了将容器注入到配置数据的机制,同时保持容器与 OpenShift Container Platform 无关。配置映射可用于存储细粒度信息(如个别属性)或粗粒度信息(如完整配置文件或 JSON blob)。

ConfigMap API 对象包含配置数据的键值对,这些数据可在 Pod 中消耗或用于存储控制器等系统组件的配置数据。例如:

ConfigMap 对象定义

kind: ConfigMap
apiVersion: v1
metadata:
  creationTimestamp: 2016-02-18T19:14:38Z
  name: example-config
  namespace: default
data: 1
  example.property.1: hello
  example.property.2: world
  example.property.file: |-
    property.1=value-1
    property.2=value-2
    property.3=value-3
binaryData:
  bar: L3Jvb3QvMTAw 2

1 1
包含配置数据。
2
指向含有非 UTF8 数据的文件,如二进制 Java 密钥存储文件。以 Base64 格式输入文件数据。
注意

从二进制文件(如镜像)创建配置映射时,您可以使用 binaryData 字段。

可以在 Pod 中以各种方式消耗配置数据。配置映射可用于:

  • 在容器中填充环境变量值
  • 设置容器中的命令行参数
  • 填充卷中的配置文件

用户和系统组件可以在配置映射中存储配置数据。

配置映射与 secret 类似,但设计为能更加便捷地支持与不含敏感信息的字符串配合。

配置映射限制

在 pod 中可以消耗它的内容前,必须创建配置映射。

可以编写控制器来容许缺少的配置数据。根据具体情况使用配置映射来参考各个组件。

ConfigMap 对象驻留在一个项目中。

它们只能被同一项目中的 pod 引用。

Kubelet 只支持为它从 API 服务器获取的 pod 使用配置映射。

这包括使用 CLI 创建或间接从复制控制器创建的 pod。它不包括通过 OpenShift Container Platform 节点的 --manifest-url 标记、--config 标记,或通过 REST API 创建的 pod,因为这些不是创建 pod 的通用方法。

2.8.2. 在 OpenShift Container Platform Web 控制台中创建配置映射

您可以在 OpenShift Container Platform Web 控制台中创建配置映射。

流程

  • 以集群管理员身份创建配置映射:

    1. 在 Administrator 视角中,选择 WorkloadsConfig Maps
    2. 在该页面右上方选择 Create Config Map
    3. 输入配置映射的内容。
    4. 选择 Create
  • 以开发者身份创建配置映射:

    1. 在 Developer 视角中,选择 Config Maps
    2. 在该页面右上方选择 Create Config Map
    3. 输入配置映射的内容。
    4. 选择 Create

2.8.3. 使用 CLI 创建配置映射

您可以使用以下命令从目录、特定文件或文字值创建配置映射。

流程

  • 创建配置映射:

    $ oc create configmap <configmap_name> [options]

2.8.3.1. 从目录创建配置映射

您可以从目录中创建配置映射。这个方法允许您使用目录中的多个文件来创建配置映射。

流程

以下示例流程概述了如何从目录中创建配置映射。

  1. 从包含一些已包含您要填充配置映射的数据的文件目录开始:

    $ ls example-files

    输出示例

    game.properties
    ui.properties

    $ cat example-files/game.properties

    输出示例

    enemies=aliens
    lives=3
    enemies.cheat=true
    enemies.cheat.level=noGoodRotten
    secret.code.passphrase=UUDDLRLRBABAS
    secret.code.allowed=true
    secret.code.lives=30

    $ cat example-files/ui.properties

    输出示例

    color.good=purple
    color.bad=yellow
    allow.textmode=true
    how.nice.to.look=fairlyNice

  2. 输入以下命令,创建包含此目录中每个文件内容的配置映射:

    $ oc create configmap game-config \
        --from-file=example-files/

    --from-file 选项指向某个目录时,该目录中的每个文件都直接用于在配置映射中填充密钥,其中键的名称是文件名称,键的值是文件的内容。

    例如,上一命令会创建以下配置映射:

    $ oc describe configmaps game-config

    输出示例

    Name:           game-config
    Namespace:      default
    Labels:         <none>
    Annotations:    <none>
    
    Data
    
    game.properties:        158 bytes
    ui.properties:          83 bytes

    您可以看到,映射中的两个键都是从命令中指定的目录中的文件名创建的。因为这些键的内容可能较大,所以 oc describe 的输出只会显示键的名称及其大小。

  3. 使用带有 -o 选项的 oc get 命令以查看键的值:

    $ oc get configmaps game-config -o yaml

    输出示例

    apiVersion: v1
    data:
      game.properties: |-
        enemies=aliens
        lives=3
        enemies.cheat=true
        enemies.cheat.level=noGoodRotten
        secret.code.passphrase=UUDDLRLRBABAS
        secret.code.allowed=true
        secret.code.lives=30
      ui.properties: |
        color.good=purple
        color.bad=yellow
        allow.textmode=true
        how.nice.to.look=fairlyNice
    kind: ConfigMap
    metadata:
      creationTimestamp: 2016-02-18T18:34:05Z
      name: game-config
      namespace: default
      resourceVersion: "407"
      selflink: /api/v1/namespaces/default/configmaps/game-config
      uid: 30944725-d66e-11e5-8cd0-68f728db1985

2.8.3.2. 从文件创建配置映射

您可以从文件创建配置映射。

流程

以下示例流程概述了如何从文件创建配置映射。

注意

如果从文件创建一个配置映射,您可以在不会破坏非 UTF8 数据的项中包含非 UTF8 的数据。OpenShift Container Platform 检测到二进制文件,并将该文件编码为 MIME。在服务器上,MIME 有效负载被解码并存储而不会损坏数据。

您可以多次将 --from-file 选项传递给 CLI。以下示例生成与从目录创建示例相同的结果。

  1. 通过指定特定文件来创建配置映射:

    $ oc create configmap game-config-2 \
        --from-file=example-files/game.properties \
        --from-file=example-files/ui.properties
  2. 验证结果:

    $ oc get configmaps game-config-2 -o yaml

    输出示例

    apiVersion: v1
    data:
      game.properties: |-
        enemies=aliens
        lives=3
        enemies.cheat=true
        enemies.cheat.level=noGoodRotten
        secret.code.passphrase=UUDDLRLRBABAS
        secret.code.allowed=true
        secret.code.lives=30
      ui.properties: |
        color.good=purple
        color.bad=yellow
        allow.textmode=true
        how.nice.to.look=fairlyNice
    kind: ConfigMap
    metadata:
      creationTimestamp: 2016-02-18T18:52:05Z
      name: game-config-2
      namespace: default
      resourceVersion: "516"
      selflink: /api/v1/namespaces/default/configmaps/game-config-2
      uid: b4952dc3-d670-11e5-8cd0-68f728db1985

您可以为从文件中导入的内容在配置映射中指定要设置的键。这可以通过向 --from-file 选项传递 key=value 表达式来设置。例如:

  1. 通过指定键值对来创建配置映射:

    $ oc create configmap game-config-3 \
        --from-file=game-special-key=example-files/game.properties
  2. 验证结果:

    $ oc get configmaps game-config-3 -o yaml

    输出示例

    apiVersion: v1
    data:
      game-special-key: |- 1
        enemies=aliens
        lives=3
        enemies.cheat=true
        enemies.cheat.level=noGoodRotten
        secret.code.passphrase=UUDDLRLRBABAS
        secret.code.allowed=true
        secret.code.lives=30
    kind: ConfigMap
    metadata:
      creationTimestamp: 2016-02-18T18:54:22Z
      name: game-config-3
      namespace: default
      resourceVersion: "530"
      selflink: /api/v1/namespaces/default/configmaps/game-config-3
      uid: 05f8da22-d671-11e5-8cd0-68f728db1985

    1
    这是您在前面的步骤中设置的密钥。

2.8.3.3. 从字面值创建配置映射

您可以为配置映射提供字面值。

流程

--from-literal 选项使用 key=value 语法,允许直接在命令行中提供字面值。

  1. 通过指定字面值来创建配置映射:

    $ oc create configmap special-config \
        --from-literal=special.how=very \
        --from-literal=special.type=charm
  2. 验证结果:

    $ oc get configmaps special-config -o yaml

    输出示例

    apiVersion: v1
    data:
      special.how: very
      special.type: charm
    kind: ConfigMap
    metadata:
      creationTimestamp: 2016-02-18T19:14:38Z
      name: special-config
      namespace: default
      resourceVersion: "651"
      selflink: /api/v1/namespaces/default/configmaps/special-config
      uid: dadce046-d673-11e5-8cd0-68f728db1985

2.8.4. 用例: 在 pod 中使用配置映射

以下小节描述了在 pod 中消耗 ConfigMap 对象时的一些用例。

2.8.4.1. 使用配置映射在容器中填充环境变量

配置映射可用于在容器中填充各个环境变量或从构成有效环境变量名称的所有键填充容器中的环境变量。

例如,请考虑以下配置映射:

有两个环境变量的 ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config 1
  namespace: default 2
data:
  special.how: very 3
  special.type: charm 4

1
配置映射的名称。
2
配置映射所在的项目。配置映射只能由同一项目中的 pod 引用。
3 4
要注入的环境变量。

带有一个环境变量的ConfigMap

apiVersion: v1
kind: ConfigMap
metadata:
  name: env-config 1
  namespace: default
data:
  log_level: INFO 2

1
配置映射的名称。
2
要注入的环境变量。

流程

  • 您可以使用 configMapKeyRef 部分在 pod 中使用此 ConfigMap 的键。

    配置为注入特定环境变量的 Pod 规格示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox
          command: [ "/bin/sh", "-c", "env" ]
          env: 1
            - name: SPECIAL_LEVEL_KEY 2
              valueFrom:
                configMapKeyRef:
                  name: special-config 3
                  key: special.how 4
            - name: SPECIAL_TYPE_KEY
              valueFrom:
                configMapKeyRef:
                  name: special-config 5
                  key: special.type 6
                  optional: true 7
          envFrom: 8
            - configMapRef:
                name: env-config 9
      restartPolicy: Never

    1
    ConfigMap 中拉取指定的环境变量的小节。
    2
    要将键值注入到的 pod 环境变量的名称。
    3 5
    要从中拉取特定环境变量的 ConfigMap 名称。
    4 6
    要从 ConfigMap 中拉取的环境变量。
    7
    使环境变量成为可选。作为可选项,即使指定的 ConfigMap 和键不存在,也会启动 pod。
    8
    ConfigMap 中拉取所有环境变量的小节。
    9
    要从中拉取所有环境变量的 ConfigMap 名称。

    当此 pod 运行时,pod 日志包括以下输出:

    SPECIAL_LEVEL_KEY=very
    log_level=INFO
注意

示例输出中没有列出 SPECIAL_TYPE_KEY=charm,因为设置了 optional: true

2.8.4.2. 使用配置映射为容器命令设置命令行参数

配置映射也可用于设置容器中的命令或参数的值。这可以通过 Kubernetes 替换语法 $(VAR_NAME) 来实现。考虑以下配置映射:

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm

流程

  • 要将值注入容器中的命令中,您必须使用您要用作环境变量的键,如环境变量用例中的 ConfigMap 中一样。然后,您可以使用 $(VAR_NAME) 语法在容器的命令中引用它们。

    配置为注入特定环境变量的 Pod 规格示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox
          command: [ "/bin/sh", "-c", "echo $(SPECIAL_LEVEL_KEY) $(SPECIAL_TYPE_KEY)" ] 1
          env:
            - name: SPECIAL_LEVEL_KEY
              valueFrom:
                configMapKeyRef:
                  name: special-config
                  key: special.how
            - name: SPECIAL_TYPE_KEY
              valueFrom:
                configMapKeyRef:
                  name: special-config
                  key: special.type
      restartPolicy: Never

    1
    使用您要用作环境变量的键将值注入到容器中的命令中。

    当此 pod 运行时,test-container 容器中运行的 echo 命令的输出如下:

    very charm

2.8.4.3. 使用配置映射将内容注入卷

您可以使用配置映射将内容注入卷。

ConfigMap 自定义资源(CR)示例

apiVersion: v1
kind: ConfigMap
metadata:
  name: special-config
  namespace: default
data:
  special.how: very
  special.type: charm

流程

您可以使用配置映射将内容注入卷中有两个不同的选项。

  • 使用配置映射将内容注入卷的最基本方法是在卷中填充键为文件名称的文件,文件的内容是键值:

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox
          command: [ "/bin/sh", "cat", "/etc/config/special.how" ]
          volumeMounts:
          - name: config-volume
            mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: special-config 1
      restartPolicy: Never
    1
    包含密钥的文件。

    当这个 pod 运行时,cat 命令的输出将是:

    very
  • 您还可以控制投射配置映射键的卷中的路径:

    apiVersion: v1
    kind: Pod
    metadata:
      name: dapi-test-pod
    spec:
      containers:
        - name: test-container
          image: gcr.io/google_containers/busybox
          command: [ "/bin/sh", "cat", "/etc/config/path/to/special-key" ]
          volumeMounts:
          - name: config-volume
            mountPath: /etc/config
      volumes:
        - name: config-volume
          configMap:
            name: special-config
            items:
            - key: special.how
              path: path/to/special-key 1
      restartPolicy: Never
    1
    配置映射键的路径。

    当这个 pod 运行时,cat 命令的输出将是:

    very

2.9. 使用设备插件来利用 pod 访问外部资源

借助设备插件,您无需编写自定义代码,就能在 OpenShift Container Platform pod 中使用特定的设备类型,如 GPU、InfiniBand 或其他需要供应商专用初始化和设置的类似计算资源。

2.9.1. 了解设备插件

设备插件提供一致并可移植的解决方案,以便跨集群消耗硬件设备。设备插件通过一种扩展机制为这些设备提供支持,从而使这些设备可供容器使用,提供这些设备的健康检查,并安全地共享它们。

重要

OpenShift Container Platform 支持设备插件 API,但设备插件容器由各个供应商提供支持。

设备插件是在节点(kubelet 的外部)上运行的 gRPC 服务,负责管理特定的硬件资源。任何设备插件都必须支持以下远程过程调用 (RPC):

service DevicePlugin {
      // GetDevicePluginOptions returns options to be communicated with Device
      // Manager
      rpc GetDevicePluginOptions(Empty) returns (DevicePluginOptions) {}

      // ListAndWatch returns a stream of List of Devices
      // Whenever a Device state change or a Device disappears, ListAndWatch
      // returns the new list
      rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse) {}

      // Allocate is called during container creation so that the Device
      // Plug-in can run device specific operations and instruct Kubelet
      // of the steps to make the Device available in the container
      rpc Allocate(AllocateRequest) returns (AllocateResponse) {}

      // PreStartcontainer is called, if indicated by Device Plug-in during
      // registration phase, before each container start. Device plug-in
      // can run device specific operations such as reseting the device
      // before making devices available to the container
      rpc PreStartcontainer(PreStartcontainerRequest) returns (PreStartcontainerResponse) {}
}
设备插件示例
注意

对于简单设备插件参考实现,设备管理器代码中有一个 stub 设备插件: vendor/k8s.io/kubernetes/pkg/kubelet/cm/deviceplugin/device_plugin_stub.go

2.9.1.1. 设备插件部署方法

  • 守护进程集是设备插件部署的推荐方法。
  • 在启动时,设备插件会尝试在节点上 /var/lib/kubelet/device-plugin/ 创建一个 UNIX 域套接字,以便服务来自于设备管理器的 RPC。
  • 由于设备插件必须管理硬件资源、主机文件系统的访问权以及套接字创建,它们必须在一个特权安全上下文中运行。
  • 各种设备插件实现中提供了有关部署步骤的更多细节。

2.9.2. 了解设备管理器

设备管理器提供了一种机制,可借助称为“设备插件”的插件公告专用节点硬件资源。

您可以公告专用的硬件,而不必修改任何上游代码。

重要

OpenShift Container Platform 支持设备插件 API,但设备插件容器由各个供应商提供支持。

设备管理器将设备公告为外部资源。用户 pod 可以利用相同的限制/请求机制来使用设备管理器公告的设备,这一机制也用于请求任何其他扩展资源

在启动时,设备插件会在 /var/lib/kubelet/device-plugins/kubelet.sock 上调用 Register 将自身注册到设备管理器,并启动位于 / var/lib/kubelet/device-plugins/<plugin>.sock 的 gRPC 服务,以服务设备管理器请求。

在处理新的注册请求时,设备管理器会在设备插件服务中调用 ListAndWatch 远程过程调用 (RPC)。作为响应,设备管理器通过 gRPC 流从插件中获取设备对象的列表。设备管理器对流进行持续监控,以确认插件有没有新的更新。在插件一端,插件也会使流保持开放;只要任何设备的状态有所改变,就会通过相同的流传输连接将新设备列表发送到设备管理器。

在处理新的 pod 准入请求时,Kubelet 将请求的扩展资源传递给设备管理器以进行设备分配。设备管理器在其数据库中检查,以验证是否存在对应的插件。如果插件存在并且有可分配的设备及本地缓存,则在该特定设备插件上调用 Allocate RPC。

此外,设备插件也可以执行其他几个特定于设备的操作,如驱动程序安装、设备初始化和设备重置。这些功能视具体实现而异。

2.9.3. 启用设备管理器

启用设备管理器来实现设备插件,在不更改上游代码的前提下公告专用硬件。

设备管理器提供了一种机制,可借助称为“设备插件”的插件公告专用节点硬件资源。

  1. 输入以下命令为您要配置的节点类型获取与静态 MachineConfigPool CRD 关联的标签。执行以下步骤之一:

    1. 查看机器配置:

      # oc describe machineconfig <name>

      例如:

      # oc describe machineconfig 00-worker

      输出示例

      Name:         00-worker
      Namespace:
      Labels:       machineconfiguration.openshift.io/role=worker 1

      1
      设备管理器所需标签。

流程

  1. 为配置更改创建自定义资源 (CR)。

    设备管理器 CR 配置示例

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: devicemgr 1
    spec:
      machineConfigPoolSelector:
        matchLabels:
           machineconfiguration.openshift.io: devicemgr 2
      kubeletConfig:
        feature-gates:
          - DevicePlugins=true 3

    1
    为 CR 分配一个名称。
    2
    输入来自机器配置池的标签。
    3
    DevicePlugins 设为“true”。
  2. 创建设备管理器:

    $ oc create -f devicemgr.yaml

    输出示例

    kubeletconfig.machineconfiguration.openshift.io/devicemgr created

  3. 通过确认节点上已创建了 /var/lib/kubelet/device-plugins/kubelet.sock,确保已启用了设备管理器。这是设备管理器 gRPC 服务器在其上侦听新插件注册的 UNIX 域套接字。只有启用了设备管理器,才会在 Kubelet 启动时创建此 sock 文件。

2.10. 在 pod 调度决策中纳入 pod 优先级

您可以在集群中启用 pod 优先级与抢占功能。pod 优先级代表与其他 pod 相比此 pod 的重要性,并根据优先级进行队列处理。抢占(preemption)则允许集群驱除低优先级 pod 或与之争抢,从而在合适的节点上没有可用空间时能够调度优先级较高的 pod。pod 优先级也会影响 pod 的调度顺序以及节点上资源不足驱除顺序。

要使用优先级和抢占功能,您需要创建优先级类来定义 pod 的相对权重。然后,在 pod 规格中引用优先级类,以应用这个权重来进行调度。

2.10.1. 了解 pod 优先级

当您使用 pod 优先级与抢占功能时,调度程序会根据优先级来调度待处理 pod,而待处理 pod 会放在调度队列中优先级较低的其他待处理 pod 的前面。因此,如果达到调度要求,较高优先级的 pod 可能比低优先级的 pod 更早调度。如果 pod 无法调度,调度程序会继续调度其他较低优先级 pod。

2.10.1.1. Pod 优先级类

您可以为 pod 分配一个优先级类,它是一种非命名空间的对象,用于定义从名称到优先级整数值的映射。数值越大,优先级越高。

优先级类对象可以取小于或等于 1000000000(十亿)的 32 位整数值。对于不得被抢占或被驱除的关键 pod,请保留大于或等于 10 亿的数值。默认情况下,OpenShift Container Platform 有两个保留优先级类,用于需要保证调度的关键系统 pod。

$ oc get priorityclasses

输出示例

NAME                      VALUE        GLOBAL-DEFAULT   AGE
system-node-critical      2000001000   false            72m
system-cluster-critical   2000000000   false            72m
openshift-user-critical   1000000000   false            3d13h
cluster-logging           1000000      false            29s

  • system-node-critical - 此优先级类的值为 2000001000,用于所有不得从节点上驱除的 pod。具有此优先级类的 pod 示例有 sdn-ovssdn 等。许多关键组件默认包括 system-node-critical 优先级类,例如:

    • master-api
    • master-controller
    • master-etcd
    • sdn
    • sdn-ovs
    • sync
  • system-cluster-critical - 此优先级类的值是 2000000000(二十亿),用于对集群而言很重要的 pod。在某些情况下,具有此优先级类的 Pod 可以从节点中驱除。例如,配置了 system-node-critical 优先级类的 pod 可以拥有优先权。不过,此优先级类确实能够保证调度。具有此优先级类的 pod 示例有 fluentd 以及 descheduler 这样的附加组件等。许多关键组件默认包括 system-cluster-critical 优先级类,例如:

    • fluentd
    • metrics-server
    • descheduler
  • openshift-user-critical - 您可以使用带有重要 pod 的 priorityClassName 字段,这些 pod 无法绑定其资源消耗,且没有可预测的资源消耗行为。openshift-monitoringopenshift-user-workload-monitoring 命名空间下的 Prometheus Pod 使用 openshift-user-critical priorityClassName。监控工作负载使用 system-critical 作为其第一个 priorityClass,但在监控使用过量内存时造成问题,且无法驱除它们。因此,监控会丢弃优先级,为调度程序带来灵活性,并围绕移动繁重的工作负载来保持关键节点正常操作。
  • cluster-logging - 此优先级类供 Fluentd 用于确保 Fluentd pod 优先于其他应用调度到节点上。

2.10.1.2. Pod 优先级名称

拥有一个或多个优先级类后,您可以创建 pod,并在 Pod 规格中指定优先级类名称。优先准入控制器使用优先级类名称字段来填充优先级的整数值。如果没有找到给定名称的优先级类,pod 将被拒绝。

2.10.2. 了解 pod 抢占

当开发人员创建 pod 时,pod 会排入某一队列。如果开发人员为 pod 配置了 pod 优先级或抢占,调度程序会从队列中选取 pod,并尝试将 pod 调度到某个节点上。如果调度程序无法在满足 pod 的所有指定要求的适当节点上找到空间,则会为待处理 pod 触发抢占逻辑。

当调度程序在节点上抢占一个或多个 pod 时,较高优先级 Pod spec 的 nominatedNodeName 字段 将设为该节点的名称,nodename 字段也是如此。调度程序使用 nominatedNodeName 字段来跟踪为 pod 保留的资源,同时也向用户提供与集群中抢占相关的信息。

在调度程序抢占了某一较低优先级 pod 后,调度程序会尊重该 pod 的安全终止期限。如果在调度程序等待较低优先级 pod 终止过程中另一节点变为可用,调度程序会将较高优先级 pod 调度到该节点上。因此,Pod spec 的 nominatedNodeName 字段和 nodeName 字段可能会有所不同。

另外,如果调度程序在某一节点上抢占 pod 并正在等待终止,这时又有优先级比待处理 pod 高的 pod 需要调度,那么调度程序可以改为调度这个优先级更高的 pod。在这种情况下,调度程序会清除待处理 pod 的 nominatedNodeName,使该 pod 有资格调度到其他节点上。

抢占不一定从节点中移除所有较低优先级 pod。调度程序可以通过移除一部分较低优先级 pod 调度待处理 pod。

只有待处理 pod 能够调度到节点时,调度程序才会对这个节点考虑 pod 抢占。

2.10.2.1. 非抢占优先级类(技术预览)

抢占策略设置为 Never 的 Pod 会放置在较低优先级 pod 的调度队列中,但无法抢占其他 pod。等待调度的非抢占 pod 会保留在调度队列中,直到资源可用且可以调度。非抢占 pod 与其他 pod 一样,受调度程序后退避的影响。这意味着,如果调度程序尝试调度这些 pod,它们会以较低频率重试,允许在调度前调度其他优先级较低的 pod。

非抢占 pod 仍可被其他高优先级 pod 抢占。

2.10.2.2. Pod 抢占和其他调度程序设置

如果启用 pod 优先级与抢占功能,请考虑其他的调度程序设置:

pod 优先级和 pod 中断预算
pod 中断预算指定某一时间必须保持在线的副本的最小数量或百分比。如果您指定了 pod 中断预算,OpenShift Container Platform 会在抢占 pod 时尽力尊重这些预算。调度程序会尝试在不违反 pod 中断预算的前提下抢占 pod。如果找不到这样的 pod,则可能会无视 pod 中断预算要求而抢占较低优先级 pod。
pod 优先级和 pod 关联性
pod 关联性要求将新 pod 调度到与具有同样标签的其他 pod 相同的节点上。

如果待处理 pod 与节点上的一个或多个低优先级 pod 具有 pod 间关联性,调度程序就不能在不违反关联要求的前提下抢占较低优先级 pod。这时,调度程序会寻找其他节点来调度待处理 pod。但是,不能保证调度程序能够找到合适的节点,因此可能无法调度待处理 pod。

要防止这种情况,请仔细配置优先级相同的 pod 的 pod 关联性。

2.10.2.3. 安全终止被抢占的 pod

在抢占 pod 时,调度程序会等待 pod 安全终止期限到期,使 pod 能够完成工作并退出。如果 pod 在到期后没有退出,调度程序会终止该 pod。此安全终止期限会在调度程序抢占该 pod 的时间和待处理 pod 调度到节点的时间之间造成一个时间差。

要尽量缩短这个时间差,可以为较低优先级 pod 配置较短的安全终止期限。

2.10.3. 配置优先级和抢占

您可以通过创建优先级类对象并使用 Pod spec 中的 priorityClassName 将 pod 与优先级关联,以应用 pod 优先级与抢占功能。

优先级类对象示例

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority 1
value: 1000000 2
preemptionPolicy: PreemptLowerPriority 3
globalDefault: false 4
description: "This priority class should be used for XYZ service pods only." 5

1
优先级类对象的名称。
2
对象的优先级值。
3
指定此优先级类是否被抢占或未抢占的可选字段。抢占策略默认为 PreemptLowerPriority,它允许该优先级类中的 pod 抢占较低优先级 pod。如果抢占策略设置为 Never,则该优先级类中的 pod 就不会被抢占。
4
此可选字段指定是否应该将这个优先级类用于 pod,而不指定优先级类名。此字段默认为 false。集群中只能存在一个 globalDefault 设为 true 的优先级类。如果没有 globalDefault:true 的优先级类,则无优先级类名称的 pod 的优先级为零。添加具有 globalDefault:true 的优先级类只会影响在添加优先级类后创建的 pod,不会更改现有 pod 的优先级。
5
此可选任意文本字符串用于描述开发人员应对哪些 pod 使用这个优先级类。

流程

配置集群以使用优先级与抢占功能:

  1. 创建一个或多个优先级类:

    1. 指定优先级的名称和值。
    2. (可选)指定优先级类的 globalDefault 字段和描述。
  2. 创建 Pod spec 或编辑现有的 pod 以包含优先级类的名称,如下所示:

    带有优先级类名称的 Pod 规格示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        env: test
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
      priorityClassName: high-priority 1

    1
    指定要用于此 pod 的优先级类。
  3. 创建 pod:

    $ oc create -f <file-name>.yaml

    您可以将优先级名称直接添加到 pod 配置或 pod 模板中。

2.11. 使用节点选择器将 pod 放置到特定节点

节点选择器指定一个键值对映射。使用节点中的自定义标签和 pod 中指定的选择器来定义规则。

若要使 pod 有资格在某一节点上运行,pod 必须具有指定为该节点上标签的键值对。

如果您在同一 pod 配置中同时使用节点关联性和节点选择器,请查看下方的重要注意事项。

2.11.1. 使用节点选择器控制 pod 放置

您可以使用节点上的 pod 和标签上的节点选择器来控制 pod 的调度位置。使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

要将节点选择器添加到现有 pod 中,将节点选择器添加到该 pod 的控制对象中,如 ReplicaSet 对象、DaemonSet 对象、StatefulSet 对象、Deployment 对象或 DeploymentConfig 对象。任何属于该控制对象的现有 pod 都会在具有匹配标签的节点上重新创建。如果要创建新 pod,可以将节点选择器直接添加到 Pod 规格中。

注意

您不能直接将节点选择器添加到现有调度的 pod 中。

先决条件

要将节点选择器添加到现有 pod 中,请确定该 pod 的控制对象。例如, router-default-66d5cf9464-m2g75 pod 由 router-default-66d5cf9464 副本集控制:

$ oc describe pod router-default-66d5cf9464-7pwkc

Name:               router-default-66d5cf9464-7pwkc
Namespace:          openshift-ingress

....

Controlled By:      ReplicaSet/router-default-66d5cf9464

Web 控制台在 pod YAML 的 ownerReferences 下列出控制对象:

  ownerReferences:
    - apiVersion: apps/v1
      kind: ReplicaSet
      name: router-default-66d5cf9464
      uid: d81dd094-da26-11e9-a48a-128e7edf0312
      controller: true
      blockOwnerDeletion: true

流程

  1. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 对象向由计算机器集管理的节点添加标签:

      1. 运行以下命令,将标签添加到 MachineSet 对象中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api

        例如:

        $ oc patch MachineSet abc612-msrtw-worker-us-east-1c  --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet 对象中:

        例如:

        $ oc edit MachineSet abc612-msrtw-worker-us-east-1c -n openshift-machine-api

        MachineSet 对象示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        
        ....
        
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node
        ....

    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

        $ oc label nodes <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ip-10-0-142-25.ec2.internal type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            type: "user-node"
            region: "east"
      2. 验证标签是否已添加到节点:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                          STATUS   ROLES    AGE   VERSION
        ip-10-0-142-25.ec2.internal   Ready    worker   17m   v1.25.0

  2. 将匹配的节点选择器添加到 pod:

    • 要将节点选择器添加到现有和未来的 pod,请向 pod 的控制对象添加节点选择器:

      带有标签的 ReplicaSet 对象示例

      kind: ReplicaSet
      
      ....
      
      spec:
      
      ....
      
        template:
          metadata:
            creationTimestamp: null
            labels:
              ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
              pod-template-hash: 66d5cf9464
          spec:
            nodeSelector:
              kubernetes.io/os: linux
              node-role.kubernetes.io/worker: ''
              type: user-node 1

      1
      添加节点选择器。
    • 要将节点选择器添加到一个特定的新 pod,直接将选择器添加到 Pod 对象中:

      使用节点选择器的 Pod 对象示例

      apiVersion: v1
      kind: Pod
      
      ....
      
      spec:
        nodeSelector:
          region: east
          type: user-node

      注意

      您不能直接将节点选择器添加到现有调度的 pod 中。

第 3 章 控制节点上的 pod 放置(调度)

3.1. 使用调度程序控制 pod 放置

Pod 调度是一个内部过程,决定新 pod 如何放置到集群内的节点上。

调度程度代码具有明确隔离,会监测创建的新 pod 并确定最适合托管它们的节点。然后,它会利用主 API 为 pod 创建 pod 至节点的绑定。

默认 pod 调度
OpenShift Container Platform 附带一个满足大多数用户需求的默认调度程序。默认调度程序使用内置和自定义工具来决定最适合 pod 的调度程序。
高级 pod 调度

如果您想要更多地控制新 pod 的放置位置,可以利用 OpenShift Container Platform 高级调度功能来配置 pod,从而使 pod 能够根据要求或偏好在特定的节点上运行,或者与特定的 pod 一起运行。

您可以使用以下调度功能来控制 pod 放置:

3.1.1. 关于默认调度程序

默认的 OpenShift Container Platform pod 调度程序负责确定新 pod 放置到集群中的节点上。它从 pod 读取数据,并查找最适合配置的配置集的节点。它完全独立存在,作为独立解决方案。它不会修改 pod;它会为将 pod 绑定到特定节点的 pod 创建绑定。

3.1.1.1. 了解默认调度

现有的通用调度程序是平台默认提供的调度程序引擎,它可通过三步操作来选择托管 pod 的节点:

过滤节点
根据指定的约束或要求过滤可用的节点。这可以通过使用名为 predicates, 或 filters 的过滤器函数列表在每个节点上运行来实现。
排列过滤后节点列表的优先顺序
这可以通过一系列 priority, 或 scoring 来实现,这些函数为其分配分数介于 0 到 10 之间,0 表示不适合,10 则表示最适合托管该 pod。调度程序配置还可以为每个评分功能使用简单的 权重 (正数值)。每个评分功能提供的节点分数乘以权重(大多数分数的默认权重为 1),然后将每个节点通过为所有分数提供的分数相加。管理员可以使用这个权重属性为某些分数赋予更高的重要性。
选择最适合的节点
节点按照分数排序,系统选择分数最高的节点来托管该 pod。如果多个节点的分数相同,则随机选择其中一个。

3.1.2. 调度程序用例

在 OpenShift Container Platform 中调度的一个重要用例是支持灵活的关联性和反关联性策略。

3.1.2.1. 基础架构拓扑级别

管理员可以通过在节点上指定标签,为基础架构(节点)定义多个拓扑级别。例如,region=r1zone=z1rack=s1

这些标签名称没有特别的含义,管理员可以自由为其基础架构级别命名,比如城市/楼宇/房间。另外,管理员可以为其基础架构拓扑定义任意数量的级别,通常三个级别比较适当(例如:regionszoneracks)。管理员可以在各个级别上以任何组合指定关联性和反关联性规则。

3.1.2.2. 关联性

管理员应能够配置调度程序,在任何一个甚至多个拓扑级别上指定关联性。特定级别上的关联性指示所有属于同一服务的 pod 调度到属于同一级别的节点。这会让管理员确保对等 pod 在地理上不会过于分散,以此处理应用程序对延迟的要求。如果同一关联性组中没有节点可用于托管 pod,则不调度该 pod。

如果您需要更好地控制 pod 的调度位置,请参阅使用节点关联性规则控制节点上的 pod 放置,以及使用关联性和反关联性规则相对于其他 pod 放置 pod

管理员可以利用这些高级调度功能,来指定 pod 可以调度到哪些节点,并且相对于其他 pod 来强制或拒绝调度。

3.1.2.3. 反关联性

管理员应能够配置调度程序,在任何一个甚至多个拓扑级别上指定反关联性。特定级别上的反关联性(或分散)指示属于同一服务的所有 pod 分散到属于该级别的不同节点上。这样可确保应用程序合理分布,以实现高可用性目的。调度程序尝试在所有适用的节点之间尽可能均匀地平衡服务 pod。

如果您需要更好地控制 pod 的调度位置,请参阅使用节点关联性规则控制节点上的 pod 放置,以及使用关联性和反关联性规则相对于其他 pod 放置 pod

管理员可以利用这些高级调度功能,来指定 pod 可以调度到哪些节点,并且相对于其他 pod 来强制或拒绝调度。

3.2. 使用调度程序配置集调度 pod

您可以将 OpenShift Container Platform 配置为使用调度配置集将 pod 调度到集群内的节点上。

3.2.1. 关于调度程序配置集

您可以指定一个调度程序配置集来控制 pod 如何调度到节点上。

可用的调度程序配置集如下:

LowNodeUtilization
此配置集尝试在节点间平均分配 pod,以获得每个节点的资源用量较低。这个配置集提供默认的调度程序行为。
HighNodeUtilization
此配置集会尝试将尽量多的 pod 放置到尽量少的节点。这样可最小化节点数,并且每个节点的资源使用率很高。
NoScoring
这是一个低延迟配置集,通过禁用所有分数(score)插件来实现最快的调度周期。这可能会为更快的调度决策提供更好的要求。

3.2.2. 配置调度程序配置集

您可以将调度程序配置为使用调度程序配置集。

先决条件

  • 使用具有 cluster-admin 角色的用户访问集群。

流程

  1. 编辑 Scheduler 对象:

    $ oc edit scheduler cluster
  2. 指定在 spec.profile 字段中使用的配置集:

    apiVersion: config.openshift.io/v1
    kind: Scheduler
    metadata:
      ...
      name: cluster
      resourceVersion: "601"
      selfLink: /apis/config.openshift.io/v1/schedulers/cluster
      uid: b351d6d0-d06f-4a99-a26b-87af62e79f59
    spec:
      mastersSchedulable: false
      profile: HighNodeUtilization 1
    1
    设置为 LowNodeUtilizationHighNodeUtilizationNoScoring
  3. 保存文件以使改变生效。

3.3. 使用关联性和反关联性规则相对于其他 pod 放置 pod

关联性是 pod 的一个属性,用于控制它们希望调度到的节点。反关联性是 pod 的一个属性,用于阻止 pod 调度到某个节点上。

在 OpenShift Container Platform 中,可以借助 pod 关联性pod 反关联性来根据其他 pod 上的键/值标签限制 pod 有资格调度到哪些节点。

3.3.1. 了解 pod 关联性

您可以借助 pod 关联性pod 反关联性来根据其他 pod 上的键/值标签限制 pod 有资格调度到哪些节点。

  • 如果新 pod 上的标签选择器与当前 pod 上的标签匹配,pod 关联性可以命令调度程序将新 pod 放置到与其他 pod 相同的节点上。
  • 如果新 pod 上的标签选择器与当前 pod 上的标签匹配,pod 反关联性可以阻止调度程序将新 pod 放置到与具有相同标签的 pod 相同的节点上。

例如,您可以使用关联性规则,在服务内或相对于其他服务中的 pod 来分散或聚拢 pod。如果特定服务的 pod 的性能已知会受到另一服务的 pod 影响,那么您可以利用反关联性规则,防止前一服务的 pod 调度到与后一服务的 pod 相同的节点上。或者,您可以将服务的 pod 分散到节点间、可用性区域或可用性集,以减少相关的故障。

pod 关联性规则有两种,即必要规则和偏好规则。

必须满足必要规则,pod 才能调度到节点上。偏好规则指定在满足规则时调度程序会尝试强制执行规则,但不保证一定能强制执行成功。

注意

根据 pod 优先级和抢占设置,调度程序可能无法在不违反关联性要求的前提下为 pod 找到适合的节点。若是如此,pod 可能不会被调度。

要防止这种情况,请仔细配置优先级相同的 pod 的 pod 关联性。

您可以通过 Pod 规格文件配置 pod 关联性/反关联性。您可以指定必要规则或偏好规则,或同时指定这两种规则。如果您同时指定,节点必须首先满足必要规则,然后尝试满足偏好规则。

以下示例显示了配置了 pod 关联性和反关联性的 Pod 规格。

在本例中,pod 关联性规则指明,只有当节点至少有一个已在运行且具有键 security 和值 S1 的标签的 pod 时,pod 才可以调度到这个节点上。pod 反关联性则表示,如果节点已在运行带有键 security 和值 S2.的标签的 pod,则 pod 将偏向于不调度到该节点上。

具有 pod 关联性的 Pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-affinity
spec:
  affinity:
    podAffinity: 1
      requiredDuringSchedulingIgnoredDuringExecution: 2
      - labelSelector:
          matchExpressions:
          - key: security 3
            operator: In 4
            values:
            - S1 5
        topologyKey: failure-domain.beta.kubernetes.io/zone
  containers:
  - name: with-pod-affinity
    image: docker.io/ocpqe/hello-pod

1
用于配置 pod 关联性的小节。
2
定义必要规则。
3 5
必须匹配键和值(标签)才会应用该规则。
4
运算符表示现有 pod 上的标签和新 pod 规格中 matchExpression 参数的值集合之间的关系。可以是 InNotInExistsDoesNotExist

具有 pod 反关联性的 Pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-pod-antiaffinity
spec:
  affinity:
    podAntiAffinity: 1
      preferredDuringSchedulingIgnoredDuringExecution: 2
      - weight: 100  3
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security 4
              operator: In 5
              values:
              - S2
          topologyKey: kubernetes.io/hostname
  containers:
  - name: with-pod-affinity
    image: docker.io/ocpqe/hello-pod

1
用于配置 pod 反关联性的小节。
2
定义偏好规则。
3
为偏好规则指定权重。优先选择权重最高的节点。
4
描述用来决定何时应用反关联性规则的 pod 标签。指定标签的键和值。
5
运算符表示现有 pod 上的标签和新 pod 规格中 matchExpression 参数的值集合之间的关系。可以是 InNotInExistsDoesNotExist
注意

如果节点标签在运行时改变,使得不再满足 pod 上的关联性规则,pod 会继续在该节点上运行。

3.3.2. 配置 pod 关联性规则

以下步骤演示了一个简单的双 pod 配置,它创建一个带有某标签的 pod,以及一个使用关联性来允许随着该 pod 一起调度的 pod。

流程

  1. 创建在 Pod spec 中带有特定标签的 pod:

    $ cat team4.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: security-s1
      labels:
        security: S1
    spec:
      containers:
      - name: security-s1
        image: docker.io/ocpqe/hello-pod
  2. 在创建其他 pod 时,按如下所示编辑 Pod 规格:

    1. 使用 podAffinity 小节配置 requiredDuringSchedulingIgnoredDuringExecution 参数或 preferredDuringSchedulingIgnoredDuringExecution 参数:
    2. 指定必须满足的键和值。如果您希望新 pod 与另一个 pod 一起调度,请使用与第一个 pod 上标签相同的 keyvalue 参数。

          podAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - key: security
                  operator: In
                  values:
                  - S1
              topologyKey: failure-domain.beta.kubernetes.io/zone
    3. 指定一个 operator。运算符可以是 InNotInExistsDoesNotExist。例如,使用运算符 In 来要求节点上存在该标签。
    4. 指定 topologyKey,这是一个预填充的 Kubernetes 标签,供系统用于表示这样的拓扑域。
  3. 创建 pod。

    $ oc create -f <pod-spec>.yaml

3.3.3. 配置 pod 反关联性规则

以下步骤演示了一个简单的双 pod 配置,它创建一个带有某标签的 pod,以及一个使用反关联性偏好规则来尝试阻止随着该 pod 一起调度的 pod。

流程

  1. 创建在 Pod spec 中带有特定标签的 pod:

    $ cat team4.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: security-s2
      labels:
        security: S2
    spec:
      containers:
      - name: security-s2
        image: docker.io/ocpqe/hello-pod
  2. 在创建其他 pod 时,编辑 Pod spec 来设置以下参数:
  3. 使用 podAntiAffinity 小节配置 requiredDuringSchedulingIgnoredDuringExecution 参数或 preferredDuringSchedulingIgnoredDuringExecution 参数:

    1. 为节点指定一个 1 到 100 的权重。优先选择权重最高的节点。
    2. 指定必须满足的键和值。如果您希望新 pod 不与另一个 pod 一起调度,请使用与第一个 pod 上标签相同的 keyvalue 参数。

          podAntiAffinity:
            preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                  - key: security
                    operator: In
                    values:
                    - S2
                topologyKey: kubernetes.io/hostname
    3. 为偏好规则指定一个 1 到 100 的权重。
    4. 指定一个 operator。运算符可以是 InNotInExistsDoesNotExist。例如,使用运算符 In 来要求节点上存在该标签。
  4. 指定 topologyKey,这是一个预填充的 Kubernetes 标签,供系统用于表示这样的拓扑域。
  5. 创建 pod。

    $ oc create -f <pod-spec>.yaml

3.3.4. pod 关联性和反关联性规则示例

以下示例演示了 pod 关联性和 pod 反关联性。

3.3.4.1. Pod 关联性

以下示例演示了具有匹配标签和标签选择器的 pod 的 pod 关联性。

  • pod team4 具有标签 team:4

    $ cat team4.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: team4
      labels:
         team: "4"
    spec:
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
  • pod team4apodAffinity 下具有标签选择器 team:4

    $ cat pod-team4a.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: team4a
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: team
                operator: In
                values:
                - "4"
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-affinity
        image: docker.io/ocpqe/hello-pod
  • team4a pod 调度到与 team4 pod 相同的节点上。

3.3.4.2. Pod 反关联性

以下示例演示了具有匹配标签和标签选择器的 pod 的 pod 反关联性。

  • pod pod-s1 具有标签 security:s1

    cat pod-s1.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
      labels:
        security: s1
    spec:
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
  • pod pod-s2podAntiAffinity 下具有标签选择器 security:s1

    cat pod-s2.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s2
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - s1
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-antiaffinity
        image: docker.io/ocpqe/hello-pod
  • pod pod-s2 无法调度到与 pod-s1 相同的节点上。

3.3.4.3. 无匹配标签的 Pod 反关联性

以下示例演示了在没有匹配标签和标签选择器时的 pod 的 pod 关联性。

  • pod pod-s1 具有标签 security:s1

    $ cat pod-s1.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
      labels:
        security: s1
    spec:
      containers:
      - name: ocp
        image: docker.io/ocpqe/hello-pod
  • pod pod-s2 具有标签选择器 security:s2

    $ cat pod-s2.yaml
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s2
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: security
                operator: In
                values:
                - s2
            topologyKey: kubernetes.io/hostname
      containers:
      - name: pod-affinity
        image: docker.io/ocpqe/hello-pod
  • 除非节点上具有带 security:s2 标签的 pod,否则不会调度 pod-s2。如果没有具有该标签的其他 pod,新 pod 会保持在待处理状态:

    输出示例

    NAME      READY     STATUS    RESTARTS   AGE       IP        NODE
    pod-s2    0/1       Pending   0          32s       <none>

3.3.5. 使用 pod 关联性和反关联性来控制安装 Operator 的位置

默认情况下,当安装 Operator 时,OpenShift Container Platform 会随机将 Operator pod 安装到其中一个 worker 节点。然而,在某些情况下,您可能希望该 pod 调度到特定节点或一组节点上。

以下示例描述了您可能希望将 Operator pod 调度到特定节点或一组节点的情况:

  • 如果 Operator 需要特定的平台,如 amd64arm64
  • 如果 Operator 需要特定的操作系统,如 Linux 或 Windows
  • 如果您希望 Operator 在同一个主机上或位于同一机架的主机上工作
  • 如果您希望 Operator 在整个基础架构中分散,以避免因为网络或硬件问题而停机

您可以通过向 Operator 的 Subscription 对象添加 pod 关联性或反关联性来控制 Operator pod 的安装位置。

以下示例演示了如何使用 pod 反关联性来防止从具有特定标签的 pod 中安装自定义 Metrics Autoscaler Operator:

将 Operator pod 放置到一个或多个特定节点的 Pod 关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      podAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - test
          topologyKey: kubernetes.io/hostname

1
将 Operator 的 pod 放置到具有 app=test 标签的 pod 的节点上的 pod 关联性。

防止 Operator pod 来自一个或多个特定节点的 Pod 反关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      podAntiAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
        - labelSelector:
            matchExpressions:
            - key: cpu
              operator: In
              values:
              - high
          topologyKey: kubernetes.io/hostname
 ...

1
一个 pod 反关联性,它可防止 Operator 的 pod 调度到具有 cpu=high 标签的 pod 的节点上。

流程

要控制 Operator pod 的放置,请完成以下步骤:

  1. 照常安装 Operator。
  2. 如果需要,请确保您的节点已标记为正确响应关联性。
  3. 编辑 Operator Subscription 对象以添加关联性:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: openshift-custom-metrics-autoscaler-operator
      namespace: openshift-keda
    spec:
      name: my-package
      source: my-operators
      sourceNamespace: operator-registries
      config:
        affinity:
          podAntiAffinity: 1
            requiredDuringSchedulingIgnoredDuringExecution:
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                  - key: kubernetes.io/hostname
                    operator: In
                    values:
                    - ip-10-0-185-229.ec2.internal
                topologyKey: topology.kubernetes.io/zone
     ...
    1
    添加 podAffinitypodAntiAffinity

验证

  • 要确保 pod 部署到特定的节点上,请运行以下命令:

    $ oc get pods -o wide

    输出示例

    NAME                                                  READY   STATUS    RESTARTS   AGE   IP            NODE                           NOMINATED NODE   READINESS GATES
    custom-metrics-autoscaler-operator-5dcc45d656-bhshg   1/1     Running   0          50s   10.131.0.20   ip-10-0-185-229.ec2.internal   <none>           <none>

3.4. 使用节点关联性规则控制节点上的 pod 放置

关联性是 pod 的一个属性,用于控制它们希望调度到的节点。

在 OpenShift Container Platform 中,节点关联性是由调度程序用来确定 pod 的可放置位置的一组规则。规则是使用节点中的自定义标签和 pod 中指定的选择器进行定义的。

3.4.1. 了解节点关联性

节点关联性允许 pod 指定与可以放置该 pod 的一组节点的关联性。节点对放置没有控制权。

例如,您可以将 pod 配置为仅在具有特定 CPU 或位于特定可用区的节点上运行。

节点关联性规则有两种,即必要规则和偏好规则。

必须满足必要规则,pod 才能调度到节点上。偏好规则指定在满足规则时调度程序会尝试强制执行规则,但不保证一定能强制执行成功。

注意

如果节点标签在运行时改变,使得不再满足 pod 上的节点关联性规则,该 pod 将继续在这个节点上运行。

您可以通过 Pod 规格文件配置节点关联性。您可以指定必要规则或偏好规则,或同时指定这两种规则。如果您同时指定,节点必须首先满足必要规则,然后尝试满足偏好规则。

下例中的 Pod spec 包含一条规则,要求 pod 放置到具有键为 e2e-az-NorthSouth 且值为 e2e-az-Northe2e-az-South 的标签的节点上:

具有节点关联性必要规则的 pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity: 1
      requiredDuringSchedulingIgnoredDuringExecution: 2
        nodeSelectorTerms:
        - matchExpressions:
          - key: e2e-az-NorthSouth 3
            operator: In 4
            values:
            - e2e-az-North 5
            - e2e-az-South 6
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod

1
用于配置节点关联性的小节。
2
定义必要规则。
3 5 6
必须匹配键/值对(标签)才会应用该规则。
4
运算符表示节点上的标签和 Pod 规格中 matchExpression 参数的值集合之间的关系。这个值可以是 InNotInExistsDoesNotExistLtGt

下例中的节点规格包含一条偏好规则,其规定优先为 pod 选择具有键为 e2e-az-EastWest 且值为 e2e-az-Easte2e-az-West 的节点:

具有节点关联性偏好规则的 pod 配置文件示例

apiVersion: v1
kind: Pod
metadata:
  name: with-node-affinity
spec:
  affinity:
    nodeAffinity: 1
      preferredDuringSchedulingIgnoredDuringExecution: 2
      - weight: 1 3
        preference:
          matchExpressions:
          - key: e2e-az-EastWest 4
            operator: In 5
            values:
            - e2e-az-East 6
            - e2e-az-West 7
  containers:
  - name: with-node-affinity
    image: docker.io/ocpqe/hello-pod

1
用于配置节点关联性的小节。
2
定义偏好规则。
3
为偏好规则指定权重。优先选择权重最高的节点。
4 6 7
必须匹配键/值对(标签)才会应用该规则。
5
运算符表示节点上的标签和 Pod 规格中 matchExpression 参数的值集合之间的关系。这个值可以是 InNotInExistsDoesNotExistLtGt

没有明确的节点反关联性概念,但使用 NotInDoesNotExist 运算符就能实现这种行为。

注意

如果您在同一 pod 配置中同时使用节点关联性和节点选择器,请注意以下几点:

  • 如果同时配置了 nodeSelectornodeAffinity,则必须满足这两个条件时 pod 才能调度到候选节点。
  • 如果您指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,那么其中一个 nodeSelectorTerms 满足时 pod 就能调度到节点上。
  • 如果您指定了多个与 nodeSelectorTerms 关联的 matchExpressions,那么只有所有 matchExpressions 都满足时 pod 才能调度到节点上。

3.4.2. 配置节点关联性必要规则

必须满足必要规则,pod 才能调度到节点上。

流程

以下步骤演示了一个简单的配置,此配置会创建一个节点,以及调度程序要放置到该节点上的 pod。

  1. 使用 oc label node 命令给节点添加标签:

    $ oc label node node1 e2e-az-name=e2e-az1
    提示

    您还可以应用以下 YAML 来添加标签:

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        e2e-az-name: e2e-az1
  2. Pod spec 中,使用 nodeAffinity 小节来配置 requiredDuringSchedulingIgnoredDuringExecution 参数:

    1. 指定必须满足的键和值。如果希望新 pod 调度到您编辑的节点上,请使用与节点中标签相同的 keyvalue 参数。
    2. 指定一个 operator。运算符可以是 InNotInExistsDoesNotExistLtGt。例如,使用运算符 In 来要求节点上存在该标签:

      输出示例

      spec:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: e2e-az-name
                  operator: In
                  values:
                  - e2e-az1
                  - e2e-az2

  3. 创建 pod:

    $ oc create -f e2e-az2.yaml

3.4.3. 配置首选的节点关联性规则

偏好规则指定在满足规则时调度程序会尝试强制执行规则,但不保证一定能强制执行成功。

流程

以下步骤演示了一个简单的配置,此配置会创建一个节点,以及调度程序尝试放置到该节点上的 pod。

  1. 使用 oc label node 命令给节点添加标签:

    $ oc label node node1 e2e-az-name=e2e-az3
  2. Pod spec 中,使用 nodeAffinity 小节来配置 preferredDuringSchedulingIgnoredDuringExecution 参数:

    1. 为节点指定一个权重,值为 1 到 100 的数字。优先选择权重最高的节点。
    2. 指定必须满足的键和值。如果希望新 pod 调度到您编辑的节点上,请使用与节点中标签相同的 keyvalue 参数:

      spec:
        affinity:
          nodeAffinity:
            preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 1
              preference:
                matchExpressions:
                - key: e2e-az-name
                  operator: In
                  values:
                  - e2e-az3
    3. 指定一个 operator。运算符可以是 InNotInExistsDoesNotExistLtGt。例如,使用运算符 In 来要求节点上存在该标签。
  3. 创建 pod。

    $ oc create -f e2e-az3.yaml

3.4.4. 节点关联性规则示例

以下示例演示了节点关联性。

3.4.4.1. 具有匹配标签的节点关联性

以下示例演示了具有匹配标签的节点与 pod 的节点关联性:

  • Node1 节点具有标签 zone:us

    $ oc label node node1 zone=us
    提示

    您还可以应用以下 YAML 来添加标签:

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        zone: us
  • pod-s1 pod 在节点关联性必要规则下具有 zoneus 键/值对:

    $ cat pod-s1.yaml

    输出示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
    spec:
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: "zone"
                  operator: In
                  values:
                  - us

  • pod-s1 pod 可以调度到 Node1 上:

    $ oc get pod -o wide

    输出示例

    NAME     READY     STATUS       RESTARTS   AGE      IP      NODE
    pod-s1   1/1       Running      0          4m       IP1     node1

3.4.4.2. 没有匹配标签的节点关联性

以下示例演示了无匹配标签的节点与 pod 的节点关联性:

  • Node1 节点具有标签 zone:emea:

    $ oc label node node1 zone=emea
    提示

    您还可以应用以下 YAML 来添加标签:

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        zone: emea
  • pod-s1 pod 在节点关联性必要规则下具有 zoneus 键/值对:

    $ cat pod-s1.yaml

    输出示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-s1
    spec:
      containers:
        - image: "docker.io/ocpqe/hello-pod"
          name: hello-pod
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: "zone"
                  operator: In
                  values:
                  - us

  • pod-s1 pod 无法调度到 Node1 上:

    $ oc describe pod pod-s1

    输出示例

    ...
    
    Events:
     FirstSeen LastSeen Count From              SubObjectPath  Type                Reason
     --------- -------- ----- ----              -------------  --------            ------
     1m        33s      8     default-scheduler Warning        FailedScheduling    No nodes are available that match all of the following predicates:: MatchNodeSelector (1).

3.4.5. 使用节点关联性来控制安装 Operator 的位置

默认情况下,当安装 Operator 时,OpenShift Container Platform 会随机将 Operator pod 安装到其中一个 worker 节点。然而,在某些情况下,您可能希望该 pod 调度到特定节点或一组节点上。

以下示例描述了您可能希望将 Operator pod 调度到特定节点或一组节点的情况:

  • 如果 Operator 需要特定的平台,如 amd64arm64
  • 如果 Operator 需要特定的操作系统,如 Linux 或 Windows
  • 如果您希望 Operator 在同一个主机上或位于同一机架的主机上工作
  • 如果您希望 Operator 在整个基础架构中分散,以避免因为网络或硬件问题而停机

您可以通过在 Operator 的 Subscription 对象中添加节点关联性约束来控制 Operator pod 的安装位置。

以下示例演示了如何使用节点关联性将自定义 Metrics Autoscaler Operator 实例安装到集群中的特定节点:

将 Operator pod 放置到特定节点的节点关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      nodeAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
              - ip-10-0-163-94.us-west-2.compute.internal
 ...

1
要求 Operator 的 pod 调度到名为 ip-10-0-163-94.us-west-2.compute.internal 的节点关联性。

将 Operator pod 放置到带有特定平台的节点关联性示例

apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
  name: openshift-custom-metrics-autoscaler-operator
  namespace: openshift-keda
spec:
  name: my-package
  source: my-operators
  sourceNamespace: operator-registries
  config:
    affinity:
      nodeAffinity: 1
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
          - matchExpressions:
            - key: kubernetes.io/arch
              operator: In
              values:
              - arm64
            - key: kubernetes.io/os
              operator: In
              values:
              - linux

1
要求 Operator 的 pod 调度到具有 kubernetes.io/arch=arm64kubernetes.io/os=linux 标签的节点上。

流程

要控制 Operator pod 的放置,请完成以下步骤:

  1. 照常安装 Operator。
  2. 如果需要,请确保您的节点已标记为正确响应关联性。
  3. 编辑 Operator Subscription 对象以添加关联性:

    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: openshift-custom-metrics-autoscaler-operator
      namespace: openshift-keda
    spec:
      name: my-package
      source: my-operators
      sourceNamespace: operator-registries
      config:
        affinity: 1
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - ip-10-0-185-229.ec2.internal
     ...
    1
    添加 nodeAffinity

验证

  • 要确保 pod 部署到特定的节点上,请运行以下命令:

    $ oc get pods -o wide

    输出示例

    NAME                                                  READY   STATUS    RESTARTS   AGE   IP            NODE                           NOMINATED NODE   READINESS GATES
    custom-metrics-autoscaler-operator-5dcc45d656-bhshg   1/1     Running   0          50s   10.131.0.20   ip-10-0-185-229.ec2.internal   <none>           <none>

3.4.6. 其他资源

3.5. 将 pod 放置到过量使用的节点

处于过量使用(overcommited)状态时,容器计算资源请求和限制的总和超过系统中可用的资源。过量使用常用于开发环境,因为在这种环境中可以接受以牺牲保障性能来换取功能的情况。

请求和限制可让管理员允许和管理节点上资源的过量使用。调度程序使用请求来调度容器,并提供最低服务保证。限制约束节点上可以消耗的计算资源数量。

3.5.1. 了解过量使用

请求和限制可让管理员允许和管理节点上资源的过量使用。调度程序使用请求来调度容器,并提供最低服务保证。限制约束节点上可以消耗的计算资源数量。

OpenShift Container Platform 管理员可以通过配置主控机(master)来覆盖开发人员容器上设置的请求和限制之间的比率,来控制过量使用的程度并管理节点上的容器密度。与项目一级上的用于指定限制和默认值的 LimitRange 对象一起使用,可以调整容器限制和请求以达到所需的过量使用程度。

注意

如果没有在容器中设定限制,则这些覆盖无效。创建一个带有默认限制(基于每个独立的项目或在项目模板中)的 LimitRange 对象,以确保能够应用覆盖。

在进行这些覆盖后,容器限制和请求必须仍需要满足项目中的 LimitRange 对象的要求。这可能会导致 pod 被禁止的情况。例如,开发人员指定了一个接近最小限制的限制,然后其请求被覆盖为低于最小限制。这个问题在以后会加以解决,但目前而言,请小心地配置此功能和 LimitRange 对象。

3.5.2. 了解节点过量使用

在过量使用的环境中,务必要正确配置节点,以提供最佳的系统行为。

当节点启动时,它会确保为内存管理正确设置内核可微调标识。除非物理内存不足,否则内核应该永不会在内存分配时失败。

为确保这一行为,OpenShift Container Platform 通过将 vm.overcommit_memory 参数设置为 1 来覆盖默认操作系统设置,从而将内核配置为始终过量使用内存。

OpenShift Container Platform 还通过将 vm.panic_on_oom 参数设置为 0,将内核配置为不会在内存不足时崩溃。设置为 0 可告知内核在内存不足 (OOM) 情况下调用 oom_killer,以根据优先级终止进程

您可以通过对节点运行以下命令来查看当前的设置:

$ sysctl -a |grep commit

输出示例

vm.overcommit_memory = 1

$ sysctl -a |grep panic

输出示例

vm.panic_on_oom = 0

注意

节点上应该已设置了上述标记,不需要进一步操作。

您还可以为每个节点执行以下配置:

  • 使用 CPU CFS 配额禁用或强制实施 CPU 限制
  • 为系统进程保留资源
  • 为不同的服务质量等级保留内存

3.6. 使用节点污点控制 pod 放置

通过污点和容限,节点可以控制哪些 pod 应该(或不应该)调度到节点上。

3.6.1. 了解污点和容限

通过使用污点(taint),节点可以拒绝调度 pod,除非 pod 具有匹配的容限(toleration)

您可以通过节点规格(NodeSpec)将污点应用到节点,并通过 Pod 规格(PodSpec)将容限应用到 pod。当您应用污点时,调度程序无法将 pod 放置到该节点上,除非 pod 可以容限该污点。

节点规格中的污点示例

spec:
  taints:
  - effect: NoExecute
    key: key1
    value: value1
....

Pod 规格中的容限示例

spec:
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600
....

污点与容限由 key、value 和 effect 组成。

表 3.1. 污点和容限组件

参数描述

key

key 是任意字符串,最多 253 个字符。key 必须以字母或数字开头,可以包含字母、数字、连字符、句点和下划线。

value

value 是任意字符串,最多 63 个字符。value 必须以字母或数字开头,可以包含字母、数字、连字符、句点和下划线。

effect

effect 的值包括:

NoSchedule [1]

  • 与污点不匹配的新 pod 不会调度到该节点上。
  • 该节点上现有的 pod 会保留。

PreferNoSchedule

  • 与污点不匹配的新 pod 可以调度到该节点上,但调度程序会尽量不这样调度。
  • 该节点上现有的 pod 会保留。

NoExecute

  • 与污点不匹配的新 pod 无法调度到该节点上。
  • 节点上没有匹配容限的现有 pod 将被移除。

operator

Equal

key/value/effect 参数必须匹配。这是默认值。

Exists

key/effect 参数必须匹配。您必须保留一个空的 value 参数,这将匹配任何值。

  1. 如果向 control plane 节点添加了一个 NoSchedule 污点,节点必须具有 node-role.kubernetes.io/master=:NoSchedule 污点,这默认会添加。

    例如:

    apiVersion: v1
    kind: Node
    metadata:
      annotations:
        machine.openshift.io/machine: openshift-machine-api/ci-ln-62s7gtb-f76d1-v8jxv-master-0
        machineconfiguration.openshift.io/currentConfig: rendered-master-cdc1ab7da414629332cc4c3926e6e59c
    ...
    spec:
      taints:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
    ...

容限与污点匹配:

  • 如果 operator 参数设为 Equal

    • key 参数相同;
    • value 参数相同;
    • effect 参数相同。
  • 如果 operator 参数设为 Exists

    • key 参数相同;
    • effect 参数相同。

OpenShift Container Platform 中内置了以下污点:

  • node.kubernetes.io/not-ready:节点未就绪。这与节点状况 Ready=False 对应。
  • node.kubernetes.io/unreachable:节点无法从节点控制器访问。这与节点状况 Ready=Unknown 对应。
  • node.kubernetes.io/memory-pressure:节点存在内存压力问题。这与节点状况 MemoryPressure=True 对应。
  • node.kubernetes.io/disk-pressure:节点存在磁盘压力问题。这与节点状况 DiskPressure=True 对应。
  • node.kubernetes.io/network-unavailable:节点网络不可用。
  • node.kubernetes.io/unschedulable:节点不可调度。
  • node.cloudprovider.kubernetes.io/uninitialized:当节点控制器通过外部云提供商启动时,在节点上设置这个污点来将其标记为不可用。在云控制器管理器中的某个控制器初始化这个节点后,kubelet 会移除此污点。
  • node.kubernetes.io/pid-pressure :节点具有 pid 压力。这与节点状况 PIDPressure=True 对应。

    重要

    OpenShift Container Platform 不设置默认的 pid.available evictionHard

3.6.1.1. 了解如何使用容限秒数来延迟 pod 驱除

您可以通过在 Pod 规格或 MachineSet 对象中指定 tolerationSeconds 参数,指定 pod 在被驱除前可以保持与节点绑定的时长。如果将具有 NoExecute effect 的污点添加到节点,则容限污点(包含 tolerationSeconds 参数)的 pod,在此期限内 pod 不会被驱除。

输出示例

spec:
  tolerations:
  - key: "key1"
    operator: "Equal"
    value: "value1"
    effect: "NoExecute"
    tolerationSeconds: 3600

在这里,如果此 pod 正在运行但没有匹配的容限,pod 保持与节点绑定 3600 秒,然后被驱除。如果污点在这个时间之前移除,pod 就不会被驱除。

3.6.1.2. 了解如何使用多个污点

您可以在同一个节点中放入多个污点,并在同一 pod 中放入多个容限。OpenShift Container Platform 按照如下所述处理多个污点和容限:

  1. 处理 pod 具有匹配容限的污点。
  2. 其余的不匹配污点在 pod 上有指示的 effect:

    • 如果至少有一个不匹配污点具有 NoSchedule effect,则 OpenShift Container Platform 无法将 pod 调度到该节点上。
    • 如果没有不匹配污点具有 NoSchedule effect,但至少有一个不匹配污点具有 PreferNoSchedule effect,则 OpenShift Container Platform 尝试不将 pod 调度到该节点上。
    • 如果至少有一个未匹配污点具有 NoExecute effect,OpenShift Container Platform 会将 pod 从该节点驱除(如果它已在该节点上运行),或者不将 pod 调度到该节点上(如果还没有在该节点上运行)。

      • 不容许污点的 Pod 会立即被驱除。
      • 如果 Pod 容许污点而没有在 Pod 规格中指定 tolerationSeconds,则会永久保持绑定。
      • 如果 Pod 容许污点,且指定了 tolerationSeconds,则会在指定的时间里保持绑定。

例如:

  • 向节点添加以下污点:

    $ oc adm taint nodes node1 key1=value1:NoSchedule
    $ oc adm taint nodes node1 key1=value1:NoExecute
    $ oc adm taint nodes node1 key2=value2:NoSchedule
  • pod 具有以下容限:

    spec:
      tolerations:
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoSchedule"
      - key: "key1"
        operator: "Equal"
        value: "value1"
        effect: "NoExecute"

在本例中,pod 无法调度到节点上,因为没有与第三个污点匹配的容限。如果在添加污点时 pod 已在节点上运行,pod 会继续运行,因为第三个污点是三个污点中 pod 唯一不容许的污点。

3.6.1.3. 了解 pod 调度和节点状况(根据状况保留节点)

Taint Nodes By Condition (默认启用)可自动污点报告状况的节点,如内存压力和磁盘压力。如果某个节点报告一个状况,则添加一个污点,直到状况被清除为止。这些污点具有 NoSchedule effect;即,pod 无法调度到该节点上,除非 pod 有匹配的容限。

在调度 pod 前,调度程序会检查节点上是否有这些污点。如果污点存在,则将 pod 调度到另一个节点。由于调度程序检查的是污点而非实际的节点状况,因此您可以通过添加适当的 pod 容限,将调度程序配置为忽略其中一些节点状况。

为确保向后兼容,守护进程会自动将下列容限添加到所有守护进程中:

  • node.kubernetes.io/memory-pressure
  • node.kubernetes.io/disk-pressure
  • node.kubernetes.io/unschedulable(1.10 或更高版本)
  • node.kubernetes.io/network-unavailable(仅限主机网络)

您还可以在守护进程集中添加任意容限。

注意

control plane 还会在具有 QoS 类的 pod 中添加 node.kubernetes.io/memory-pressure 容限。这是因为 Kubernetes 在 GuaranteedBurstable QoS 类中管理 pod。新的 BestEffort pod 不会调度到受影响的节点上。

3.6.1.4. 了解根据状况驱除 pod(基于垃圾的驱除)

Taint-Based Evictions 功能默认是启用的,可以从遇到特定状况(如 not-readyunreachable)的节点驱除 pod。当节点遇到其中一个状况时,OpenShift Container Platform 会自动给节点添加污点,并开始驱除 pod 以及将 pod 重新调度到其他节点。

Taint Based Evictions 具有 NoExecute 效果,不容许污点的 pod 都被立即驱除,容许污点的 pod 不会被驱除,除非 pod 使用 tolerationSeconds 参数。

tolerationSeconds 参数允许您指定 pod 保持与具有节点状况的节点绑定的时长。如果在 tolerationSections 到期后状况仍然存在,则污点会保持在节点上,并且具有匹配容限的 pod 将被驱除。如果状况在 tolerationSeconds 到期前清除,则不会删除具有匹配容限的 pod。

如果使用没有值的 tolerationSeconds 参数,则 pod 不会因为未就绪和不可访问的节点状况而被驱除。

注意

OpenShift Container Platform 会以限速方式驱除 pod,从而防止在主控机从节点分离等情形中发生大量 pod 驱除。

默认情况下,如果给定区域中的节点超过 55% 的节点不健康,节点生命周期控制器会将该区域的状态改为 PartialDisruption,并且 pod 驱除率会减少。对于此状态的小型集群(默认为 50 个节点或更少),这个区中的节点不会污点,驱除会被停止。

如需更多信息,请参阅 Kubernetes 文档中的 有关驱除率限制

OpenShift Container Platform 会自动为 node.kubernetes.io/not-readynode.kubernetes.io/unreachable 添加容限并设置 tolerationSeconds=300,除非 Pod 配置中指定了其中任一种容限。

spec:
  tolerations:
  - key: node.kubernetes.io/not-ready
    operator: Exists
    effect: NoExecute
    tolerationSeconds: 300 1
  - key: node.kubernetes.io/unreachable
    operator: Exists
    effect: NoExecute
    tolerationSeconds: 300
1
这些容限确保了在默认情况下,pod 在检测到这些节点条件问题中的任何一个时,会保持绑定五分钟。

您可以根据需要配置这些容限。例如,如果您有一个具有许多本地状态的应用程序,您可能希望在发生网络分区时让 pod 与节点保持绑定更久一些,以等待分区恢复并避免 pod 驱除行为的发生。

由守护进程集生成的 pod 在创建时会带有以下污点的 NoExecute 容限,且没有 tolerationSeconds:

  • node.kubernetes.io/unreachable
  • node.kubernetes.io/not-ready

因此,守护进程集 pod 不会被驱除。

3.6.1.5. 容限所有污点

您可以通过添加 operator: "Exists" 容限而无需 keyvalue 参数,将节点配置为容许所有污点。具有此容限的 Pod 不会从具有污点的节点中删除。

用于容忍所有污点的Pod 规格

spec:
  tolerations:
  - operator: "Exists"

3.6.2. 添加污点和容限

您可以为 pod 和污点添加容限,以便节点能够控制哪些 pod 应该或不应该调度到节点上。对于现有的 pod 和节点,您应首先将容限添加到 pod,然后将污点添加到节点,以避免在添加容限前从节点上移除 pod。

流程

  1. 通过编辑 Pod spec 使其包含 tolerations 小节来向 pod 添加容限:

    使用 Equal 运算符的 pod 配置文件示例

    spec:
      tolerations:
      - key: "key1" 1
        value: "value1"
        operator: "Equal"
        effect: "NoExecute"
        tolerationSeconds: 3600 2

    1
    容限参数,如 Taint 和 toleration 组件表中所述。
    2
    tolerationSeconds 参数指定 pod 在被驱除前可以保持与节点绑定的时长。

    例如:

    使用 Exists 运算符的 pod 配置文件示例

    spec:
       tolerations:
        - key: "key1"
          operator: "Exists" 1
          effect: "NoExecute"
          tolerationSeconds: 3600

    1
    Exists 运算符不会接受一个 value

    本例在 node1 上放置一个键为 key1 且值为 value1 的污点,污点效果是 NoExecute

  2. 通过以下命令,使用 Taint 和 toleration 组件表中描述的参数为节点添加污点:

    $ oc adm taint nodes <node_name> <key>=<value>:<effect>

    例如:

    $ oc adm taint nodes node1 key1=value1:NoExecute

    此命令在 node1 上放置一个键为 key1,值为 value1 的污点,其效果是 NoExecute

    注意

    如果向 control plane 节点添加了一个 NoSchedule 污点,节点必须具有 node-role.kubernetes.io/master=:NoSchedule 污点,这默认会添加。

    例如:

    apiVersion: v1
    kind: Node
    metadata:
      annotations:
        machine.openshift.io/machine: openshift-machine-api/ci-ln-62s7gtb-f76d1-v8jxv-master-0
        machineconfiguration.openshift.io/currentConfig: rendered-master-cdc1ab7da414629332cc4c3926e6e59c
    ...
    spec:
      taints:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
    ...

    pod 上的容限与节点上的污点匹配。具有任一容限的 pod 可以调度到 node1 上。

3.6.2.1. 使用计算机器集添加污点和容限

您可以使用计算机器集为节点添加污点。与 MachineSet 对象关联的所有节点都会使用污点更新。容限响应由计算机器设置添加的污点,其方式与直接添加到节点的污点相同。

流程

  1. 通过编辑 Pod spec 使其包含 tolerations 小节来向 pod 添加容限:

    使用 Equal 运算符的 pod 配置文件示例

    spec:
      tolerations:
      - key: "key1" 1
        value: "value1"
        operator: "Equal"
        effect: "NoExecute"
        tolerationSeconds: 3600 2

    1
    容限参数,如 Taint 和 toleration 组件表中所述。
    2
    tolerationSeconds 参数指定 pod 在被驱除前与节点绑定的时长。

    例如:

    使用 Exists 运算符的 pod 配置文件示例

    spec:
      tolerations:
      - key: "key1"
        operator: "Exists"
        effect: "NoExecute"
        tolerationSeconds: 3600

  2. 将污点添加到 MachineSet 对象:

    1. 为您想要污点的节点编辑 MachineSet YAML,也可以创建新 MachineSet 对象:

      $ oc edit machineset <machineset>
    2. 将污点添加到 spec.template.spec 部分:

      计算机器设置规格中的污点示例

      spec:
      ....
        template:
      ....
          spec:
            taints:
            - effect: NoExecute
              key: key1
              value: value1
      ....

      本例在节点上放置一个键为 key1,值为 value1 的污点,污点效果是 NoExecute

    3. 将计算机器设置为 0:

      $ oc scale --replicas=0 machineset <machineset> -n openshift-machine-api
      提示

      您还可以应用以下 YAML 来扩展计算机器集:

      apiVersion: machine.openshift.io/v1beta1
      kind: MachineSet
      metadata:
        name: <machineset>
        namespace: openshift-machine-api
      spec:
        replicas: 0

      等待机器被删除。

    4. 根据需要扩展计算机器:

      $ oc scale --replicas=2 machineset <machineset> -n openshift-machine-api

      或者:

      $ oc edit machineset <machineset> -n openshift-machine-api

      等待机器启动。污点添加到与 MachineSet 对象关联的节点上。

3.6.2.2. 使用污点和容限将用户绑定到节点

如果要指定一组节点供特定用户独占使用,为 pod 添加容限。然后,在这些节点中添加对应的污点。具有容限的 pod 被允许使用污点节点,或集群中的任何其他节点。

如果您希望确保 pod 只调度到那些污点节点,还要将标签添加到同一组节点,并为 pod 添加节点关联性,以便 pod 只能调度到具有该标签的节点。

流程

配置节点以使用户只能使用该节点:

  1. 为这些节点添加对应的污点:

    例如:

    $ oc adm taint nodes node1 dedicated=groupName:NoSchedule
    提示

    您还可以应用以下 YAML 来添加污点:

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        ...
    spec:
      taints:
        - key: dedicated
          value: groupName
          effect: NoSchedule
  2. 通过编写自定义准入控制器,为 pod 添加容限。

3.6.2.3. 使用节点选择器和容限创建项目

您可以创建一个使用节点选择器和容限(设为注解)的项目,以控制 pod 放置到特定的节点上。然后,项目中创建的任何后续资源都会调度到与容限匹配的污点节点上。

先决条件

  • 通过使用计算机器集或直接编辑节点,已将节点选择的标签添加到一个或多个节点上。
  • 通过使用计算机器集或直接编辑节点,已将污点添加到一个或多个节点上。

流程

  1. 创建 Project 资源定义,在 metadata.annotations 部分指定节点选择器和容限:

    project.yaml 文件示例

    kind: Project
    apiVersion: project.openshift.io/v1
    metadata:
      name: <project_name> 1
      annotations:
        openshift.io/node-selector: '<label>' 2
        scheduler.alpha.kubernetes.io/defaultTolerations: >-
          [{"operator": "Exists", "effect": "NoSchedule", "key":
          "<key_name>"} 3
          ]

    1
    项目名称。
    2
    默认节点选择器标签。
    3
    容限参数,如 Taint 和 toleration 组件表中所述。本例使用 NoSchedule effect (允许节点上现有的 pod 保留)和 Exists 运算符(不使用值)。
  2. 使用 oc apply 命令来创建项目:

    $ oc apply -f project.yaml

现在,<project_name> 命名空间中创建的任何后续资源都应调度到指定的节点上。

3.6.2.4. 使用污点和容限控制具有特殊硬件的节点

如果集群中有少量节点具有特殊的硬件,您可以使用污点和容限让不需要特殊硬件的 pod 与这些节点保持距离,从而将这些节点保留给那些确实需要特殊硬件的 pod。您还可以要求需要特殊硬件的 pod 使用特定的节点。

您可以将容限添加到需要特殊硬件并污点具有特殊硬件的节点的 pod 中。

流程

确保为特定 pod 保留具有特殊硬件的节点:

  1. 为需要特殊硬件的 pod 添加容限。

    例如:

    spec:
      tolerations:
        - key: "disktype"
          value: "ssd"
          operator: "Equal"
          effect: "NoSchedule"
          tolerationSeconds: 3600
  2. 使用以下命令之一,给拥有特殊硬件的节点添加污点:

    $ oc adm taint nodes <node-name> disktype=ssd:NoSchedule

    或者:

    $ oc adm taint nodes <node-name> disktype=ssd:PreferNoSchedule
    提示

    您还可以应用以下 YAML 来添加污点:

    kind: Node
    apiVersion: v1
    metadata:
      name: <node_name>
      labels:
        ...
    spec:
      taints:
        - key: disktype
          value: ssd
          effect: PreferNoSchedule

3.6.3. 删除污点和容限

您可以根据需要,从节点移除污点并从 pod 移除容限。您应首先将容限添加到 pod,然后将污点添加到节点,以避免在添加容限前从节点上移除 pod。

流程

移除污点和容限:

  1. 从节点移除污点:

    $ oc adm taint nodes <node-name> <key>-

    例如:

    $ oc adm taint nodes ip-10-0-132-248.ec2.internal key1-

    输出示例

    node/ip-10-0-132-248.ec2.internal untainted

  2. 要从 pod 移除某一容限,请编辑 Pod 规格来移除该容限:

    spec:
      tolerations:
      - key: "key2"
        operator: "Exists"
        effect: "NoExecute"
        tolerationSeconds: 3600

3.7. 使用节点选择器将 pod 放置到特定节点

节点选择器指定一个键/值对映射,该映射使用 pod 中指定的自定义标签和选择器定义。

要使 pod 有资格在节点上运行,pod 必须具有与节点上标签相同的键值节点选择器。

3.7.1. 关于节点选择器

您可以使用节点上的 pod 和标签上的节点选择器来控制 pod 的调度位置。使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

您可以使用节点选择器将特定的 pod 放置到特定的节点上,集群范围节点选择器将新 pod 放置到集群中的任何特定节点上,以及项目节点选择器,将新 pod 放置到特定的节点上。

例如,作为集群管理员,您可以创建一个基础架构,应用程序开发人员可以通过在创建的每个 pod 中包括节点选择器,将 pod 部署到最接近其地理位置的节点。在本例中,集群由五个数据中心组成,分布在两个区域。在美国,将节点标记为 us-eastus-centralus-west。在亚太地区(APAC),将节点标记为 apac-eastapac-west。开发人员可在其创建的 pod 中添加节点选择器,以确保 pod 调度到这些节点上。

如果 Pod 对象包含节点选择器,但没有节点具有匹配的标签,则不会调度 pod。

重要

如果您在同一 pod 配置中使用节点选择器和节点关联性,则以下规则控制 pod 放置到节点上:

  • 如果同时配置了 nodeSelectornodeAffinity,则必须满足这两个条件时 pod 才能调度到候选节点。
  • 如果您指定了多个与 nodeAffinity 类型关联的 nodeSelectorTerms,那么其中一个 nodeSelectorTerms 满足时 pod 就能调度到节点上。
  • 如果您指定了多个与 nodeSelectorTerms 关联的 matchExpressions,那么只有所有 matchExpressions 都满足时 pod 才能调度到节点上。
特定 pod 和节点上的节点选择器

您可以使用节点选择器和标签控制特定 pod 调度到哪些节点上。

要使用节点选择器和标签,首先标记节点以避免 pod 被取消调度,然后将节点选择器添加到 pod。

注意

您不能直接将节点选择器添加到现有调度的 pod 中。您必须标记控制 pod 的对象,如部署配置。

例如,以下 Node 对象具有 region: east 标签:

带有标识的 Node 对象示例

kind: Node
apiVersion: v1
metadata:
  name: ip-10-0-131-14.ec2.internal
  selfLink: /api/v1/nodes/ip-10-0-131-14.ec2.internal
  uid: 7bc2580a-8b8e-11e9-8e01-021ab4174c74
  resourceVersion: '478704'
  creationTimestamp: '2019-06-10T14:46:08Z'
  labels:
    kubernetes.io/os: linux
    failure-domain.beta.kubernetes.io/zone: us-east-1a
    node.openshift.io/os_version: '4.5'
    node-role.kubernetes.io/worker: ''
    failure-domain.beta.kubernetes.io/region: us-east-1
    node.openshift.io/os_id: rhcos
    beta.kubernetes.io/instance-type: m4.large
    kubernetes.io/hostname: ip-10-0-131-14
    beta.kubernetes.io/arch: amd64
    region: east 1

1
与 pod 节点选择器匹配的标签。

pod 具有 type: user-node,region: east 节点选择器:

使用节点选择器的 Pod 对象示例

apiVersion: v1
kind: Pod

....

spec:
  nodeSelector: 1
    region: east
    type: user-node

1
与节点标签匹配的节点选择器。

使用示例 pod 规格创建 pod 时,它可以调度到示例节点上。

默认集群范围节点选择器

使用默认集群范围节点选择器时,如果您在集群中创建 pod,OpenShift Container Platform 会将默认节点选择器添加到 pod,并将该 pod 调度到具有匹配标签的节点。

例如,以下 Scheduler 对象具有默认的集群范围的 region=easttype=user-node 节点选择器:

Scheduler Operator 自定义资源示例

apiVersion: config.openshift.io/v1
kind: Scheduler
metadata:
  name: cluster
...

spec:
  defaultNodeSelector: type=user-node,region=east
...

集群中的节点具有 type=user-node,region=east 标签:

Node 对象示例

apiVersion: v1
kind: Node
metadata:
  name: ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4
...
  labels:
    region: east
    type: user-node
...

使用节点选择器的 Pod 对象示例

apiVersion: v1
kind: Pod
...

spec:
  nodeSelector:
    region: east
...

当您使用示例集群中的 pod spec 创建 pod 时,该 pod 会使用集群范围节点选择器创建,并调度到标记的节点:

在标记的节点上带有 pod 的 pod 列表示例

NAME     READY   STATUS    RESTARTS   AGE   IP           NODE                                       NOMINATED NODE   READINESS GATES
pod-s1   1/1     Running   0          20s   10.131.2.6   ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4   <none>           <none>

注意

如果您在其中创建 pod 的项目具有项目节点选择器,则该选择器优先于集群范围节点选择器。如果 pod 没有项目节点选择器,则 pod 不会被创建或调度。

项目节点选择器

使用项目节点选择器时,如果您在此项目中创建 pod,OpenShift Container Platform 会将节点选择器添加到 pod,并将 pod 调度到具有匹配标签的节点。如果存在集群范围默认节点选择器,则以项目节点选择器为准。

例如,以下项目具有 region=east 节点选择器:

Namespace 对象示例

apiVersion: v1
kind: Namespace
metadata:
  name: east-region
  annotations:
    openshift.io/node-selector: "region=east"
...

以下节点具有 type=user-node,region=east 标签:

Node 对象示例

apiVersion: v1
kind: Node
metadata:
  name: ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4
...
  labels:
    region: east
    type: user-node
...

当您使用本例项目中的示例 pod 规格创建 pod 时,pod 会使用项目节点选择器创建,并调度到标记的节点:

Pod 对象示例

apiVersion: v1
kind: Pod
metadata:
  namespace: east-region
...
spec:
  nodeSelector:
    region: east
    type: user-node
...

在标记的节点上带有 pod 的 pod 列表示例

NAME     READY   STATUS    RESTARTS   AGE   IP           NODE                                       NOMINATED NODE   READINESS GATES
pod-s1   1/1     Running   0          20s   10.131.2.6   ci-ln-qg1il3k-f76d1-hlmhl-worker-b-df2s4   <none>           <none>

如果 pod 包含不同的节点选择器,则项目中的 pod 不会被创建或调度。例如,如果您将以下 Pod 部署到示例项目中,则不会创建它:

带有无效节点选择器的 Pod 对象示例

apiVersion: v1
kind: Pod
...

spec:
  nodeSelector:
    region: west

....

3.7.2. 使用节点选择器控制 pod 放置

您可以使用节点上的 pod 和标签上的节点选择器来控制 pod 的调度位置。使用节点选择器时,OpenShift Container Platform 会将 pod 调度到包含匹配标签的节点。

您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

要将节点选择器添加到现有 pod 中,将节点选择器添加到该 pod 的控制对象中,如 ReplicaSet 对象、DaemonSet 对象、StatefulSet 对象、Deployment 对象或 DeploymentConfig 对象。任何属于该控制对象的现有 pod 都会在具有匹配标签的节点上重新创建。如果要创建新 pod,可以将节点选择器直接添加到 Pod 规格中。

注意

您不能直接将节点选择器添加到现有调度的 pod 中。

先决条件

要将节点选择器添加到现有 pod 中,请确定该 pod 的控制对象。例如, router-default-66d5cf9464-m2g75 pod 由 router-default-66d5cf9464 副本集控制:

$ oc describe pod router-default-66d5cf9464-7pwkc

Name:               router-default-66d5cf9464-7pwkc
Namespace:          openshift-ingress

....

Controlled By:      ReplicaSet/router-default-66d5cf9464

Web 控制台在 pod YAML 的 ownerReferences 下列出控制对象:

  ownerReferences:
    - apiVersion: apps/v1
      kind: ReplicaSet
      name: router-default-66d5cf9464
      uid: d81dd094-da26-11e9-a48a-128e7edf0312
      controller: true
      blockOwnerDeletion: true

流程

  1. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 对象向由计算机器集管理的节点添加标签:

      1. 运行以下命令,将标签添加到 MachineSet 对象中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api

        例如:

        $ oc patch MachineSet abc612-msrtw-worker-us-east-1c  --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet 对象中:

        例如:

        $ oc edit MachineSet abc612-msrtw-worker-us-east-1c -n openshift-machine-api

        MachineSet 对象示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        
        ....
        
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node
        ....

    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

        $ oc label nodes <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ip-10-0-142-25.ec2.internal type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            type: "user-node"
            region: "east"
      2. 验证标签是否已添加到节点:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                          STATUS   ROLES    AGE   VERSION
        ip-10-0-142-25.ec2.internal   Ready    worker   17m   v1.25.0

  2. 将匹配的节点选择器添加到 pod:

    • 要将节点选择器添加到现有和未来的 pod,请向 pod 的控制对象添加节点选择器:

      带有标签的 ReplicaSet 对象示例

      kind: ReplicaSet
      
      ....
      
      spec:
      
      ....
      
        template:
          metadata:
            creationTimestamp: null
            labels:
              ingresscontroller.operator.openshift.io/deployment-ingresscontroller: default
              pod-template-hash: 66d5cf9464
          spec:
            nodeSelector:
              kubernetes.io/os: linux
              node-role.kubernetes.io/worker: ''
              type: user-node 1

      1
      添加节点选择器。
    • 要将节点选择器添加到一个特定的新 pod,直接将选择器添加到 Pod 对象中:

      使用节点选择器的 Pod 对象示例

      apiVersion: v1
      kind: Pod
      
      ....
      
      spec:
        nodeSelector:
          region: east
          type: user-node

      注意

      您不能直接将节点选择器添加到现有调度的 pod 中。

3.7.3. 创建默认的集群范围节点选择器

您可以组合使用 pod 上的默认集群范围节点选择器和节点上的标签,将集群中创建的所有 pod 限制到特定节点。

使用集群范围节点选择器时,如果您在集群中创建 pod,OpenShift Container Platform 会将默认节点选择器添加到 pod,并将该 pod 调度到具有匹配标签的节点。

您可以通过编辑调度程序 Operator 自定义资源(CR)来配置集群范围节点选择器。您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

注意

您可以向 pod 添加额外的键/值对。但是,您无法为一个默认的键添加不同的值。

流程

添加默认的集群范围节点选择器:

  1. 编辑调度程序 Operator CR 以添加默认的集群范围节点选择器:

    $ oc edit scheduler cluster

    使用节点选择器的调度程序 Operator CR 示例

    apiVersion: config.openshift.io/v1
    kind: Scheduler
    metadata:
      name: cluster
    ...
    spec:
      defaultNodeSelector: type=user-node,region=east 1
      mastersSchedulable: false

    1
    使用适当的 <key>:<value> 对添加节点选择器。

    完成此更改后,请等待重新部署 openshift-kube-apiserver 项目中的 pod。这可能需要几分钟。只有重新部署 pod 后,默认的集群范围节点选择器才会生效。

  2. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用计算机器集向由计算机器设置管理的节点添加标签:

      1. 运行以下命令,将标签添加到 MachineSet 对象中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api 1
        1
        为每个标识添加 <key>/<value> 对。

        例如:

        $ oc patch MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet 对象中:

        例如:

        $ oc edit MachineSet abc612-msrtw-worker-us-east-1c -n openshift-machine-api

        MachineSet 对象示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
          ...
        spec:
          ...
          template:
            metadata:
          ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node
          ...

      3. 通过缩减至 0 并扩展节点来重新部署与该计算机器集关联的节点:

        例如:

        $ oc scale --replicas=0 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
        $ oc scale --replicas=1 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
      4. 当节点就绪并可用时,使用 oc get 命令验证该标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>

        例如:

        $ oc get nodes -l type=user-node

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp   Ready    worker   61s   v1.25.0

    • 直接向节点添加标签:

      1. 为节点编辑 Node 对象:

        $ oc label nodes <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49 type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            type: "user-node"
            region: "east"
      2. 使用 oc get 命令验证标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>,<key>=<value>

        例如:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49   Ready    worker   17m   v1.25.0

3.7.4. 创建项目范围节点选择器

您可以组合使用项目中的节点选择器和节点上的标签,将该项目中创建的所有 pod 限制到标记的节点。

当您在这个项目中创建 pod 时,OpenShift Container Platform 会将节点选择器添加到项目中 pod,并将 pod 调度到项目中具有匹配标签的节点。如果存在集群范围默认节点选择器,则以项目节点选择器为准。

您可以通过编辑 Namespace 对象来向项目添加节点选择器,以添加 openshift.io/node-selector 参数。您可向节点、计算机器集或机器配置添加标签。将标签添加到计算机器集可确保节点或机器停机时,新节点具有该标签。如果节点或机器停机,添加到节点或机器配置的标签不会保留。

如果 Pod 对象包含节点选择器,则不会调度 pod,但没有项目具有匹配的节点选择器。从该 spec 创建 pod 时,您收到类似以下消息的错误:

错误信息示例

Error from server (Forbidden): error when creating "pod.yaml": pods "pod-4" is forbidden: pod node label selector conflicts with its project node label selector

注意

您可以向 pod 添加额外的键/值对。但是,您无法为一个项目键添加其他值。

流程

添加默认项目节点选择器:

  1. 创建命名空间或编辑现有命名空间,以添加 openshift.io/node-selector 参数:

    $ oc edit namespace <name>

    输出示例

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
        openshift.io/node-selector: "type=user-node,region=east" 1
        openshift.io/description: ""
        openshift.io/display-name: ""
        openshift.io/requester: kube:admin
        openshift.io/sa.scc.mcs: s0:c30,c5
        openshift.io/sa.scc.supplemental-groups: 1000880000/10000
        openshift.io/sa.scc.uid-range: 1000880000/10000
      creationTimestamp: "2021-05-10T12:35:04Z"
      labels:
        kubernetes.io/metadata.name: demo
      name: demo
      resourceVersion: "145537"
      uid: 3f8786e3-1fcb-42e3-a0e3-e2ac54d15001
    spec:
      finalizers:
      - kubernetes

    1
    使用适当的 <key>:<value> 对添加 openshift.io/node-selector
  2. 使用计算机器集或直接编辑节点,为节点添加标签:

    • 在创建节点时,使用 MachineSet 对象向由计算机器集管理的节点添加标签:

      1. 运行以下命令,将标签添加到 MachineSet 对象中:

        $ oc patch MachineSet <name> --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"<key>"="<value>","<key>"="<value>"}}]'  -n openshift-machine-api

        例如:

        $ oc patch MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c --type='json' -p='[{"op":"add","path":"/spec/template/spec/metadata/labels", "value":{"type":"user-node","region":"east"}}]'  -n openshift-machine-api
        提示

        您还可以应用以下 YAML 来向计算机器集中添加标签:

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
          name: <machineset>
          namespace: openshift-machine-api
        spec:
          template:
            spec:
              metadata:
                labels:
                  region: "east"
                  type: "user-node"
      2. 使用 oc edit 命令验证标签是否已添加到 MachineSet 对象中:

        例如:

        $ oc edit MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api

        输出示例

        apiVersion: machine.openshift.io/v1beta1
        kind: MachineSet
        metadata:
        ...
        spec:
        ...
          template:
            metadata:
        ...
            spec:
              metadata:
                labels:
                  region: east
                  type: user-node

      3. 重新部署与该计算机器集关联的节点:

        例如:

        $ oc scale --replicas=0 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
        $ oc scale --replicas=1 MachineSet ci-ln-l8nry52-f76d1-hl7m7-worker-c -n openshift-machine-api
      4. 当节点就绪并可用时,使用 oc get 命令验证该标签是否已添加到节点:

        $ oc get nodes -l <key>=<value>

        例如:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-c-vmqzp   Ready    worker   61s   v1.25.0

    • 直接向节点添加标签:

      1. 编辑 Node 对象以添加标签:

        $ oc label <resource> <name> <key>=<value>

        例如,若要为以下节点添加标签:

        $ oc label nodes ci-ln-l8nry52-f76d1-hl7m7-worker-c-tgq49 type=user-node region=east
        提示

        您还可以应用以下 YAML 来向节点添加标签:

        kind: Node
        apiVersion: v1
        metadata:
          name: <node_name>
          labels:
            type: "user-node"
            region: "east"
      2. 使用 oc get 命令验证标签是否已添加到 Node 对象中:

        $ oc get nodes -l <key>=<value>

        例如:

        $ oc get nodes -l type=user-node,region=east

        输出示例

        NAME                                       STATUS   ROLES    AGE   VERSION
        ci-ln-l8nry52-f76d1-hl7m7-worker-b-tgq49   Ready    worker   17m   v1.25.0

3.8. 使用 pod 拓扑分布限制控制 pod 放置

您可以使用 pod 拓扑分布约束来控制 pod 在节点、区、区域或其他用户定义的拓扑域间的放置。

3.8.1. 关于 pod 拓扑分布限制

通过使用 pod 拓扑分布约束,您可以对故障域中的 pod 分布提供精细的控制,以帮助实现高可用性和更有效的资源使用。

OpenShift Container Platform 管理员可以标记节点以提供拓扑信息,如区域、区、节点或其他用户定义域。在节点上设置了这些标签后,用户才能定义 pod 拓扑分布约束,以控制 pod 在这些拓扑域中的放置。

您可以指定哪些 pod 要分组在一起,它们分散到哪些拓扑域以及可以接受的基点。只有同一命名空间中的 pod 在因为约束而分散时才会被匹配和分组。

3.8.2. 配置 pod 拓扑分布限制

以下步骤演示了如何配置 pod 拓扑扩展约束,以根据区分配与指定标签匹配的 pod。

您可以指定多个 pod 拓扑分散约束,但您必须确保它们不会相互冲突。必须满足所有 pod 拓扑分布约束才能放置 pod。

先决条件

  • 集群管理员已将所需的标签添加到节点。

流程

  1. 创建 Pod spec 并指定 pod 拓扑分散约束:

    pod-spec.yaml 文件示例

    apiVersion: v1
    kind: Pod
    metadata:
      name: my-pod
      labels:
        foo: bar
    spec:
      topologySpreadConstraints:
      - maxSkew: 1 1
        topologyKey: topology.kubernetes.io/zone 2
        whenUnsatisfiable: DoNotSchedule 3
        labelSelector: 4
          matchLabels:
            foo: bar 5
      containers:
      - image: "docker.io/ocpqe/hello-pod"
        name: hello-pod

    1
    两个拓扑域间的 pod 数量的最大差别。默认为 1,您不能指定 0 值。
    2
    节点标签的密钥。具有此键和相同值的节点被视为在同一拓扑中。
    3
    如果不满足分布式约束,如何处理 pod。默认为 DoNotSchedule,它会告诉调度程序不要调度 pod。设置为 ScheduleAnyway,它仍然会调度 pod,但调度程序会优先考虑 skew 的根据情况以使集群不要出现不平衡的情况。
    4
    匹配此标签选择器的 Pod 在分发时被计算并识别为组,以满足约束要求。确保指定标签选择器,否则就无法匹配 pod。
    5
    如果您希望以后正确计数此 Pod 规格,请确保此 Pod spec 也会设置其标签选择器来匹配这个标签选择器。
  2. 创建 pod:

    $ oc create -f pod-spec.yaml

3.8.3. pod 拓扑分布限制示例

以下示例演示了 pod 拓扑分散约束配置。

3.8.3.1. 单个 pod 拓扑分布约束示例

Pod spec 示例定义了一个 pod 拓扑分散约束。它与标记为 foo:bar 的 pod 匹配,在区间分布,指定 skew 1,并在不满足这些要求时不调度 pod。

kind: Pod
apiVersion: v1
metadata:
  name: my-pod
  labels:
    foo: bar
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  containers:
  - image: "docker.io/ocpqe/hello-pod"
    name: hello-pod

3.8.3.2. 多个 pod 拓扑分布约束示例

Pod spec 示例定义了两个 pod 拓扑分布限制。标签为 foo:bar 的 pod 上的匹配,指定为 skew 1,并在不满足这些要求时不调度 pod。

第一个限制基于用户定义的标签 node 发布 pod,第二个约束根据用户定义的标签 rack 分发 pod。调度 pod 必须满足这两个限制。

kind: Pod
apiVersion: v1
metadata:
  name: my-pod-2
  labels:
    foo: bar
spec:
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: node
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  - maxSkew: 1
    topologyKey: rack
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        foo: bar
  containers:
  - image: "docker.io/ocpqe/hello-pod"
    name: hello-pod

3.8.4. 其他资源

3.9. 使用 descheduler 驱除 pod

调度程序(scheduler)被用来决定最适合托管新 pod 的节点,而 descheduler 可以用来驱除正在运行的 pod,从而使 pod 能够重新调度到更合适的节点上。

3.9.1. 关于 descheduler

您可以使用 descheduler 根据特定策略驱除 pod,以便可将 pod 重新调度到更合适的节点上。

descheduler 适合于在以下情况下 处理运行的 pod:

  • 节点使用不足或过度使用。
  • Pod 和节点关联性要求(如污点或标签)已更改,并且原始的调度不再适合于某些节点。
  • 节点失败需要移动 pod。
  • 集群中添加了新节点。
  • Pod 重启的次数太多。
重要

descheduler 不调度被驱除的 pod。调度被驱除 pod 的任务由调度程序(scheduler)执行。

当 descheduler 决定从节点驱除 pod 时,它会使用以下机制:

  • openshift-*kube-system 命名空间中的 Pod 不会被驱除。
  • priorityClassName 被设置为 system-cluster-criticalsystem-node-critical 的关键 pod 不会被驱除。
  • 不属于复制控制器、副本集、部署或作业一部分的静态、镜像或独立 pod 不会被驱除,因为这些 pod 不会被重新创建。
  • 与守护进程集关联的 pod 不会被驱除。
  • 具有本地存储的 Pod 不会被驱除。
  • BestEffort pod 会在 Burstable 和 Guaranteed pod 之前被驱除。
  • 具有 descheduler.alpha.kubernetes.io/evict 注解的所有 pod 类型都可以被驱除。此注解用于覆盖防止驱除的检查,用户可以选择驱除哪些 pod。用户应该知道如何创建 pod 以及是否重新创建 pod。
  • 对于受 Pod Disruption Budget (PDB) 限制的 pod,如果进行 deschedule 会违反 Pod disruption budget (PDB),则 pod 不会被驱除。通过使用驱除子资源来处理 PDB 来驱除 pod 。

3.9.2. Descheduler 配置集

以下 descheduler 配置集可用:

AffinityAndTaints

此配置集驱除违反了 pod 间的反关联性、节点关联性和节点污点的 pod。

它启用了以下策略:

  • RemovePodsViolatingInterPodAntiAffinity:删除违反了 pod 间的反关联性的 pod。
  • RemovePodsViolatingNodeAffinity:移除违反了节点关联性的 pod。
  • RemovePodsViolatingNodeTaints:移除违反了节点上的 NoSchedule 污点的 pod。

    移除具有节点关联性类型 requiredDuringSchedulingIgnoredDuringExecution的 pod。

TopologyAndDuplicates

此配置集会驱除 pod 以努力在节点间平均分配类似的 pod 或相同拓扑域的 pod。

它启用了以下策略:

  • RemovePodsViolatingTopologySpreadConstraint:找到未平衡的拓扑域,并在 DoNotSchedule 约束被违反时尝试从较大的 pod 驱除 pod。
  • RemoveDuplicates:确保只有一个 pod 与同一节点上运行的副本集、复制控制器、部署或作业相关联。如果存在多个重复的 pod,则这些重复的 pod 会被驱除以更好地在集群中的 pod 分布。
LifecycleAndUtilization

此配置集驱除长时间运行的 pod,并平衡节点之间的资源使用情况。

它启用了以下策略:

  • RemovePodsHavingTooManyRestarts :删除容器重启了多次的 pod。

    在所有容器(包括初始容器)中被重启的总数超过 100 次的 Pod 。

  • LowNodeUtilization:查找使用率不足的节点,并在可能的情况下从其他过度使用的节点中驱除 pod,以希望这些被驱除的 pod 可以在使用率低的节点上被重新创建。

    如果节点的用量低于 20%(CPU、内存和 pod 的数量),则该节点将被视为使用率不足。

    如果节点的用量超过 50%(CPU、内存和 pod 的数量),则该节点将被视为过量使用。

  • PodLifeTime:驱除太老的 pod。

    默认情况下,会删除超过 24 小时的 pod。您可以自定义 pod 生命周期值。

SoftTopologyAndDuplicates

这个配置集与 TopologyAndDuplicates 相同,不同之处在于具有软拓扑约束的 pod(如 whenUnsatisfiable: ScheduleAnyway )也被视为驱除。

注意

不要同时启用 SoftTopologyAndDuplicatesTopologyAndDuplicates。启用两者会导致冲突。

EvictPodsWithLocalStorage
此配置集允许具有本地存储的 pod 有资格被驱除。
EvictPodsWithPVC
此配置集允许带有持久性卷声明的 pod 有资格驱除。如果使用 Kubernetes NFS Subdir External Provisioner,您必须为安装置备程序的命名空间添加排除的命名空间。

3.9.3. 安装 descheduler

在默认情况下,不提供 descheduler。要启用 descheduler,您必须从 OperatorHub 安装 Kube Descheduler Operator,并启用一个或多个 descheduler 配置集。

默认情况下,descheduler 以预测模式运行,这意味着它只模拟 pod 驱除。您必须将 descheduler 的模式更改为自动进行 pod 驱除。

重要

如果您在集群中启用了托管的 control plane,设置自定义优先级阈值,以降低托管 control plane 命名空间中的 pod 被驱除。将优先级阈值类名称设置为 hypershift-control-plane,因为它有托管的 control plane 优先级类的最低优先级值(100000000)。

先决条件

  • 必须具有集群管理员权限。
  • 访问 OpenShift Container Platform Web 控制台。

流程

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 为 Kube Descheduler Operator 创建所需的命名空间。

    1. 进行 AdministrationNamespaces,点 Create Namespace
    2. Name 字段中输入 openshift-kube-descheduler-operator,在 Labels 字段中输入 openshift.io/cluster-monitoring=true 来启用 descheduler 指标,然后点击 Create
  3. 安装 Kube Descheduler Operator。

    1. 进入 OperatorsOperatorHub
    2. 在过滤框中输入 Kube Descheduler Operator
    3. 选择 Kube Descheduler Operator 并点 Install
    4. Install Operator 页面中,选择 A specific namespace on the cluster。从下拉菜单中选择 openshift-kube-descheduler-operator
    5. Update ChannelApproval Strategy 的值调整为所需的值。
    6. 点击 Install
  4. 创建 descheduler 实例。

    1. OperatorsInstalled Operators 页面中,点 Kube Descheduler Operator
    2. 选择 Kube Descheduler 标签页并点 Create KubeDescheduler
    3. 根据需要编辑设置。

      1. 要驱除 pod 而不是模拟驱除,请将 Mode 字段更改为 Automatic
      2. 展开 Profiles 部分,以选择要启用的一个或多个配置集。AffinityAndTaints 配置集默认为启用。点 Add Profile 选择附加配置集。

        注意

        不要同时启用 TopologyAndDuplicatesSoftTopologyAndDuplicates。启用两者会导致冲突。

      3. 可选:展开 Profile Customizations 部分,设置 descheduler 的可选配置。

        • LifecycleAndUtilization 配置集设置自定义 pod 生命周期值。使用 podLifetime 字段设置数字值和一个有效单元(smh)。默认 pod 生命周期为 24 小时(24h)。
        • 设置自定义优先级阈值,使其仅在优先级低于指定优先级级别时才会考虑 pod 进行驱除。使用 thresholdPriority 字段设置数字优先级阈值,或者使用 thresholdPriorityClassName 字段指定特定的优先级类名称。

          注意

          不要为 descheduler 指定 thresholdPrioritythresholdPriorityClassName

        • 将特定的命名空间设置为包括在或排除在 descheduler 操作中。展开 namespaces 字段,并将命名空间添加到 excludedincluded 列表中。您只能设置要排除的命名空间列表或要包含的命名空间列表。请注意,默认排除受保护的命名空间(openshift-*kube-systemhypershift)。

          重要

          LowNodeUtilization 策略不支持命名空间排除。如果设置了 LifecycleAndUtilization 配置集,它启用了 LowNodeUtilization 策略,则不会排除任何命名空间,即使受保护的命名空间也是如此。为了避免在启用 LowNodeUtilization 策略时从受保护的命名空间中驱除,请将优先级类名称设置为 system-cluster-criticalsystem-node-critical

        • 实验性:为 LowNodeUtilization 策略设置利用不足和过度利用的阈值。使用 devLowNodeUtilizationThresholds 字段设置以下值之一:

          • Low: 10% 低利用,30% 过渡利用
          • Medium: 20% 低利用,50% 过渡利用(默认)
          • High: 40% 低利用,70% 过渡利用
          注意

          这个设置是实验性的,不应在生产环境中使用。

      4. 可选: 使用 Descheduling Interval Seconds 字段更改 descheduler 运行间隔的秒数。默认值为 3600 秒。
    4. Create

您还可以稍后使用 OpenShift CLI(oc)为 descheduler 配置配置集和设置。如果您在从 web 控制台创建 descheduler 实例时没有调整配置集,则默认启用 AffinityAndTaints 配置集。

3.9.4. 配置 descheduler 配置集

您可以配置 descheduler 使用哪些配置集来驱除 pod。

先决条件

  • 集群管理员特权

流程

  1. 编辑 KubeDescheduler 对象:

    $ oc edit kubedeschedulers.operator.openshift.io cluster -n openshift-kube-descheduler-operator
  2. spec.profiles 部分指定一个或多个配置集。

    apiVersion: operator.openshift.io/v1
    kind: KubeDescheduler
    metadata:
      name: cluster
      namespace: openshift-kube-descheduler-operator
    spec:
      deschedulingIntervalSeconds: 3600
      logLevel: Normal
      managementState: Managed
      operatorLogLevel: Normal
      mode: Predictive                                     1
      profileCustomizations:
        namespaces:                                        2
          excluded:
          - my-namespace
        podLifetime: 48h                                   3
        thresholdPriorityClassName: my-priority-class-name 4
      profiles:                                            5
      - AffinityAndTaints
      - TopologyAndDuplicates                              6
      - LifecycleAndUtilization
      - EvictPodsWithLocalStorage
      - EvictPodsWithPVC
    1
    可选:默认情况下,descheduler 不会驱除 pod。要驱除 pod,请将 mode 设置为 Automatic
    2
    可选:设置用户创建命名空间列表,以便从 descheduler 操作中包含或排除。使用 exclude 设置要排除的命名空间列表,或者使用 included 来设置要包含的命名空间列表。请注意,默认排除受保护的命名空间(openshift-*kube-systemhypershift)。
    重要

    LowNodeUtilization 策略不支持命名空间排除。如果设置了 LifecycleAndUtilization 配置集,它启用了 LowNodeUtilization 策略,则不会排除任何命名空间,即使受保护的命名空间也是如此。为了避免在启用 LowNodeUtilization 策略时从受保护的命名空间中驱除,请将优先级类名称设置为 system-cluster-criticalsystem-node-critical

    3
    可选:为 LifecycleAndUtilization 配置集启用自定义 pod 生命周期值。有效单位是 smh。默认 pod 生命周期为 24 小时。
    4
    可选:指定优先级阈值,仅在优先级低于指定级别时才会考虑 pod 进行驱除。使用 thresholdPriority 字段设置数字优先级阈值(如 10000)或者使用 thresholdPriorityClassName 字段指定特定的优先级类名称(如 my-priority-class-name)。如果指定优先级类名称,则必须已存在它,否则 descheduler 会抛出错误。不要同时设置 thresholdPrioritythresholdPriorityClassName
    5
    添加一个或多个配置文件以启用。可用配置集:AffinityAndTaintsTopologyAndDuplicatesLifecycleAndUtilizationSoftTopologyAndDuplicatesEvictPodsWithLocalStorageEvictPodsWithPVC
    6
    不要同时启用 TopologyAndDuplicatesSoftTopologyAndDuplicates。启用两者会导致冲突。

    您可以启用多个配置集 ; 指定配置集的顺序并不重要。

  3. 保存文件以使改变生效。

3.9.5. 配置 descheduler 间隔

您可以配置 descheduler 运行之间的时间长度。默认为 3600 秒(一小时)。

先决条件

  • 集群管理员特权

流程

  1. 编辑 KubeDescheduler 对象:

    $ oc edit kubedeschedulers.operator.openshift.io cluster -n openshift-kube-descheduler-operator
  2. deschedulingIntervalSeconds 字段更新为所需的值:

    apiVersion: operator.openshift.io/v1
    kind: KubeDescheduler
    metadata:
      name: cluster
      namespace: openshift-kube-descheduler-operator
    spec:
      deschedulingIntervalSeconds: 3600 1
    ...
    1
    设置 descheduler 运行间隔的秒数。如果设为 0,则 descheduler 会运行一次并退出。
  3. 保存文件以使改变生效。

3.9.6. 卸载 descheduler

您可以通过删除 descheduler 实例并卸载 Kube Descheduler Operator 从集群中移除 descheduler。此流程还会清理 KubeDescheduler CRD 和 openshift-kube-descheduler-operator 命名空间。

先决条件

  • 必须具有集群管理员权限。
  • 访问 OpenShift Container Platform Web 控制台。

流程

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 删除 descheduler 实例。

    1. OperatorsInstalled Operators 页面中,点 Kube Descheduler Operator
    2. 选择 Kube Descheduler 选项卡。
    3. 集群 条目旁的 Options 菜单 kebab 并选择 Delete KubeDescheduler
    4. 在确认对话框中,点 Delete
  3. 卸载 Kube Descheduler Operator。

    1. 导航到 OperatorsInstalled Operators
    2. Kube Descheduler Operator 条目 kebab 旁边的 Options 菜单,然后选择 Uninstall Operator
    3. 在确认对话框中,点 Uninstall
  4. 删除 openshift-kube-descheduler-operator 命名空间。

    1. 导航至 AdministrationNamespaces
    2. 在过滤器框中输入 openshift-kube-descheduler-operator
    3. openshift-kube-descheduler-operator 条目旁的 Options 菜单 kebab ,然后选择 Delete Namespace
    4. 在确认对话框中,输入 openshift-kube-descheduler-operator 并点 Delete
  5. 删除 KubeDescheduler CRD。

    1. 进入 AdministrationCustom Resource Definitions
    2. 在过滤器框中输入 KubeDescheduler
    3. KubeDescheduler 条目旁的 Options 菜单 kebab ,然后选择 Delete CustomResourceDefinition
    4. 在确认对话框中,点 Delete

3.10. 二级调度程序

3.10.1. 二级调度程序概述

您可以安装 Secondary Scheduler Operator 来运行自定义二级调度程序,以及调度 pod 的默认调度程序。

3.10.1.1. 关于 Secondary Scheduler Operator

Red Hat OpenShift 的 Secondary Scheduler Operator 提供了在 OpenShift Container Platform 中部署自定义二级调度程序的方法。二级调度程序与默认调度程序一起运行,以调度 pod。Pod 配置可指定要使用的调度程序。

自定义调度程序必须具有 /bin/kube-scheduler 二进制文件,并基于 Kubernetes 调度框架

重要

您可以使用 Secondary Scheduler Operator 在 OpenShift Container Platform 中部署自定义二级调度程序,但红帽不直接支持自定义二级调度程序的功能。

Secondary Scheduler Operator 创建二级调度程序所需的默认角色和角色绑定。您可以通过为从属调度程序配置 KubeSchedulerConfiguration 资源,来指定哪些调度插件来启用或禁用。

3.10.2. Secondary Scheduler Operator for Red Hat OpenShift 发行注记

Red Hat OpenShift 的 Secondary Scheduler Operator 允许您在 OpenShift Container Platform 集群中部署自定义二级调度程序。

本发行注记介绍了针对 Red Hat OpenShift 的 Secondary Scheduler Operator 的开发。

如需更多信息,请参阅关于 Secondary Scheduler Operator

3.10.2.1. Red Hat OpenShift 1.1.0 的 Secondary Scheduler Operator 发行注记

<hiddendate>Issued: 2022-9-1</hiddendate>

以下公告可用于 Red Hat OpenShift 1.1.0 的 Secondary Scheduler Operator:

3.10.2.1.1. 新功能及功能增强
3.10.2.1.2. 已知问题
  • 目前,您无法通过 Secondary Scheduler Operator 部署其他资源,如配置映射、CRD 或 RBAC 策略。自定义二级调度程序所需的角色和角色绑定以外的任何资源都必须外部应用。(BZ#2071684)

3.10.3. 使用二级调度程序调度 pod

您可以通过安装 Secondary Scheduler Operator、部署二级调度程序,并在 pod 定义中设置二级调度程序,在 OpenShift Container Platform 中运行自定义次要调度程序。

3.10.3.1. 安装 Secondary Scheduler Operator

您可以使用 Web 控制台为 Red Hat OpenShift 安装 Secondary Scheduler Operator。

先决条件

  • 您可以使用 cluster-admin 权限访问集群。
  • 访问 OpenShift Container Platform web 控制台。

流程

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 为 Red Hat OpenShift 创建 Secondary Scheduler Operator 所需的命名空间。

    1. 进行 AdministrationNamespaces,点 Create Namespace
    2. Name 字段中输入 openshift-secondary-scheduler-operator,再点 Create
  3. 为 Red Hat OpenShift 安装 Secondary Scheduler Operator。

    1. 导航至 OperatorsOperatorHub
    2. 在过滤器框中输入 Secondary Scheduler Operator for Red Hat OpenShift
    3. 选择 Secondary Scheduler Operator for Red Hat OpenShift 并点 Install
    4. Install Operator 页面中:

      1. Update channel 设置为 stable,它将为 Red Hat OpenShift 安装 Secondary Scheduler Operator 的最新稳定版本。
      2. 选择 A specific namespace on the cluster,并从下拉菜单中选择 openshift-secondary-scheduler-operator
      3. 选择一个 更新批准策略

        • Automatic 策略允许 Operator Lifecycle Manager(OLM)在有新版本可用时自动更新 Operator。
        • Manual 策略需要拥有适当凭证的用户批准 Operator 更新。
      4. Install

验证

  1. 导航到 OperatorsInstalled Operators
  2. 验证 Secondary Scheduler Operator for Red Hat OpenShift 已列出,StatusSucceeded

3.10.3.2. 部署二级调度程序

安装 Secondary Scheduler Operator 后,您可以部署二级调度程序。

先决条件

  • 您可以使用 cluster-admin 权限访问集群。
  • 访问 OpenShift Container Platform web 控制台。
  • 安装了 Secondary Scheduler Operator for Red Hat OpenShift。

步骤

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 创建配置映射来保存二级调度程序的配置。

    1. 进入 WorkloadsConfigMaps
    2. Create ConfigMap
    3. 在 YAML 编辑器中,输入包含必要 KubeSchedulerConfiguration 配置的配置映射定义。例如:

      apiVersion: v1
      kind: ConfigMap
      metadata:
        name: "secondary-scheduler-config"                  1
        namespace: "openshift-secondary-scheduler-operator" 2
      data:
        "config.yaml": |
          apiVersion: kubescheduler.config.k8s.io/v1beta3
          kind: KubeSchedulerConfiguration                  3
          leaderElection:
            leaderElect: false
          profiles:
            - schedulerName: secondary-scheduler            4
              plugins:                                      5
                score:
                  disabled:
                    - name: NodeResourcesBalancedAllocation
                    - name: NodeResourcesLeastAllocated
      1
      配置映射的名称。这将在创建 SecondaryScheduler CR 时,在 Scheduler Config 字段中使用。
      2
      配置映射必须在 openshift-secondary-scheduler-operator 命名空间中创建。
      3
      二级调度程序的 KubeSchedulerConfiguration 资源。如需更多信息,请参阅 Kubernetes API 文档中的 KubeSchedulerConfiguration
      4
      二级调度程序的名称。将其 spec.schedulerName 字段设置为此值的 Pod 会使用这个二级调度程序来调度。
      5
      为二级调度程序启用或禁用插件。如需列出默认调度插件,请参阅 Kubernetes 文档中的 调度插件
    4. Create
  3. 创建 SecondaryScheduler CR:

    1. 导航到 OperatorsInstalled Operators
    2. 选择 Secondary Scheduler Operator for Red Hat OpenShift
    3. 选择 Secondary Scheduler 选项卡,然后点 Create SecondaryScheduler
    4. Name 字段默认为 cluster; 不要更改此名称。
    5. Scheduler Config 字段默认为 secondary-scheduler-config。确保这个值与此流程中创建的配置映射的名称匹配。
    6. Scheduler Image 字段中,输入自定义调度程序的镜像名称。

      重要

      红帽不直接支持自定义二级调度程序的功能。

    7. Create

3.10.3.3. 使用二级调度程序调度 pod

要使用二级调度程序调度 pod,请在 pod 定义中设置 schedulerName 字段。

先决条件

  • 您可以使用 cluster-admin 权限访问集群。
  • 访问 OpenShift Container Platform web 控制台。
  • 安装了 Secondary Scheduler Operator for Red Hat OpenShift。
  • 配置了二级调度程序。

步骤

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 导航到 WorkloadsPods
  3. Create Pod
  4. 在 YAML 编辑器中,输入所需的 pod 配置并添加 schedulerName 字段:

    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      namespace: default
    spec:
      containers:
        - name: nginx
          image: nginx:1.14.2
          ports:
            - containerPort: 80
      schedulerName: secondary-scheduler 1
    1
    在配置二级调度程序时,schedulerName 字段必须与配置映射中定义的名称匹配。
  5. Create

验证

  1. 登录到 OpenShift CLI。
  2. 使用以下命令描述 pod:

    $ oc describe pod nginx -n default

    输出示例

    Name:         nginx
    Namespace:    default
    Priority:     0
    Node:         ci-ln-t0w4r1k-72292-xkqs4-worker-b-xqkxp/10.0.128.3
    ...
    Events:
      Type    Reason          Age   From                 Message
      ----    ------          ----  ----                 -------
      Normal  Scheduled       12s   secondary-scheduler  Successfully assigned default/nginx to ci-ln-t0w4r1k-72292-xkqs4-worker-b-xqkxp
    ...

  3. 在事件表中,找到带有与 Successfully assigned <namespace>/<pod_name> to <node_name> 类似消息的事件。
  4. 在 "From" 列中,验证事件是从二级调度程序生成的,而不是默认调度程序。

    注意

    您还可以检查 openshift-secondary-scheduler-namespace 中的 secondary-scheduler-* pod 日志,以验证 pod 是否已由二级调度程序调度。

3.10.4. 卸载 Secondary Scheduler Operator

您可以通过卸载 Operator 并删除其相关资源,从 OpenShift Container Platform 中删除 Red Hat OpenShift 的 Secondary Scheduler Operator。

3.10.4.1. 卸载 Secondary Scheduler Operator

您可以使用 Web 控制台为 Red Hat OpenShift 卸载 Secondary Scheduler Operator。

先决条件

  • 您可以使用 cluster-admin 权限访问集群。
  • 访问 OpenShift Container Platform web 控制台。
  • 安装了 Secondary Scheduler Operator for Red Hat OpenShift。

步骤

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 为 Red Hat OpenShift Operator 卸载 Secondary Scheduler Operator。

    1. 导航到 OperatorsInstalled Operators
    2. Secondary Scheduler Operator 条目旁边的 Options 菜单 kebab ,并点 Uninstall Operator
    3. 在确认对话框中,点 Uninstall

3.10.4.2. 删除 Secondary Scheduler Operator 资源

另外,在为 Red Hat OpenShift 卸载 Secondary Scheduler Operator 后,您可以从集群中移除其相关资源。

先决条件

  • 您可以使用 cluster-admin 权限访问集群。
  • 访问 OpenShift Container Platform web 控制台。

流程

  1. 登陆到 OpenShift Container Platform Web 控制台。
  2. 删除由 Secondary Scheduler Operator 安装的 CRD:

    1. 进入到 AdministrationCustomResourceDefinitions
    2. Name 字段中输入 SecondaryScheduler 以过滤 CRD。
    3. SecondaryScheduler CRD 旁边的 Options 菜单 kebab 并选择 Delete Custom Resource Definition:
  3. 删除 openshift-secondary-scheduler-operator 命名空间。

    1. 导航至 AdministrationNamespaces
    2. openshift-secondary-scheduler-operator 旁边的 Options 菜单 kebab 并选择 Delete Namespace
    3. 在确认对话框中,在字段中输入 openshift-secondary-scheduler-operator,再点 Delete

第 4 章 使用作业和 DaemonSet

4.1. 使用 daemonset 在节点上自动运行后台任务

作为管理员,您可以创建并使用守护进程集在 OpenShift Container Platform 集群的特定节点或所有节点上运行 pod 副本。

守护进程集确保所有(或部分)节点都运行 pod 的副本。当节点添加到集群中时,pod 也会添加到集群中。当节点从集群中移除时,这些 pod 也会通过垃圾回收而被移除。删除守护进程集会清理它创建的 pod。

您可以使用 daemonset 创建共享存储,在集群的每一节点上运行日志 pod,或者在每个节点上部署监控代理。

为安全起见,集群管理员和项目管理员可以创建守护进程集。

如需有关守护进程集的更多信息,请参阅 Kubernetes 文档

重要

守护进程集调度与项目的默认节点选择器不兼容。如果您没有禁用它,守护进程集会与默认节点选择器合并,从而受到限制。这会造成在合并后节点选择器没有选中的节点上频繁地重新创建 pod,进而给集群带来意外的负载。

4.1.1. 通过默认调度程序调度

守护进程集确保所有有资格的节点都运行 pod 的副本。通常,Kubernetes 调度程序会选择要在其上运行 pod 的节点。但是,以前守护进程集 pod 由守护进程集控制器创建并调度。这会引发以下问题:

  • pod 行为不一致:等待调度的普通 pod 被创建好并处于待处理状态,但守护进程集 pod 没有以待处理的状态创建。这会给用户造成混淆。
  • Pod 抢占由默认调度程序处理。启用抢占后,守护进程集控制器将在不考虑 pod 优先级和抢占的前提下做出调度决策。

OpenShift Container Platform 中默认启用 ScheduleDaemonSetPods 功能允许您使用默认调度程序而不是守护进程集控制器来调度守护进程集,具体方法是添加 NodeAffinity 术语到守护进程集 pod,而不是 .spec.nodeName 术语。然后,默认调度程序用于将 pod 绑定到目标主机。如果守护进程集的节点关联性已经存在,它会被替换掉。守护进程设置控制器仅在创建或修改守护进程集 pod 时执行这些操作,且不会对守护进程集的 spec.template 进行任何更改。

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

另外,node.kubernetes.io/unschedulable:NoSchedule 容限会自动添加到守护进程设置 Pod 中。在调度守护进程设置 pod 时,默认调度程序会忽略不可调度的节点。

4.1.2. 创建 daemonset

在创建守护进程集时,使用 nodeSelector 字段来指示守护进程集应在其上部署副本的节点。

先决条件

  • 在开始使用守护进程集之前,通过将命名空间注解 openshift.io/node-selector 设置为空字符串来禁用命名空间中的默认项目范围节点选择器:

    $ oc patch namespace myproject -p \
        '{"metadata": {"annotations": {"openshift.io/node-selector": ""}}}'
    提示

    您还可以应用以下 YAML 来为命名空间禁用默认的项目范围节点选择器:

    apiVersion: v1
    kind: Namespace
    metadata:
      name: <namespace>
      annotations:
        openshift.io/node-selector: ''
  • 如果您要创建新项目,请覆盖默认节点选择器:

    $ oc adm new-project <name> --node-selector=""

流程

创建守护进程集:

  1. 定义守护进程集 yaml 文件:

    apiVersion: apps/v1
    kind: DaemonSet
    metadata:
      name: hello-daemonset
    spec:
      selector:
          matchLabels:
            name: hello-daemonset 1
      template:
        metadata:
          labels:
            name: hello-daemonset 2
        spec:
          nodeSelector: 3
            role: worker
          containers:
          - image: openshift/hello-openshift
            imagePullPolicy: Always
            name: registry
            ports:
            - containerPort: 80
              protocol: TCP
            resources: {}
            terminationMessagePath: /dev/termination-log
          serviceAccount: default
          terminationGracePeriodSeconds: 10
    1
    决定哪些 pod 属于守护进程集的标签选择器。
    2
    pod 模板的标签选择器。必须与上述标签选择器匹配。
    3
    决定应该在哪些节点上部署 pod 副本的节点选择器。节点上必须存在匹配的标签。
  2. 创建守护进程集对象:

    $ oc create -f daemonset.yaml
  3. 验证 pod 是否已创建好,并且每个节点都有 pod 副本:

    1. 查找 daemonset pod:

      $ oc get pods

      输出示例

      hello-daemonset-cx6md   1/1       Running   0          2m
      hello-daemonset-e3md9   1/1       Running   0          2m

    2. 查看 pod 以验证 pod 已放置到节点上:

      $ oc describe pod/hello-daemonset-cx6md|grep Node

      输出示例

      Node:        openshift-node01.hostname.com/10.14.20.134

      $ oc describe pod/hello-daemonset-e3md9|grep Node

      输出示例

      Node:        openshift-node02.hostname.com/10.14.20.137

重要
  • 如果更新守护进程设置的 pod 模板,现有的 pod 副本不会受到影响。
  • 如果您删除了守护进程集,然后在创建新守护进程集时使用不同的模板和相同的标签选择器,它会将现有 pod 副本识别为具有匹配的标签,因而不更新它们,也不会创建新的副本,尽管 pod 模板中存在不匹配。
  • 如果您更改了节点标签,守护进程集会把 pod 添加到与新标签匹配的节点,并从不匹配新标签的节点中删除 pod。

要更新守护进程集,请通过删除旧副本或节点来强制创建新的 pod 副本。

4.2. 使用任务在 Pod 中运行任务

作业(job)在 OpenShift Container Platform 集群中执行某项任务。

作业会跟踪任务的整体进度,并使用活跃、成功和失败 pod 的相关信息来更新其状态。删除作业会清理它创建的所有 pod 副本。作业是 Kubernetes API 的一部分,可以像其他对象类型一样通过 oc 命令进行管理。

作业规格示例

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  parallelism: 1    1
  completions: 1    2
  activeDeadlineSeconds: 1800 3
  backoffLimit: 6   4
  template:         5
    metadata:
      name: pi
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: OnFailure    6

1
作业应并行运行的 pod 副本 。
2
pod 成功完成后需要标记为作业也完成。
3
作业可以运行的最长时间。
4
作业的重试次数。
5
控制器创建的 pod 模板。
6
pod 的重启策略。

如需有关作业的更多信息,请参阅 Kubernetes 文档

4.2.1. 了解作业和 cron 作业

作业会跟踪任务的整体进度,并使用活跃、成功和失败 pod 的相关信息来更新其状态。删除作业会清理它创建的所有 pod。作业是 Kubernetes API 的一部分,可以像其他对象类型一样通过 oc 命令进行管理。

OpenShift Container Platform 中有两种资源类型可以创建只运行一次的对象:

作业
常规作业是一种只运行一次的对象,它会创建一个任务并确保作业完成。

有三种适合作为作业运行的任务类型:

  • 非并行作业:

    • 仅启动一个 pod 的作业,除非 pod 失败。
    • 一旦 pod 成功终止,作业就会马上完成。
  • 带有固定完成计数的并行作业:

    • 启动多个 pod 的作业。
    • Job 代表整个任务,并在 1completions 范围内的每个值都有一个成功 pod 时完成 。
  • 带有工作队列的并行作业:

    • 在一个给定 pod 中具有多个并行 worker 进程的作业。
    • OpenShift Container Platform 协调 pod,以确定每个 pod 都应该使用什么作业,或使用一个外部队列服务。
    • 每个 pod 都可以独立决定是否所有对等 pod 都已完成(整个作业完成)。
    • 当所有来自作业的 pod 都成功终止时,不会创建新的 pod。
    • 当至少有一个 pod 成功终止并且所有 pod 都终止时,作业成功完成。
    • 当任何 pod 成功退出时,其他 pod 都不应该为这个任务做任何工作或写任何输出。Pod 都应该处于退出过程中。

如需有关如何使用不同类型的作业的更多信息,请参阅 Kubernetes 文档中的作业模式

Cron job
通过使用 Cron Job,一个作业可以被调度为运行多次。

Cron Job 基于常规作业构建,允许您指定作业的运行方式。Cron job 是 Kubernetes API 的一部分,可以像其他对象类型一样通过 oc 命令进行管理。

Cron Job 可用于创建周期性和重复执行的任务,如运行备份或发送电子邮件。Cron Job 也可以将个别任务调度到指定时间执行,例如,将一个作业调度到低活动时段执行。一个 cron 作业会创建一个 Job 对象,它基于在运行 cronjob 的 control plane 节点上配置的时区。

警告

Cron Job 大致会在调度的每个执行时间创建一个 Job 对象,但在有些情况下,它可能无法创建作业,或者可能会创建两个作业。因此,作业必须具有幂等性,而且您必须配置历史限制。

4.2.1.1. 了解如何创建作业

两种资源类型都需要一个由以下关键部分组成的作业配置:

  • pod 模板,用于描述 OpenShift Container Platform 创建的 pod。
  • parallelism 参数,用于指定在任意时间点上应并行运行多少个 pod 来执行某个作业。

    • 对于非并行作业,请保留未设置。当取消设置时,默认为 1
  • completions 参数,用于指定需要成功完成多少个 pod 才能完成某个作业。

    • 对于非并行作业,请保留未设置。当取消设置时,默认为 1
    • 对于带有固定完成计数的并行作业,请指定一个值。
    • 对于带有工作队列的并行作业,请保留 unset。当取消设置默认为 parallelism 值。

4.2.1.2. 了解如何为作业设置最长持续时间

在定义作业时,您可以通过设置 activeDeadlineSeconds 字段来定义其最长持续时间。以秒为单位指定,默认情况下不设置。若未设置,则不强制执行最长持续时间。

最长持续时间从系统中调度第一个 pod 的时间开始计算,并且定义作业在多久时间内处于活跃状态。它将跟踪整个执行时间。达到指定的超时后,OpenShift Container Platform 将终止作业。

4.2.1.3. 了解如何为 pod 失败设置作业避退策略

在因为配置中的逻辑错误或其他类似原因而重试了一定次数后,作业会被视为已经失败。控制器以六分钟为上限,按指数避退延时(10s20s40s …)重新创建与作业关联的失败 pod。如果控制器检查之间没有出现新的失败 pod,则重置这个限制。

使用 spec.backoffLimit 参数为作业设置重试次数。

4.2.1.4. 了解如何配置 Cron Job 以移除工件

Cron Job 可能会遗留工件资源,如作业或 pod 等。作为用户,务必要配置一个历史限制,以便能妥善清理旧作业及其 pod。Cron Job 规格内有两个字段负责这一事务:

  • .spec.successfulJobsHistoryLimit。要保留的成功完成作业数(默认为 3)。
  • .spec.failedJobsHistoryLimit。要保留的失败完成作业数(默认为 1)。
提示
  • 删除您不再需要的 Cron Job:

    $ oc delete cronjob/<cron_job_name>

    这样可防止生成不必要的工件。

  • 您可以通过将 spec.suspend 设置为 true 来挂起后续执行。所有后续执行都会挂起,直到重置为 false

4.2.1.5. 已知限制

作业规格重启策略只适用于 pod,不适用于作业控制器。不过,作业控制器被硬编码为可以一直重试直到作业完成为止。

因此,restartPolicy: Never--restart=Never 会产生与 restartPolicy: OnFailure--restart=OnFailure 相同的行为。也就是说,作业失败后会自动重启,直到成功(或被手动放弃)为止。策略仅设定由哪一子系统执行重启。

使用 Never 策略时,作业控制器负责执行重启。在每次尝试时,作业控制器会在作业状态中递增失败次数并创建新的 pod。这意味着,每次尝试失败都会增加 pod 的数量。

使用 OnFailure 策略时,kubelet 负责执行重启。每次尝试都不会在作业状态中递增失败次数。另外,kubelet 将通过在相同节点上启动 pod 来重试失败的作业。

4.2.2. 创建作业

您可以通过创建作业对象在 OpenShift Container Platform 中创建作业。

流程

创建作业:

  1. 创建一个类似以下示例的 YAML 文件:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: pi
    spec:
      parallelism: 1    1
      completions: 1    2
      activeDeadlineSeconds: 1800 3
      backoffLimit: 6   4
      template:         5
        metadata:
          name: pi
        spec:
          containers:
          - name: pi
            image: perl
            command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
          restartPolicy: OnFailure    6
    1
    可选:指定一个作业应并行运行多少个 pod 副本;默认与 1
    • 对于非并行作业,请保留未设置。当取消设置时,默认为 1
    2
    可选:指定标记作业完成需要成功完成多少个 pod。
    • 对于非并行作业,请保留未设置。当取消设置时,默认为 1
    • 对于具有固定完成计数的并行作业,请指定完成数。
    • 对于带有工作队列的并行作业,请保留 unset。当取消设置默认为 parallelism 值。
    3
    可选:指定作业可以运行的最长持续时间。
    4
    可选:指定作业的重试次数。此字段默认值为 6。
    5
    指定控制器创建的 Pod 模板。
    6
    指定 pod 的重启策略:
    • Never。不要重启作业。
    • OnFailure。仅在失败时重启该任务。
    • Always。总是重启该任务。

      如需了解 OpenShift Container Platform 如何使用与失败容器相关的重启策略,请参阅 Kubernetes 文档中的示例状态

  2. 创建作业:

    $ oc create -f <file-name>.yaml
注意

您还可以使用 oc create job,在一个命令中创建并启动作业。以下命令会创建并启动一个与上个示例中指定的相似的作业:

$ oc create job pi --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'

4.2.3. 创建 cron job

您可以通过创建作业对象在 OpenShift Container Platform 中创建 Cron Job。

流程

创建 Cron Job:

  1. 创建一个类似以下示例的 YAML 文件:

    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: pi
    spec:
      schedule: "*/1 * * * *"          1
      timeZone: Etc/UTC                2
      concurrencyPolicy: "Replace"     3
      startingDeadlineSeconds: 200     4
      suspend: true                    5
      successfulJobsHistoryLimit: 3    6
      failedJobsHistoryLimit: 1        7
      jobTemplate:                     8
        spec:
          template:
            metadata:
              labels:                  9
                parent: "cronjobpi"
            spec:
              containers:
              - name: pi
                image: perl
                command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
              restartPolicy: OnFailure 10
    1
    cron 格式指定的作业调度计划。在本例中,作业将每分钟运行一次。
    2
    调度的可选时区。有关有效选项,请参阅 tz 数据库时区列表。如果没有指定,Kubernetes 控制器管理器会解释相对于其本地时区的调度。此设置作为技术预览提供
    3
    可选的并发策略,指定如何对待 Cron Job 中的并发作业。只能指定以下并发策略之一。若未指定,默认为允许并发执行。
    • Allow,允许 Cron Job 并发运行。
    • Forbid,禁止并发运行。如果上一运行尚未结束,则跳过下一运行。
    • Replace,取消当前运行的作业并替换为新作业。
    4
    可选期限(秒为单位),如果作业因任何原因而错过预定时间,则在此期限内启动作业。错过的作业执行计为失败的作业。若不指定,则没有期限。
    5
    可选标志,允许挂起 Cron Job。若设为 true,则会挂起所有后续执行。
    6
    要保留的成功完成作业数(默认为 3)。
    7
    要保留的失败完成作业数(默认为 1)。
    8
    作业模板。类似于作业示例。
    9
    为此 Cron Job 生成的作业设置一个标签。
    10
    pod 的重启策略。这不适用于作业控制器。
    注意

    .spec.successfulJobsHistoryLimit.spec.failedJobsHistoryLimit 字段是可选的。用于指定应保留的已完成作业和已失败作业的数量。默认情况下,分别设置为 31。如果将限制设定为 0,则对应种类的作业完成后不予保留。

  2. 创建 cron job:

    $ oc create -f <file-name>.yaml
注意

您还可以使用 oc create cronjob,在一个命令中创建并启动 Cron Job。以下命令会创建并启动与上一示例中指定的相似的 Cron Job:

$ oc create cronjob pi --image=perl --schedule='*/1 * * * *' -- perl -Mbignum=bpi -wle 'print bpi(2000)'

使用 oc create cronjob 时,--schedule 选项接受采用 cron 格式的调度计划。

第 5 章 操作节点

5.1. 查看和列出 OpenShift Container Platform 集群中的节点

您可以列出集群中的所有节点,以获取节点的相关信息,如状态、年龄、内存用量和其他详情。

在执行节点管理操作时,CLI 与代表实际节点主机的节点对象交互。主控机(master)使用来自节点对象的信息执行健康检查,以此验证节点。

5.1.1. 关于列出集群中的所有节点

您可以获取集群中节点的详细信息。

  • 以下命令列出所有节点:

    $ oc get nodes

    以下示例是具有健康节点的集群:

    $ oc get nodes

    输出示例

    NAME                   STATUS    ROLES     AGE       VERSION
    master.example.com     Ready     master    7h        v1.25.0
    node1.example.com      Ready     worker    7h        v1.25.0
    node2.example.com      Ready     worker    7h        v1.25.0

    以下示例是具有一个不健康节点的集群:

    $ oc get nodes

    输出示例

    NAME                   STATUS                      ROLES     AGE       VERSION
    master.example.com     Ready                       master    7h        v1.25.0
    node1.example.com      NotReady,SchedulingDisabled worker    7h        v1.25.0
    node2.example.com      Ready                       worker    7h        v1.25.0

    触发 NotReady 状态的条件在本节中显示。

  • -o wide 选项提供有关节点的附加信息。

    $ oc get nodes -o wide

    输出示例

    NAME                STATUS   ROLES    AGE    VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                                                       KERNEL-VERSION                 CONTAINER-RUNTIME
    master.example.com  Ready    master   171m   v1.25.0   10.0.129.108   <none>        Red Hat Enterprise Linux CoreOS 48.83.202103210901-0 (Ootpa)   4.18.0-240.15.1.el8_3.x86_64   cri-o://1.25.0-30.rhaos4.10.gitf2f339d.el8-dev
    node1.example.com   Ready    worker   72m    v1.25.0   10.0.129.222   <none>        Red Hat Enterprise Linux CoreOS 48.83.202103210901-0 (Ootpa)   4.18.0-240.15.1.el8_3.x86_64   cri-o://1.25.0-30.rhaos4.10.gitf2f339d.el8-dev
    node2.example.com   Ready    worker   164m   v1.25.0   10.0.142.150   <none>        Red Hat Enterprise Linux CoreOS 48.83.202103210901-0 (Ootpa)   4.18.0-240.15.1.el8_3.x86_64   cri-o://1.25.0-30.rhaos4.10.gitf2f339d.el8-dev

  • 以下命令列出一个节点的相关信息:

    $ oc get node <node>

    例如:

    $ oc get node node1.example.com

    输出示例

    NAME                   STATUS    ROLES     AGE       VERSION
    node1.example.com      Ready     worker    7h        v1.25.0

  • 以下命令提供有关特定节点的更多详细信息,包括发生当前状况的原因:

    $ oc describe node <node>

    例如:

    $ oc describe node node1.example.com

    输出示例

    Name:               node1.example.com 1
    Roles:              worker 2
    Labels:             beta.kubernetes.io/arch=amd64   3
                        beta.kubernetes.io/instance-type=m4.large
                        beta.kubernetes.io/os=linux
                        failure-domain.beta.kubernetes.io/region=us-east-2
                        failure-domain.beta.kubernetes.io/zone=us-east-2a
                        kubernetes.io/hostname=ip-10-0-140-16
                        node-role.kubernetes.io/worker=
    Annotations:        cluster.k8s.io/machine: openshift-machine-api/ahardin-worker-us-east-2a-q5dzc  4
                        machineconfiguration.openshift.io/currentConfig: worker-309c228e8b3a92e2235edd544c62fea8
                        machineconfiguration.openshift.io/desiredConfig: worker-309c228e8b3a92e2235edd544c62fea8
                        machineconfiguration.openshift.io/state: Done
                        volumes.kubernetes.io/controller-managed-attach-detach: true
    CreationTimestamp:  Wed, 13 Feb 2019 11:05:57 -0500
    Taints:             <none>  5
    Unschedulable:      false
    Conditions:                 6
      Type             Status  LastHeartbeatTime                 LastTransitionTime                Reason                       Message
      ----             ------  -----------------                 ------------------                ------                       -------
      OutOfDisk        False   Wed, 13 Feb 2019 15:09:42 -0500   Wed, 13 Feb 2019 11:05:57 -0500   KubeletHasSufficientDisk     kubelet has sufficient disk space available
      MemoryPressure   False   Wed, 13 Feb 2019 15:09:42 -0500   Wed, 13 Feb 2019 11:05:57 -0500   KubeletHasSufficientMemory   kubelet has sufficient memory available
      DiskPressure     False   Wed, 13 Feb 2019 15:09:42 -0500   Wed, 13 Feb 2019 11:05:57 -0500   KubeletHasNoDiskPressure     kubelet has no disk pressure
      PIDPressure      False   Wed, 13 Feb 2019 15:09:42 -0500   Wed, 13 Feb 2019 11:05:57 -0500   KubeletHasSufficientPID      kubelet has sufficient PID available
      Ready            True    Wed, 13 Feb 2019 15:09:42 -0500   Wed, 13 Feb 2019 11:07:09 -0500   KubeletReady                 kubelet is posting ready status
    Addresses:   7
      InternalIP:   10.0.140.16
      InternalDNS:  ip-10-0-140-16.us-east-2.compute.internal
      Hostname:     ip-10-0-140-16.us-east-2.compute.internal
    Capacity:    8
     attachable-volumes-aws-ebs:  39
     cpu:                         2
     hugepages-1Gi:               0
     hugepages-2Mi:               0
     memory:                      8172516Ki
     pods:                        250
    Allocatable:
     attachable-volumes-aws-ebs:  39
     cpu:                         1500m
     hugepages-1Gi:               0
     hugepages-2Mi:               0
     memory:                      7558116Ki
     pods:                        250
    System Info:    9
     Machine ID:                              63787c9534c24fde9a0cde35c13f1f66
     System UUID:                             EC22BF97-A006-4A58-6AF8-0A38DEEA122A
     Boot ID:                                 f24ad37d-2594-46b4-8830-7f7555918325
     Kernel Version:                          3.10.0-957.5.1.el7.x86_64
     OS Image:                                Red Hat Enterprise Linux CoreOS 410.8.20190520.0 (Ootpa)
     Operating System:                        linux
     Architecture:                            amd64
     Container Runtime Version:               cri-o://1.25.0-0.6.dev.rhaos4.3.git9ad059b.el8-rc2
     Kubelet Version:                         v1.25.0
     Kube-Proxy Version:                      v1.25.0
    PodCIDR:                                  10.128.4.0/24
    ProviderID:                               aws:///us-east-2a/i-04e87b31dc6b3e171
    Non-terminated Pods:                      (12 in total)  10
      Namespace                               Name                                   CPU Requests  CPU Limits  Memory Requests  Memory Limits
      ---------                               ----                                   ------------  ----------  ---------------  -------------
      openshift-cluster-node-tuning-operator  tuned-hdl5q                            0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-dns                           dns-default-l69zr                      0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-image-registry                node-ca-9hmcg                          0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-ingress                       router-default-76455c45c-c5ptv         0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-machine-config-operator       machine-config-daemon-cvqw9            20m (1%)      0 (0%)      50Mi (0%)        0 (0%)
      openshift-marketplace                   community-operators-f67fh              0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-monitoring                    alertmanager-main-0                    50m (3%)      50m (3%)    210Mi (2%)       10Mi (0%)
      openshift-monitoring                    node-exporter-l7q8d                    10m (0%)      20m (1%)    20Mi (0%)        40Mi (0%)
      openshift-monitoring                    prometheus-adapter-75d769c874-hvb85    0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-multus                        multus-kw8w5                           0 (0%)        0 (0%)      0 (0%)           0 (0%)
      openshift-sdn                           ovs-t4dsn                              100m (6%)     0 (0%)      300Mi (4%)       0 (0%)
      openshift-sdn                           sdn-g79hg                              100m (6%)     0 (0%)      200Mi (2%)       0 (0%)
    Allocated resources:
      (Total limits may be over 100 percent, i.e., overcommitted.)
      Resource                    Requests     Limits
      --------                    --------     ------
      cpu                         380m (25%)   270m (18%)
      memory                      880Mi (11%)  250Mi (3%)
      attachable-volumes-aws-ebs  0            0
    Events:     11
      Type     Reason                   Age                From                      Message
      ----     ------                   ----               ----                      -------
      Normal   NodeHasSufficientPID     6d (x5 over 6d)    kubelet, m01.example.com  Node m01.example.com status is now: NodeHasSufficientPID
      Normal   NodeAllocatableEnforced  6d                 kubelet, m01.example.com  Updated Node Allocatable limit across pods
      Normal   NodeHasSufficientMemory  6d (x6 over 6d)    kubelet, m01.example.com  Node m01.example.com status is now: NodeHasSufficientMemory
      Normal   NodeHasNoDiskPressure    6d (x6 over 6d)    kubelet, m01.example.com  Node m01.example.com status is now: NodeHasNoDiskPressure
      Normal   NodeHasSufficientDisk    6d (x6 over 6d)    kubelet, m01.example.com  Node m01.example.com status is now: NodeHasSufficientDisk
      Normal   NodeHasSufficientPID     6d                 kubelet, m01.example.com  Node m01.example.com status is now: NodeHasSufficientPID
      Normal   Starting                 6d                 kubelet, m01.example.com  Starting kubelet.
     ...

    1
    节点的名称。
    2
    节点的角色,可以是 masterworker
    3
    应用到节点的标签。
    4
    应用到节点的注解。
    5
    应用到节点的污点。
    6
    节点条件和状态。conditions 小节列出了 ReadyPIDPressurePIDPressureMemoryPressureDiskPressureOutOfDisk 状态。本节稍后将描述这些条件。
    7
    节点的 IP 地址和主机名。
    8
    pod 资源和可分配的资源。
    9
    节点主机的相关信息。
    10
    节点上的 pod。
    11
    节点报告的事件。

在显示的节点信息中,本节显示的命令输出中会出现以下节点状况:

表 5.1. 节点状况

状况描述

Ready

如果为 true,节点处于健康状态,并可以接受 pod。如果为 false,则节点处于不健康的状态,不接受 pod。如果为 unknown,代表节点控制器在 node-monitor-grace-period 时间内(默认为 40 秒)还没有收到来自节点的心跳信号。

DiskPressure

如果为 true,代表磁盘容量较低。

MemoryPressure

如果为 true,代表节点内存较低。

PIDPressure

如果为 true,代表节点上的进程太多。

OutOfDisk

如果为 true,代表节点上的可用空间不足,无法添加新 pod。

NetworkUnavailable

如果为 true,代表节点的网络不会被正确配置。

NotReady

如果为true,代表一个底层组件(如容器运行时或网络)遇到了问题或尚未配置。

SchedulingDisabled

无法通过调度将 Pod 放置到节点上。

5.1.2. 列出集群中某一节点上的 pod

您可以列出特定节点上的所有 pod。

流程

  • 列出一个或多个节点上的所有或选定 pod:

    $ oc describe node <node1> <node2>

    例如:

    $ oc describe node ip-10-0-128-218.ec2.internal
  • 列出选定节点上的所有或选定 pod:

    $ oc describe --selector=<node_selector>
    $ oc describe node  --selector=kubernetes.io/os

    或者:

    $ oc describe -l=<pod_selector>
    $ oc describe node -l node-role.kubernetes.io/worker
  • 列出特定节点上的所有 pod,包括终止的 pod:

    $ oc get pod --all-namespaces --field-selector=spec.nodeName=<nodename>

5.1.3. 查看节点上的内存和 CPU 用量统计

您可以显示节点的用量统计,这些统计信息为容器提供了运行时环境。这些用量统计包括 CPU、内存和存储的消耗。

先决条件

  • 您必须有 cluster-reader 权限才能查看用量统计。
  • 必须安装 Metrics 才能查看用量统计。

流程

  • 查看用量统计:

    $ oc adm top nodes

    输出示例

    NAME                                   CPU(cores)   CPU%      MEMORY(bytes)   MEMORY%
    ip-10-0-12-143.ec2.compute.internal    1503m        100%      4533Mi          61%
    ip-10-0-132-16.ec2.compute.internal    76m          5%        1391Mi          18%
    ip-10-0-140-137.ec2.compute.internal   398m         26%       2473Mi          33%
    ip-10-0-142-44.ec2.compute.internal    656m         43%       6119Mi          82%
    ip-10-0-146-165.ec2.compute.internal   188m         12%       3367Mi          45%
    ip-10-0-19-62.ec2.compute.internal     896m         59%       5754Mi          77%
    ip-10-0-44-193.ec2.compute.internal    632m         42%       5349Mi          72%

  • 查看具有标签的节点的用量统计信息:

    $ oc adm top node --selector=''

    您必须选择过滤所基于的选择器(标签查询)。支持 ===!=

5.2. 操作节点

作为管理员,您可以执行若干任务来提高集群的效率。

5.2.1. 了解如何撤离节点上的 pod

通过撤离 pod,您可以迁移给定的一个或多个节点上的所有或选定 pod。

您只能撤离由复制控制器支持的 pod。复制控制器在其他节点上创建新 pod,并从指定节点移除现有的 pod。

裸机 pod(即不由复制控制器支持的 pod)默认情况下不受影响。您可以通过指定 pod 选择器来撤离一小部分 pod。pod 选择器基于标签,因此带有指定标签的所有 pod 都将被撤离。

流程

  1. 在执行 pod 驱除前,标记不可调度的节点。

    1. 将节点标记为不可调度:

      $ oc adm cordon <node1>

      输出示例

      node/<node1> cordoned

    2. 检查节点状态为 Ready,SchedulingDisabled:

      $ oc get node <node1>

      输出示例

      NAME        STATUS                     ROLES     AGE       VERSION
      <node1>     Ready,SchedulingDisabled   worker    1d        v1.25.0

  2. 使用以下方法之一驱除 pod:

    • 在一个或多个节点上驱除所有或选定的 pod:

      $ oc adm drain <node1> <node2> [--pod-selector=<pod_selector>]
    • 使用 --force 选项强制删除裸机 pod。设为 true 时,即使存在不由复制控制器、副本集、作业、守护进程设置或有状态设置管理的 pod,也会继续执行删除:

      $ oc adm drain <node1> <node2> --force=true
    • 使用 --grace-period 以秒为单位设置一个期限,以便每个 pod 能够安全地终止。如果为负,则使用 pod 中指定的默认值:

      $ oc adm drain <node1> <node2> --grace-period=-1
    • 忽略由守护进程集管理的 pod,将 --ignore-daemonsets 标记设为 true

      $ oc adm drain <node1> <node2> --ignore-daemonsets=true
    • 使用 --timeout 标记来设置在放弃前要等待的时长。值为 0 时设定无限时长:

      $ oc adm drain <node1> <node2> --timeout=5s
    • 即使存在使用 emptyDir 卷的 pod,将 --delete-emptydir-data 标志设为 true,也会删除 pod。节点排空时会删除本地数据:

      $ oc adm drain <node1> <node2> --delete-emptydir-data=true
    • --dry-run 选项设为 true,它会列出将要迁移的对象而不实际执行撤离:

      $ oc adm drain <node1> <node2>  --dry-run=true

      您可以使用 --selector=<node_selector> 选项来撤离选定节点上的 pod,而不指定具体的节点名称(如 <node1> <node2>)。

  3. 完成后将节点标记为可调度。

    $ oc adm uncordon <node1>

5.2.2. 了解如何更新节点上的标签

您可以更新节点上的任何标签。

节点标签不会在节点删除后保留,即使机器备份了节点也是如此。

注意

MachineSet 对象的任何更改都不会应用到计算机器集拥有的现有机器。例如,对现有 MachineSet 对象编辑或添加的标签不会传播到与计算机器集关联的现有机器和节点。

  • 以下命令在节点上添加或更新标签:

    $ oc label node <node> <key_1>=<value_1> ... <key_n>=<value_n>

    例如:

    $ oc label nodes webconsole-7f7f6 unhealthy=true
    提示

    您还可以应用以下 YAML 来应用标签:

    kind: Node
    apiVersion: v1
    metadata:
      name: webconsole-7f7f6
      labels:
        unhealthy: 'true'
  • 以下命令更新命名空间中的所有 pod:

    $ oc label pods --all <key_1>=<value_1>

    例如:

    $ oc label pods --all status=unhealthy

5.2.3. 了解如何将节点标记为不可调度或可以调度

默认情况下,具有 Ready 状态的健康节点被标记为可以调度,这意味着您可以在节点上放置新 pod。如果手动将节点标记为不可调度,则会阻止在该节点上调度任何新的 pod。节点上的现有 pod 不受影响。

  • 以下命令将一个或多个节点标记为不可调度:

    输出示例

    $ oc adm cordon <node>

    例如:

    $ oc adm cordon node1.example.com

    输出示例

    node/node1.example.com cordoned
    
    NAME                 LABELS                                        STATUS
    node1.example.com    kubernetes.io/hostname=node1.example.com      Ready,SchedulingDisabled

  • 以下命令将当前不可调度的一个或多个节点标记为可以调度:

    $ oc adm uncordon <node1>

    另外,您也可以使用 --selector=<node_selector> 选项将选定的节点标记为可以调度或不可调度,而不指定具体的节点名称(如 <node>)。

5.2.4. 删除节点

5.2.4.1. 从集群中删除节点

当您使用 CLI 删除节点时,节点对象会从 Kubernetes 中删除,但该节点上存在的 pod 不会被删除。任何未由复制控制器支持的裸机 pod 都无法从 OpenShift Container Platform 访问。由复制控制器支持的 Pod 会重新调度到其他可用的节点。您必须删除本地清单 pod。

流程

要从 OpenShift Container Platform 集群中删除节点,请编辑适当的 MachineSet 对象:

注意

如果您在裸机上运行集群,则无法通过编辑 MachineSet 对象来删除节点。计算机器集仅在集群与云供应商集成时才可用。相反,您必须在手动删除前取消调度并排空节点。

  1. 查看集群中的计算机器集:

    $ oc get machinesets -n openshift-machine-api

    计算机器集以 <clusterid>-worker-<aws-region-az> 的形式列出。

  2. 扩展计算机器集:

    $ oc scale --replicas=2 machineset <machineset> -n openshift-machine-api

    或者:

    $ oc edit machineset <machineset> -n openshift-machine-api
    提示

    您还可以应用以下 YAML 来扩展计算机器集:

    apiVersion: machine.openshift.io/v1beta1
    kind: MachineSet
    metadata:
      name: <machineset>
      namespace: openshift-machine-api
    spec:
      replicas: 2

其他资源

5.2.4.2. 从裸机集群中删除节点

当您使用 CLI 删除节点时,节点对象会从 Kubernetes 中删除,但该节点上存在的 pod 不会被删除。任何未由复制控制器支持的裸机 pod 都无法从 OpenShift Container Platform 访问。由复制控制器支持的 Pod 会重新调度到其他可用的节点。您必须删除本地清单 pod。

流程

通过完成以下步骤,从裸机上运行的 OpenShift Container Platform 集群中删除节点:

  1. 将节点标记为不可调度:

    $ oc adm cordon <node_name>
  2. 排空节点上的所有 pod:

    $ oc adm drain <node_name> --force=true

    如果节点离线或者无响应,此步骤可能会失败。即使节点没有响应,它仍然在运行写入共享存储的工作负载。为了避免数据崩溃,请在进行操作前关闭物理硬件。

  3. 从集群中删除节点:

    $ oc delete node <node_name>

    虽然节点对象现已从集群中删除,但它仍然可在重启后或 kubelet 服务重启后重新加入集群。要永久删除该节点及其所有数据,您必须弃用该节点

  4. 如果您关闭了物理硬件,请重新打开它以便节点可以重新加入集群。

5.3. 管理节点

OpenShift Container Platform 使用 KubeletConfig 自定义资源(CR)来管理节点的配置。通过创建 KubeletConfig 对象的实例,会创建一个受管机器配置来覆盖节点上的设置。

注意

不支持为更改配置而登录远程机器。

5.3.1. 修改节点

要对集群或机器池进行配置更改,您必须创建自定义资源定义(CRD)或 kubeletConfig 对象。OpenShift Container Platform 使用 Machine Config Controller 来监控是否通过 CRD 进行了更改,以将更改应用到集群。

注意

因为 kubeletConfig 对象中的字段直接从上游 Kubernetes 传递给 kubelet,所以对这些字段的验证直接由 kubelet 本身处理。有关这些字段的有效值,请参阅相关的 Kubernetes 文档。kubeletConfig 对象中的无效值可能会导致集群节点不可用。

步骤

  1. 为您要配置的节点类型,获取与静态 CRD (Machine Config Pool) 关联的标签。执行以下步骤之一:

    1. 检查所需机器配置池的当前标签。

      例如:

      $  oc get machineconfigpool  --show-labels

      输出示例

      NAME      CONFIG                                             UPDATED   UPDATING   DEGRADED   LABELS
      master    rendered-master-e05b81f5ca4db1d249a1bf32f9ec24fd   True      False      False      operator.machineconfiguration.openshift.io/required-for-upgrade=
      worker    rendered-worker-f50e78e1bc06d8e82327763145bfcf62   True      False      False

    2. 为所需的机器配置池添加自定义标签。

      例如:

      $ oc label machineconfigpool worker custom-kubelet=enabled
  2. 为您的配置更改创建一个 kubeletconfig 自定义资源(CR)。

    例如:

    custom-config CR 配置示例

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: custom-config 1
    spec:
      machineConfigPoolSelector:
        matchLabels:
          custom-kubelet: enabled 2
      kubeletConfig: 3
        podsPerCore: 10
        maxPods: 250
        systemReserved:
          cpu: 2000m
          memory: 1Gi

    1
    为 CR 分配一个名称。
    2
    指定要应用配置更改的标签,这是您添加到机器配置池中的标签。
    3
    指定要更改的新值。
  3. 创建 CR 对象。

    $ oc create -f <file-name>

    例如:

    $ oc create -f master-kube-config.yaml

大多数 Kubelet 配置选项 可由用户设置。不允许覆盖下列选项:

  • CgroupDriver
  • ClusterDNS
  • ClusterDomain
  • RuntimeRequestTimeout
  • StaticPodPath
注意

如果单个节点包含超过 50 个镜像,pod 调度可能会在节点间进行平衡。这是因为节点上的镜像列表默认简写为 50。您可以通过编辑 KubeletConfig 对象来禁用镜像限制,并将 nodeStatusMaxImages 的值设置为 -1

5.3.2. 将 control plane 节点配置为可以调度

您可以将 control plane 节点配置为可以调度,这意味着允许在 master 节点上放置新的 pod。默认情况下,control plane 节点不可调度。

您可以将 master 设置为可调度,但必须保留 worker 节点。

注意

您可以在裸机集群中部署没有 worker 节点的 OpenShift Container Platform。在这种情况下,control plane 节点会被标记为可以调度。

您可以通过配置 mastersSchedulable 字段来允许或禁止调度 control plane 节点。

重要

当您将 control plane 节点从默认的不可调度配置为可以调度时,需要额外的订阅。这是因为 control plane 节点随后变为 worker 节点。

步骤

  1. 编辑 schedulers.config.openshift.io 资源。

    $ oc edit schedulers.config.openshift.io cluster
  2. 配置 mastersSchedulable 字段。

    apiVersion: config.openshift.io/v1
    kind: Scheduler
    metadata:
      creationTimestamp: "2019-09-10T03:04:05Z"
      generation: 1
      name: cluster
      resourceVersion: "433"
      selfLink: /apis/config.openshift.io/v1/schedulers/cluster
      uid: a636d30a-d377-11e9-88d4-0a60097bee62
    spec:
      mastersSchedulable: false 1
    status: {}
    1
    设置为 true 以允许调度 control plane 节点,或设置为 false 以禁止调度 control plane 节点。
  3. 保存文件以使改变生效。

5.3.3. 设置 SELinux 布尔值

OpenShift Container Platform 允许您在 Red Hat Enterprise Linux CoreOS (RHCOS) 节点上启用和禁用 SELinux 布尔值。以下流程解释了如何使用 Machine Config Operator (MCO) 修改节点上的 SELinux 布尔值。此流程使用 container_manage_cgroup 作为示例布尔值。您可以将这个值修改为您需要的任何布尔值。

先决条件

  • 已安装 OpenShift CLI(oc)。

步骤

  1. 使用 MachineConfig 对象创建新 YAML 文件,如下例所示:

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker
      name: 99-worker-setsebool
    spec:
      config:
        ignition:
          version: 3.2.0
        systemd:
          units:
          - contents: |
              [Unit]
              Description=Set SELinux booleans
              Before=kubelet.service
    
              [Service]
              Type=oneshot
              ExecStart=/sbin/setsebool container_manage_cgroup=on
              RemainAfterExit=true
    
              [Install]
              WantedBy=multi-user.target graphical.target
            enabled: true
            name: setsebool.service
  2. 运行以下命令来创建新的 MachineConfig 对象:

    $ oc create -f 99-worker-setsebool.yaml
注意

MachineConfig 对象应用任何更改将导致所有受影响的节点在应用更改后安全重启。

5.3.4. 为节点添加内核参数

在一些特殊情况下,您可能需要为集群中的一组节点添加内核参数。进行此操作时应小心谨慎,而且您必须先清楚了解所设参数的影响。

警告

不当使用内核参数会导致系统变得无法引导。

您可以设置的内核参数示例包括:

  • Enforcing=0:将 Security Enhanced Linux(SELinux)配置为以 permissive 模式运行。在 permissive 模式中,系统会象 enforcing 模式一样加载安全策略,包括标记对象并在日志中记录访问拒绝条目,但它并不会拒绝任何操作。虽然不建议在生产环境系统中使用 permissive 模式,但 permissive 模式会有助于调试。
  • nosmt:在内核中禁用对称多线程 (SMT)。多线程允许每个 CPU 有多个逻辑线程。您可以在多租户环境中考虑使用 nosmt,以减少潜在的跨线程攻击风险。禁用 SMT 在本质上相当于选择安全性而非性能。
  • systemd.unified_cgroup_hierarchy:启用 Linux 控制组版本 2 (cgroup v2)。cgroup v2 是内核控制组的下一个版本,它包括了多个改进。

    重要

    OpenShift Container Platform cgroups 版本 2 支持只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

    有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围

如需内核参数的列表和描述,请参阅 Kernel.org 内核参数

在以下流程中,您要创建一个用于标识以下内容的 MachineConfig 对象:

  • 您要添加内核参数的一组机器。本例中为具有 worker 角色的机器。
  • 附加到现有内核参数末尾的内核参数。
  • 指示机器配置列表中应用更改的位置的标签。

先决条件

  • 具有正常运行的 OpenShift Container Platform 集群的管理特权。

流程

  1. 列出 OpenShift Container Platform 集群的现有 MachineConfig 对象,以确定如何标记您的机器配置:

    $ oc get MachineConfig

    输出示例

    NAME                                               GENERATEDBYCONTROLLER                      IGNITIONVERSION   AGE
    00-master                                          52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    00-worker                                          52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-master-container-runtime                        52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-master-kubelet                                  52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-worker-container-runtime                        52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-worker-kubelet                                  52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    99-master-generated-registries                     52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    99-master-ssh                                                                                 3.2.0             40m
    99-worker-generated-registries                     52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    99-worker-ssh                                                                                 3.2.0             40m
    rendered-master-23e785de7587df95a4b517e0647e5ab7   52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    rendered-worker-5d596d9293ca3ea80c896a1191735bb1   52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m

  2. 创建一个用于标识内核参数的 MachineConfig 对象文件(例如 05-worker-kernelarg-selinuxpermissive.yaml

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfig
    metadata:
      labels:
        machineconfiguration.openshift.io/role: worker1
      name: 05-worker-kernelarg-selinuxpermissive2
    spec:
      kernelArguments:
        - enforcing=03
    1
    仅将新内核参数应用到 worker 节点。
    2
    用于标识它插入到机器配置中的什么位置(05)以及发挥什么作用(添加一个内核参数来配置 SELinux permissive 模式)。
    3
    将确切的内核参数标识为 enforcing=0
  3. 创建新机器配置:

    $ oc create -f 05-worker-kernelarg-selinuxpermissive.yaml
  4. 检查机器配置以查看是否添加了新配置:

    $ oc get MachineConfig

    输出示例

    NAME                                               GENERATEDBYCONTROLLER                      IGNITIONVERSION   AGE
    00-master                                          52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    00-worker                                          52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-master-container-runtime                        52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-master-kubelet                                  52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-worker-container-runtime                        52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    01-worker-kubelet                                  52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    05-worker-kernelarg-selinuxpermissive                                                         3.2.0             105s
    99-master-generated-registries                     52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    99-master-ssh                                                                                 3.2.0             40m
    99-worker-generated-registries                     52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    99-worker-ssh                                                                                 3.2.0             40m
    rendered-master-23e785de7587df95a4b517e0647e5ab7   52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m
    rendered-worker-5d596d9293ca3ea80c896a1191735bb1   52dd3ba6a9a527fc3ab42afac8d12b693534c8c9   3.2.0             33m

  5. 检查节点:

    $ oc get nodes

    输出示例

    NAME                           STATUS                     ROLES    AGE   VERSION
    ip-10-0-136-161.ec2.internal   Ready                      worker   28m   v1.25.0
    ip-10-0-136-243.ec2.internal   Ready                      master   34m   v1.25.0
    ip-10-0-141-105.ec2.internal   Ready,SchedulingDisabled   worker   28m   v1.25.0
    ip-10-0-142-249.ec2.internal   Ready                      master   34m   v1.25.0
    ip-10-0-153-11.ec2.internal    Ready                      worker   28m   v1.25.0
    ip-10-0-153-150.ec2.internal   Ready                      master   34m   v1.25.0

    您可以发现,在应用更改时每个 worker 节点上的调度都会被禁用。

  6. 前往其中一个 worker 节点并列出内核命令行参数(主机上的 /proc/cmdline 中),以检查内核参数确实已发挥作用:

    $ oc debug node/ip-10-0-141-105.ec2.internal

    输出示例

    Starting pod/ip-10-0-141-105ec2internal-debug ...
    To use host binaries, run `chroot /host`
    
    sh-4.2# cat /host/proc/cmdline
    BOOT_IMAGE=/ostree/rhcos-... console=tty0 console=ttyS0,115200n8
    rootflags=defaults,prjquota rw root=UUID=fd0... ostree=/ostree/boot.0/rhcos/16...
    coreos.oem.id=qemu coreos.oem.id=ec2 ignition.platform.id=ec2 enforcing=0
    
    sh-4.2# exit

    您应看到 enforcing=0 参数已添加至其他内核参数。

5.3.5. 在节点上启用交换内存使用

重要

在节点上启用交换内存只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

有关红帽技术预览功能支持范围的更多信息,请参阅技术预览功能支持范围

您可以根据节点为 OpenShift Container Platform 工作负载启用交换内存使用。

警告

启用交换内存可能会对工作负载性能和资源不足处理造成负面影响。不要在 control plane 节点上启用交换内存。

要启用交换内存,请创建一个 kubeletconfig 自定义资源(CR)来设置 swapbehavior 参数。您可以设置有限或无限的交换内存:

  • 有限:使用 LimitedSwap 值来限制可以使用的交换内存工作负载量。任何不是由 OpenShift Container Platform 管理的节点上的工作负载都可以使用交换内存。LimitedSwap 行为取决于节点是否使用 Linux 控制组 版本 1(cgroups v1)版本 2(cgroup v2) 运行:

    • cgroup v1:OpenShift Container Platform 工作负载可以使用内存和交换的任意组合(如果设置)到 pod 的内存限值。
    • cgroup v2:OpenShift Container Platform 工作负载无法使用交换内存。
  • 无限:使用 UnlimitedSwap 值来允许工作负载在请求时尽可能多地使用 swap 内存,最多使用系统限制。

由于 kubelet 在没有此配置的情况下不会启动交换内存,因此您必须在 OpenShift Container Platform 中启用交换内存前在节点上启用交换内存。如果节点上没有交换内存,则在 OpenShift Container Platform 中启用交换内存不会起作用。

先决条件

  • 您有一个正在运行的 OpenShift Container Platform 集群,它使用版本 4.10 或更高版本。
  • 以具有管理特权的用户身份登录集群。
  • 您已在集群中启用了 TechPreviewNoUpgrade 功能集(请参阅 Nodes → Working with cluster → Enabling features using feature gates)。

    注意

    启用 TechPreviewNoUpgrade 功能集将无法撤消,并防止次版本更新。不建议在生产环境集群中使用这些功能集。

  • 如果节点上启用了 cgroup v2,则必须通过设置 swapaccount=1 内核参数来启用节点上的交换核算。

步骤

  1. 对要允许交换内存的机器配置池应用自定义标签。

    $ oc label machineconfigpool worker kubelet-swap=enabled
  2. 创建自定义资源(CR)来启用和配置 swap 设置。

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: swap-config
    spec:
      machineConfigPoolSelector:
        matchLabels:
          kubelet-swap: enabled
      kubeletConfig:
        failSwapOn: false 1
        memorySwap:
          swapBehavior: LimitedSwap 2
    1
    设置为 false,以在关联的节点上启用交换内存使用。设置为 true 可禁用交换内存使用。
    2
    指定交换内存行为。如果未指定,则默认值为 LimitedSwap
  3. 在机器上启用交换内存。

5.3.6. 将 control plane 节点从一个 RHOSP 主机迁移到另一个 RHOSP 主机

您可以运行将 control plane 节点从一个 Red Hat OpenStack Platform(RHOSP)节点移至另一个脚本。

先决条件

  • 环境变量 OS_CLOUD 是对在 clouds.yaml 文件中具有管理凭证的 clouds 条目的引用。
  • 环境变量 KUBECONFIG 是指包含管理 OpenShift Container Platform 凭证的配置。

步骤

  • 在命令行中运行以下命令:
#!/usr/bin/env bash

set -Eeuo pipefail

if [ $# -lt 1 ]; then
	echo "Usage: '$0 node_name'"
	exit 64
fi

# Check for admin OpenStack credentials
openstack server list --all-projects >/dev/null || { >&2 echo "The script needs OpenStack admin credentials. Exiting"; exit 77; }

# Check for admin OpenShift credentials
oc adm top node >/dev/null || { >&2 echo "The script needs OpenShift admin credentials. Exiting"; exit 77; }

set -x

declare -r node_name="$1"
declare server_id
server_id="$(openstack server list --all-projects -f value -c ID -c Name | grep "$node_name" | cut -d' ' -f1)"
readonly server_id

# Drain the node
oc adm cordon "$node_name"
oc adm drain "$node_name" --delete-emptydir-data --ignore-daemonsets --force

# Power off the server
oc debug "node/${node_name}" -- chroot /host shutdown -h 1

# Verify the server is shut off
until openstack server show "$server_id" -f value -c status | grep -q 'SHUTOFF'; do sleep 5; done

# Migrate the node
openstack server migrate --wait "$server_id"

# Resize the VM
openstack server resize confirm "$server_id"

# Wait for the resize confirm to finish
until openstack server show "$server_id" -f value -c status | grep -q 'SHUTOFF'; do sleep 5; done

# Restart the VM
openstack server start "$server_id"

# Wait for the node to show up as Ready:
until oc get node "$node_name" | grep -q "^${node_name}[[:space:]]\+Ready"; do sleep 5; done

# Uncordon the node
oc adm uncordon "$node_name"

# Wait for cluster operators to stabilize
until oc get co -o go-template='statuses: {{ range .items }}{{ range .status.conditions }}{{ if eq .type "Degraded" }}{{ if ne .status "False" }}DEGRADED{{ end }}{{ else if eq .type "Progressing"}}{{ if ne .status "False" }}PROGRESSING{{ end }}{{ else if eq .type "Available"}}{{ if ne .status "True" }}NOTAVAILABLE{{ end }}{{ end }}{{ end }}{{ end }}' | grep -qv '\(DEGRADED\|PROGRESSING\|NOTAVAILABLE\)'; do sleep 5; done

如果脚本完成,control plane 机器将迁移到一个新的 RHOSP 节点。

5.4. 管理每个节点的 pod 数量上限

在 OpenShift Container Platform 中,您可以根据节点上的处理器内核数和/或硬限制,来配置可在节点上运行的 pod 数量。如果您同时使用这两个选项,则取两者中较小的限制来限制节点上的 pod 数。

超过这些值可能会导致:

  • OpenShift Container Platform CPU 使用率提高。
  • pod 调度缓慢。
  • 潜在的内存不足情形,具体取决于节点中的内存量。
  • IP 地址池耗尽。
  • 资源过量使用,导致用户应用程序性能变差。
注意

包含单个容器的一个 pod 实际上会使用两个容器。第二个容器在容器实际启动前先设置了网络。因此,运行 10 个 pod 的节点实际上运行有 20 个容器。

podsPerCore 参数根据节点的处理器内核数限制节点上可运行的 pod 数量。例如,如果将一个有 4 个处理器内核的节点上的 podsPerCore 设置为 10,则该节点上允许的 pod 数量上限为 40。

maxPods 参数将节点上可运行的 pod 数量限制为一个固定值,不考虑节点的属性。

5.4.1. 配置每个节点的最大 pod 数量

有两个参数控制可调度到节点的 pod 数量上限,分别为 podsPerCoremaxPods。如果您同时使用这两个选项,则取两者中较小的限制来限制节点上的 pod 数。

例如,如果将一个有 4 个处理器内核的节点上的 podsPerCore 设置为 10,则该节点上允许的 pod 数量上限为 40。

先决条件

  1. 输入以下命令为您要配置的节点类型获取与静态 MachineConfigPool CRD 关联的标签:

    $ oc edit machineconfigpool <name>

    例如:

    $ oc edit machineconfigpool worker

    输出示例

    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfigPool
    metadata:
      creationTimestamp: "2022-11-16T15:34:25Z"
      generation: 4
      labels:
        pools.operator.machineconfiguration.openshift.io/worker: "" 1
      name: worker

    1
    标签会出现在 Labels 下。
    提示

    如果标签不存在,请添加键/值对,例如:

    $ oc label machineconfigpool worker custom-kubelet=small-pods

步骤

  1. 为配置更改创建自定义资源 (CR)。

    max-pods CR 配置示例

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: set-max-pods 1
    spec:
      machineConfigPoolSelector:
        matchLabels:
          pools.operator.machineconfiguration.openshift.io/worker: "" 2
      kubeletConfig:
        podsPerCore: 10 3
        maxPods: 250 4

    1
    为 CR 分配一个名称。
    2
    指定机器配置池中的标签。
    3
    根据节点的处理器内核数限制节点上可运行的 pod 数量。
    4
    将节点上可运行的 pod 数量指定为一个固定值,而不考虑节点的属性。
    注意

    podsPerCore 设置为 0 可禁用这个限制。

    在上例中,podsPerCore 的默认值为 10maxPods 的默认值则为 250。这意味着,除非节点有 25 个以上的内核,否则 podsPerCore 就是默认的限制因素。

  2. 运行以下命令来创建 CR:

    $ oc create -f <file_name>.yaml

验证

  1. 列出 MachineConfigPool CRD 以查看是否应用了更改。如果 Machine Config Controller 抓取到更改,则 UPDATING 列会报告 True

    $ oc get machineconfigpools

    输出示例

    NAME     CONFIG                        UPDATED   UPDATING   DEGRADED
    master   master-9cc2c72f205e103bb534   False     False      False
    worker   worker-8cecd1236b33ee3f8a5e   False     True       False

    更改完成后,UPDATED 列会报告 True

    $ oc get machineconfigpools

    输出示例

    NAME     CONFIG                        UPDATED   UPDATING   DEGRADED
    master   master-9cc2c72f205e103bb534   False     True       False
    worker   worker-8cecd1236b33ee3f8a5e   True      False      False

5.5. 使用 Node Tuning Operator

了解 Node Tuning Operator,以及如何使用它通过编排 tuned 守护进程以管理节点级别的性能优化。

Node Tuning Operator 可以帮助您通过编排 TuneD 守护进程来管理节点级别的性能优化,并使用 Performance Profile 控制器获得低延迟性能。大多数高性能应用程序都需要一定程度的内核级性能优化。Node Tuning Operator 为用户提供了一个统一的、节点一级的 sysctl 管理接口,并可以根据具体用户的需要灵活地添加自定义性能优化设置。

Operator 将为 OpenShift Container Platform 容器化 TuneD 守护进程作为一个 Kubernetes 守护进程集进行管理。它保证了自定义性能优化设置以可被守护进程支持的格式传递到在集群中运行的所有容器化的 TuneD 守护进程中。相应的守护进程会在集群的所有节点上运行,每个节点上运行一个。

在发生触发配置集更改的事件时,或通过接收和处理终止信号安全终止容器化 TuneD 守护进程时,容器化 TuneD 守护进程所应用的节点级设置将被回滚。

Node Tuning Operator 使用 Performance Profile 控制器来实现自动性能优化,从而实现 OpenShift Container Platform 应用程序的低延迟性能。集群管理员配置了性能配置集以定义节点级别的设置,例如:

  • 将内核更新至 kernel-rt。
  • 为内务选择 CPU。
  • 为运行工作负载选择 CPU。

在版本 4.1 及更高版本中,OpenShift Container Platform 标准安装中包含了 Node Tuning Operator。

注意

在早期版本的 OpenShift Container Platform 中,Performance Addon Operator 用来实现自动性能优化,以便为 OpenShift 应用程序实现低延迟性能。在 OpenShift Container Platform 4.11 及更新的版本中,这个功能是 Node Tuning Operator 的一部分。

5.5.1. 访问 Node Tuning Operator 示例规格

使用此流程来访问 Node Tuning Operator 的示例规格。

步骤

  • 运行以下命令以访问 Node Tuning Operator 示例规格:

    $ oc get Tuned/default -o yaml -n openshift-cluster-node-tuning-operator

默认 CR 旨在为 OpenShift Container Platform 平台提供标准的节点级性能优化,它只能被修改来设置 Operator Management 状态。Operator 将覆盖对默认 CR 的任何其他自定义更改。若进行自定义性能优化,请创建自己的 Tuned CR。新创建的 CR 将与默认的 CR 合并,并基于节点或 pod 标识和配置文件优先级对节点应用自定义调整。

警告

虽然在某些情况下,对 pod 标识的支持可以作为自动交付所需调整的一个便捷方式,但我们不鼓励使用这种方法,特别是在大型集群中。默认 Tuned CR 并不带有 pod 标识匹配。如果创建了带有 pod 标识匹配的自定义配置集,则该功能将在此时启用。在以后的 Node Tuning Operator 版本中将弃用 pod 标识功能。

5.5.2. 自定义调整规格

Operator 的自定义资源 (CR) 包含两个主要部分。第一部分是 profile:,这是 TuneD 配置集及其名称的列表。第二部分是 recommend:,用来定义配置集选择逻辑。

多个自定义调优规格可以共存,作为 Operator 命名空间中的多个 CR。Operator 会检测到是否存在新 CR 或删除了旧 CR。所有现有的自定义性能优化设置都会合并,同时更新容器化 TuneD 守护进程的适当对象。

管理状态

通过调整默认的 Tuned CR 来设置 Operator Management 状态。默认情况下,Operator 处于 Managed 状态,默认的 Tuned CR 中没有 spec.managementState 字段。Operator Management 状态的有效值如下:

  • Managed: Operator 会在配置资源更新时更新其操作对象
  • Unmanaged: Operator 将忽略配置资源的更改
  • Removed: Operator 将移除 Operator 置备的操作对象和资源

配置集数据

profile: 部分列出了 TuneD 配置集及其名称。

profile:
- name: tuned_profile_1
  data: |
    # TuneD profile specification
    [main]
    summary=Description of tuned_profile_1 profile

    [sysctl]
    net.ipv4.ip_forward=1
    # ... other sysctl's or other TuneD daemon plugins supported by the containerized TuneD

# ...

- name: tuned_profile_n
  data: |
    # TuneD profile specification
    [main]
    summary=Description of tuned_profile_n profile

    # tuned_profile_n profile settings

建议的配置集

profile: 选择逻辑通过 CR 的 recommend: 部分来定义。recommend: 部分是根据选择标准推荐配置集的项目列表。

recommend:
<recommend-item-1>
# ...
<recommend-item-n>

列表中的独立项:

- machineConfigLabels: 1
    <mcLabels> 2
  match: 3
    <match> 4
  priority: <priority> 5
  profile: <tuned_profile_name> 6
  operand: 7
    debug: <bool> 8
    tunedConfig:
      reapply_sysctl: <bool> 9
1
可选。
2
MachineConfig 标签的键/值字典。键必须是唯一的。
3
如果省略,则会假设配置集匹配,除非设置了优先级更高的配置集,或设置了 machineConfigLabels
4
可选列表。
5
配置集排序优先级。较低数字表示优先级更高(0 是最高优先级)。
6
在匹配项中应用的 TuneD 配置集。例如 tuned_profile_1
7
可选操作对象配置。
8
为 TuneD 守护进程打开或关闭调试。true 为打开,false 为关闭。默认值为 false
9
为 TuneD 守护进程打开或关闭 reapply_sysctl 功能。选择 true 代表开启,false 代表关闭。

<match> 是一个递归定义的可选数组,如下所示:

- label: <label_name> 1
  value: <label_value> 2
  type: <label_type> 3
    <match> 4
1
节点或 pod 标签名称。
2
可选的节点或 pod 标签值。如果省略,<label_name> 足以匹配。
3
可选的对象类型(nodepod)。如果省略,会使用 node
4
可选的 <match> 列表。

如果不省略 <match>,则所有嵌套的 <match> 部分也必须评估为 true。否则会假定 false,并且不会应用或建议具有对应 <match> 部分的配置集。因此,嵌套(子级 <match> 部分)会以逻辑 AND 运算来运作。反之,如果匹配 <match> 列表中任何一项,整个 <match> 列表评估为 true。因此,该列表以逻辑 OR 运算来运作。

如果定义 了 machineConfigLabels,基于机器配置池的匹配会对给定的 recommend: 列表项打开。<mcLabels> 指定机器配置标签。机器配置会自动创建,以在配置集 <tuned_profile_name> 中应用主机设置,如内核引导参数。这包括使用与 <mcLabels> 匹配的机器配置选择器查找所有机器配置池,并在分配了找到的机器配置池的所有节点上设置配置集 <tuned_profile_name>。要针对同时具有 master 和 worker 角色的节点,您必须使用 master 角色。

列表项 matchmachineConfigLabels 由逻辑 OR 操作符连接。match 项首先以短电路方式评估。因此,如果它被评估为 true,则不考虑 MachineConfigLabels 项。

重要

当使用基于机器配置池的匹配时,建议将具有相同硬件配置的节点分组到同一机器配置池中。不遵循这个原则可能会导致在共享同一机器配置池的两个或者多个节点中 TuneD 操作对象导致内核参数冲突。

示例:基于节点或 pod 标签的匹配

- match:
  - label: tuned.openshift.io/elasticsearch
    match:
    - label: node-role.kubernetes.io/master
    - label: node-role.kubernetes.io/infra
    type: pod
  priority: 10
  profile: openshift-control-plane-es
- match:
  - label: node-role.kubernetes.io/master
  - label: node-role.kubernetes.io/infra
  priority: 20
  profile: openshift-control-plane
- priority: 30
  profile: openshift-node

根据配置集优先级,以上 CR 针对容器化 TuneD 守护进程转换为 recommend.conf 文件。优先级最高 (10) 的配置集是 openshift-control-plane-es,因此会首先考虑它。在给定节点上运行的容器化 TuneD 守护进程会查看同一节点上是否在运行设有 tuned.openshift.io/elasticsearch 标签的 pod。如果没有,则整个 <match> 部分评估为 false。如果存在具有该标签的 pod,为了让 <match> 部分评估为 true,节点标签也需要是 node-role.kubernetes.io/masternode-role.kubernetes.io/infra

如果这些标签对优先级为 10 的配置集而言匹配,则应用 openshift-control-plane-es 配置集,并且不考虑其他配置集。如果节点/pod 标签组合不匹配,则考虑优先级第二高的配置集 (openshift-control-plane)。如果容器化 TuneD Pod 在具有标签 node-role.kubernetes.io/masternode-role.kubernetes.io/infra 的节点上运行,则应用此配置集。

最后,配置集 openshift-node 的优先级最低 (30)。它没有 <match> 部分,因此始终匹配。如果给定节点上不匹配任何优先级更高的配置集,它会作为一个适用于所有节点的配置集来设置 openshift-node 配置集。

决定工作流

示例:基于机器配置池的匹配

apiVersion: tuned.openshift.io/v1
kind: Tuned
metadata:
  name: openshift-node-custom
  namespace: openshift-cluster-node-tuning-operator
spec:
  profile:
  - data: |
      [main]
      summary=Custom OpenShift node profile with an additional kernel parameter
      include=openshift-node
      [bootloader]
      cmdline_openshift_node_custom=+skew_tick=1
    name: openshift-node-custom

  recommend:
  - machineConfigLabels:
      machineconfiguration.openshift.io/role: "worker-custom"
    priority: 20
    profile: openshift-node-custom

为尽量减少节点的重新引导情况,为目标节点添加机器配置池将匹配的节点选择器标签,然后创建上述 Tuned CR,最后创建自定义机器配置池。

特定于云供应商的 TuneD 配置集

使用此功能,所有针对于 OpenShift Container Platform 集群上的云供应商都可以方便地分配 TuneD 配置集。这可实现,而无需添加额外的节点标签或将节点分组到机器配置池中。

这个功能会利用 spec.providerID 节点对象值(格式为 <cloud-provider>://<cloud-provider-specific-id>),并在 NTO operand 容器中写带有 <cloud-provider> 值的文件 /var/lib/tuned/provider。然后,TuneD 会使用这个文件的内容来加载 provider-<cloud-provider> 配置集(如果这个配置集存在)。

openshift 配置集(openshift-control-planeopenshift-node 配置集都从其中继承设置)现在被更新来使用这个功能(通过使用条件配置集加载)。NTO 或 TuneD 目前不提供任何特定云供应商的配置集。但是,您可以创建一个自定义配置集 provider-<cloud-provider>,它将适用于所有针对于所有云供应商的集群节点。

GCE 云供应商配置集示例

apiVersion: tuned.openshift.io/v1
kind: Tuned
metadata:
  name: provider-gce
  namespace: openshift-cluster-node-tuning-operator
spec:
  profile:
  - data: |
      [main]
      summary=GCE Cloud provider-specific profile
      # Your tuning for GCE Cloud provider goes here.
    name: provider-gce

注意

由于配置集的继承,provider-<cloud-provider> 配置集中指定的任何设置都会被 openshift 配置集及其子配置集覆盖。

5.5.3. 在集群中设置默认配置集

以下是在集群中设置的默认配置集。

apiVersion: tuned.openshift.io/v1
kind: Tuned
metadata:
  name: default
  namespace: openshift-cluster-node-tuning-operator
spec:
  profile:
  - data: |
      [main]
      summary=Optimize systems running OpenShift (provider specific parent profile)
      include=-provider-${f:exec:cat:/var/lib/tuned/provider},openshift
    name: openshift
  recommend:
  - profile: openshift-control-plane
    priority: 30
    match:
    - label: node-role.kubernetes.io/master
    - label: node-role.kubernetes.io/infra
  - profile: openshift-node
    priority: 40

从 OpenShift Container Platform 4.9 开始,所有 OpenShift TuneD 配置集都随 TuneD 软件包一起提供。您可以使用 oc exec 命令查看这些配置集的内容:

$ oc exec $tuned_pod -n openshift-cluster-node-tuning-operator -- find /usr/lib/tuned/openshift{,-control-plane,-node} -name tuned.conf -exec grep -H ^ {} \;

5.5.4. 支持的 TuneD 守护进程插件

在使用 Tuned CR 的 profile: 部分中定义的自定义配置集时,以下 TuneD 插件都受到支持,但 [main] 部分除外:

  • audio
  • cpu
  • disk
  • eeepc_she
  • modules
  • mounts
  • net
  • scheduler
  • scsi_host
  • selinux
  • sysctl
  • sysfs
  • usb
  • video
  • vm
  • bootloader

其中一些插件提供了不受支持的动态性能优化功能。目前不支持以下 TuneD 插件:

  • script
  • systemd
警告

目前,Red Hat Enterprise Linux CoreOS(RHCOS)8.x worker 节点上支持 TuneD bootloader 插件。对于 Red Hat Enterprise Linux(RHEL)7.x worker 节点,目前不支持 TuneD 引导装载程序插件。

如需更多信息,请参阅 Available TuneD Plug-insGetting Started with TuneD

5.6. 补救、隔离和维护

5.6.1. 关于节点补救、隔离和维护

硬件是 imperfect,软件包含 bug。当节点级别的故障(如内核挂起或网络接口控制器(NIC))失败时,集群所需的工作不会减少,并且受影响节点的工作负载需要在哪里重启。但是,一些工作负载(如 ReadWriteOnce (RWO) 卷和 StatefulSets)可能需要最少的语义。

影响这些工作负载的风险、损坏或两者的故障。在启动恢复工作负载(称为 补救 和理想情况)之前,确保节点达到安全状态(称为 隔离 )。

并不总是依赖于管理员干预来确认节点和工作负载的真正状态。为便于实现此类干预,OpenShift Container Platform 为自动化失败检测、隔离和修复提供了多个组件。

5.6.1.1. 自助服务修复

Self Node Remediation Operator 是一个 OpenShift Container Platform 附加组件 Operator,它实现了隔离的外部系统,并补救重启不健康的节点并删除资源,如 Pod 和 VolumeAttachments。重启可确保工作负载被隔离,资源删除会加快重新调度受影响工作负载。与其他外部系统不同,自助节点修复不需要任何管理界面,如智能平台管理接口 (IPMI) 或用于节点置备的 API。

失败的检测系统可以使用自助服务修复,如 Machine Health Check 或 Node Health Check。

5.6.1.2. 机器健康检查

Machine Health Check 使用 OpenShift Container Platform 内置故障检测、隔离和补救系统,用于监控机器的状态以及节点状况。机器健康检查可以被配置为触发外部隔离和修复系统,如自助节点修复。

5.6.1.3. 节点健康检查

Node Health Check Operator 是一个 OpenShift Container Platform 附加组件 Operator,它实现了一个监控节点状况的失败检测系统。它没有内置的隔离或补救系统,因此必须使用提供此类功能的外部系统进行配置。默认情况下,它被配置为使用 Self Node Remediation 系统。

5.6.1.4. 节点维护

管理员面临需要中断集群的情况,例如替换驱动器、RAM 或 NIC。

在此维护之前,应该对受影响的节点进行封锁并排空。当节点被封锁时,无法将新的工作负载调度到该节点上。当节点排空时,为了避免或最小化停机时间,受影响节点上的工作负载将传送到其他节点。

虽然此维护可以使用命令行工具实现,但 Node Maintenance Operator 提供了使用自定义资源来实现此目的的声明方法。当节点存在此类资源时,Operator 会封锁并排空节点,直到资源被删除为止。

5.6.2. 使用自节点修复

您可以使用 Self Node Remediation Operator 自动重新引导不健康的节点。此补救策略可最小化有状态应用程序和 ReadWriteOnce (RWO) 卷的停机时间,并在发生临时故障时恢复计算容量。

5.6.2.1. 关于自助服务修复 Operator

Self Node Remediation Operator 在集群节点上运行,并重启被识别为不健康的节点。Operator 使用 MachineHealthCheckNodeHealthCheck 控制器来检测集群中节点的健康状态。当节点识别为不健康时,MachineHealthCheckNodeHealthCheck 资源会创建 SelfNodeRemediation 自定义资源(CR),这会触发 Self Node Remediation Operator。

SelfNodeRemediation CR 类似于以下 YAML 文件:

apiVersion: self-node-remediation.medik8s.io/v1alpha1
kind: SelfNodeRemediation
metadata:
  name: selfnoderemediation-sample
  namespace: openshift-operators
spec:
status:
  lastError: <last_error_message> 1
1
显示补救过程中发生的最后错误。当补救成功或没有发生错误时,字段会留空。

Self Node Remediation Operator 最小化有状态应用程序的停机时间,并在出现临时故障时恢复计算容量。无论 IPMI 或 API 等管理界面如何置备节点,都可使用此 Operator 来置备节点,无论集群安装类型是什么,如安装程序置备的基础架构或用户置备的基础架构。

5.6.2.1.1. 关于 watchdog 设备

watchdog 设备可以是以下任意一种:

  • 独立电源的硬件设备
  • 与它们控制的主机共享电源的硬件设备
  • 软件或 softdog中实施的虚拟设备

硬件 watchdog 和 softdog 设备分别具有电子计时器和软件计时器。这些 watchdog 设备用于确保在检测到错误条件时机器进入安全状态。集群需要重复重置 watchdog 定时器以证明它处于健康状态。此计时器可能会因为出现错误条件而造成问题,如死锁、CPU 不足以及网络或磁盘访问的丢失。如果计时器过期,watchdog 设备会假设发生了错误,设备会触发强制重置节点。

硬件 watchdog 设备比 softdog 设备更可靠。

5.6.2.1.1.1. 了解 watchdog 设备的自助服务修复 Operator 行为

Self Node Remediation Operator 根据存在的 watchdog 设备决定补救策略。

如果配置了硬件 watchdog 设备并可用,Operator 会使用它进行补救。如果没有配置硬件 watchdog 设备,Operator 会启用并使用 softdog 设备进行补救。

如果既不支持 watchdog 设备,无论是系统或配置,Operator 都会使用软件重启来修复节点。

其他资源

配置 watchdog

5.6.2.2. control plane 隔离

在早期版本中,您可以在 worker 节点上启用自节点修复和 Node Health Check。如果节点失败,您现在可以在 control plane 节点上遵循补救策略。

在两种主要场景中进行自助服务修复。

  • API 服务器连接

    • 在这种情况下,要修复的 control plane 节点不会被隔离。它可以直接连接到 API 服务器,或者可以通过 worker 节点或 control-plane 节点间接连接到 API 服务器,这些节点直接连接到 API 服务器。
    • 当有 API 服务器连接时,只有在 Node Health Check Operator 为节点创建了 SelfNodeRemediation 自定义资源(CR)时,才会修复 control plane 节点。
  • 没有 API 服务器连接

    • 在这种情况下,要修复的 control plane 节点与 API 服务器隔离。节点无法直接连接或间接连接到 API 服务器。
    • 如果没有 API 服务器连接,则 control plane 节点将按照以下步骤进行修复:

      • 使用大多数对等 worker 节点检查 control plane 节点的状态。如果无法访问大多数对等 worker 节点,则会进一步分析该节点。

        • 自我诊断 control plane 节点的状态

          • 如果通过自我诊断,则不会执行任何操作。
          • 如果自我诊断失败,则该节点将被隔离并修复。
          • 目前支持的自诊断是使用 opt in 配置检查 kubelet 服务状态,以及检查端点的可用性。
      • 如果节点没有管理与大多数 worker 对等点通信,请检查 control plane 节点与其他 control plane 节点的连接。如果节点可以与任何其他 control plane peer 通信,则不会执行任何操作。否则,节点将被隔离并修复。

5.6.2.3. 使用 web 控制台安装 Self Node Remediation Operator

您可以使用 OpenShift Container Platform Web 控制台安装 Self Node Remediation Operator。

注意

Node Health Check Operator 还将 Self Node Remediation Operator 安装为默认的补救提供程序。

先决条件

  • 以具有 cluster-admin 特权的用户身份登录。

步骤

  1. 在 OpenShift Container Platform Web 控制台中导航至 OperatorsOperatorHub
  2. 从可用的 Operator 列表中选择 Self Node Remediation Operator,然后点 Install
  3. 保留安装模式命名空间的默认选择,以确保将 Operator 安装到 openshift-operators 命名空间中。
  4. Install

验证

确认安装成功:

  1. 进入到 OperatorsInstalled Operators 页面。
  2. 检查 Operator 是否安装在 openshift-operators 命名空间中,其状态是否为 Succeeded

如果 Operator 没有成功安装:

  1. 导航到 OperatorsInstalled Operators 页面,并检查 Status 列中是否有任何错误或故障。
  2. 进入 WorkloadsPods 页面,并检查在 self-node-remediation-controller-manager 项目中报告问题的 pod 的日志。

5.6.2.4. 使用 CLI 安装自助服务 Operator

您可以使用 OpenShift CLI(oc)安装 Self Node Remediation Operator。

您可以在自己的命名空间中或 openshift-operators 命名空间中安装 Self Node Remediation Operator。

要在您自己的命名空间中安装 Operator,请按照以下步骤执行。

要在 openshift-operators 命名空间中安装 Operator,请跳至步骤 3,因为需要新的 Namespace 自定义资源(CR)和 OperatorGroup CR 的步骤。

先决条件

  • 安装 OpenShift CLI(oc)。
  • 以具有 cluster-admin 特权的用户身份登录。

步骤

  1. 为 Self Node Remediation Operator 创建 Namespace 自定义资源(CR):

    1. 定义 Namespace CR 并保存 YAML 文件,如 self-node-remediation-namespace.yaml

      apiVersion: v1
      kind: Namespace
      metadata:
        name: self-node-remediation
    2. 要创建 Namespace CR,请运行以下命令:

      $ oc create -f self-node-remediation-namespace.yaml
  2. 创建 OperatorGroup CR:

    1. 定义 OperatorGroup CR 并保存 YAML 文件,如 self-node-remediation-operator-group.yaml

      apiVersion: operators.coreos.com/v1
      kind: OperatorGroup
      metadata:
        name: self-node-remediation-operator
        namespace: self-node-remediation
    2. 要创建 OperatorGroup CR,请运行以下命令:

      $ oc create -f self-node-remediation-operator-group.yaml
  3. 创建一个 Subscription CR:

    1. 定义 Subscription CR 并保存 YAML 文件,如 self-node-remediation-subscription.yaml

      apiVersion: operators.coreos.com/v1alpha1
      kind: Subscription
      metadata:
          name: self-node-remediation-operator
          namespace: self-node-remediation 1
      spec:
          channel: stable
          installPlanApproval: Manual 2
          name: self-node-remediation-operator
          source: redhat-operators
          sourceNamespace: openshift-marketplace
          package: self-node-remediation
      1
      指定要安装 Self Node Remediation Operator 的命名空间。要在 openshift-operators 命名空间中安装 Self Node Remediation Operator,在 Subscription CR 中指定 openshift-operators
      2
      如果您的指定版本被目录中的后续版本取代,则将批准策略设置为 Manual。此计划阻止自动升级到更新的版本,且需要在启动 CSV 可以完成安装前手动批准。
    2. 要创建 Subscription CR,请运行以下命令:

      $ oc create -f self-node-remediation-subscription.yaml

验证

  1. 检查 CSV 资源来验证安装是否成功:

    $ oc get csv -n self-node-remediation

    输出示例

    NAME                               DISPLAY                          VERSION   REPLACES   PHASE
    self-node-remediation.v.0.4.0      Self Node Remediation Operator   v.0.4.0              Succeeded

  2. 验证 Self Node Remediation Operator 是否正在运行:

    $ oc get deploy -n self-node-remediation

    输出示例

    NAME                                        READY   UP-TO-DATE   AVAILABLE   AGE
    self-node-remediation-controller-manager    1/1     1            1           28h

  3. 验证 Self Node Remediation Operator 是否已创建 SelfNodeRemediationConfig CR:

    $ oc get selfnoderemediationconfig -n self-node-remediation

    输出示例

    NAME                           AGE
    self-node-remediation-config   28h

  4. 验证每个自节点补救 pod 是否已调度并在每个 worker 节点上运行:

    $ oc get daemonset -n self-node-remediation

    输出示例

    NAME                      DESIRED  CURRENT  READY  UP-TO-DATE  AVAILABLE  NODE SELECTOR  AGE
    self-node-remediation-ds  3        3        3      3           3          <none>         28h

    注意

    control plane 节点不支持这个命令。

5.6.2.5. 配置自节点修复 Operator

Self Node Remediation Operator 创建 SelfNodeRemediationConfig CR 和 SelfNodeRemediationTemplate 自定义资源定义(CRD)。

5.6.2.5.1. 了解 Self Node Remediation Operator 配置

Self Node Remediation Operator 创建了名为 self-node-remediation-configSelfNodeRemediationConfig CR。CR 在 Self Node Remediation Operator 的命名空间中创建。

SelfNodeRemediationConfig CR 的更改重新创建 Self Node Remediation 守护进程集。

SelfNodeRemediationConfig CR 类似于以下 YAML 文件:

apiVersion: self-node-remediation.medik8s.io/v1alpha1
kind: SelfNodeRemediationConfig
metadata:
  name: self-node-remediation-config
  namespace: openshift-operators
spec:
  safeTimeToAssumeNodeRebootedSeconds: 180 1
  watchdogFilePath: /dev/watchdog 2
  isSoftwareRebootEnabled: true 3
  apiServerTimeout: 15s 4
  apiCheckInterval: 5s 5
  maxApiErrorThreshold: 3 6
  peerApiServerTimeout: 5s 7
  peerDialTimeout: 5s 8
  peerRequestTimeout: 5s 9
  peerUpdateInterval: 15m 10
1
指定存活对等点的超时持续时间,然后 Operator 可以假定一个不健康的节点已被重启。Operator 自动计算这个值的下限。但是,如果不同的节点有不同的 watchdog 超时,则必须将此值改为更高的值。
2
指定节点中 watchdog 设备的文件路径。如果您为 watchdog 设备输入了一个错误的路径,则 Self Node Remediation Operator 会自动检测到 softdog 设备路径。

如果 watchdog 设备不可用,则 SelfNodeRemediationConfig CR 将使用软件重启。

3
指定是否启用不健康节点的软件重启。默认情况下,SoftwareRebootEnabled 的值设置为 true。要禁用软件重启,请将参数设置为 false
4
指定检查每个 API 服务器的连接的超时持续时间。此超过了此持续时间,Operator 会启动补救。超时持续时间必须大于或等于 10 毫秒。
5
指定检查每个 API 服务器的连接的频率。超时持续时间必须大于或等于 1 秒。
6
指定一个阈值。达到这个阈值后,节点开始联系其同级服务器。阈值必须大于或等于 1 秒。
7
指定对等对等服务器连接 API 服务器的超时时间。超时持续时间必须大于或等于 10 毫秒。
8
指定与对等连接建立超时的持续时间。超时持续时间必须大于或等于 10 毫秒。
9
指定超时从对等点获得响应的时长。超时持续时间必须大于或等于 10 毫秒。
10
指定更新对等信息的频率,如 IP 地址。超时持续时间必须大于或等于 10 秒。
注意

您可以编辑由 Self Node Remediation Operator 创建的 self-node-remediation-config CR。但是,当您尝试为 Self Node Remediation Operator 创建新 CR 时,日志中会显示以下信息:

controllers.SelfNodeRemediationConfig
ignoring selfnoderemediationconfig CRs that are not named 'self-node-remediation-config'
or not in the namespace of the operator:
'openshift-operators' {"selfnoderemediationconfig":
"openshift-operators/selfnoderemediationconfig-copy"}
5.6.2.5.2. 了解自助节点修复模板配置

Self Node Remediation Operator 还创建 SelfNodeRemediationTemplate 自定义资源定义(CRD)。此 CRD 为节点定义补救策略。可用的补救策略如下:

ResourceDeletion
此补救策略移除节点上的 pod 和关联的卷附加,而不是节点对象。此策略有助于更快地恢复工作负载。ResourceDeletion 是默认的补救策略。
NodeDeletion
此补救策略已弃用,并将在以后的发行版本中删除。在当前发行版本中,即使选择了 NodeDeletion 策略,也会使用 ResourceDeletion 策略。

Self Node Remediation Operator 为策略 self-node-remediation-resource-deletion-template 创建 SelfNodeRemediationTemplate CR,其 ResourceDeletion 补救策略使用。

SelfNodeRemediationTemplate CR 类似于以下 YAML 文件:

apiVersion: self-node-remediation.medik8s.io/v1alpha1
kind: SelfNodeRemediationTemplate
metadata:
  creationTimestamp: "2022-03-02T08:02:40Z"
  name: self-node-remediation-<remediation_object>-deletion-template 1
  namespace: openshift-operators
spec:
  template:
    spec:
      remediationStrategy: <remediation_strategy>  2
1
根据补救策略指定补救模板的类型。将 <remediation_object> 替换为 resourcenode; 例如 self-node-remediation-resource-deletion-template
2
指定补救策略。补救策略是 ResourceDeletion

5.6.2.6. 对自节点修复 Operator 进行故障排除

5.6.2.6.1. 常规故障排除
问题
您需要使用自助服务修复 Operator 排除问题。
解决方案
检查 Operator 日志。
5.6.2.6.2. 检查守护进程集
问题
已安装 Self Node Remediation Operator,但守护进程集不可用。
解决方案
检查 Operator 日志中的错误或警告。
5.6.2.6.3. 失败的补救
问题
一个不健康的节点没有被修复。
解决方案

运行以下命令验证 selfNodeRemediation CR 是否已创建:

$ oc get snr -A

当节点处于不健康状态时,如果 MachineHealthCheck 控制器没有创建 SelfNodeRemediation CR,请检查 MachineHealthCheck 控制器的日志。此外,请确保 MachineHealthCheck CR 包含使用补救模板所需的规范。

如果创建了 SelfNodeRemediation CR,请确保其名称与不健康的节点或机器对象匹配。

5.6.2.6.4. 即使在卸载了 Operator 后,守护进程集和其他自节点修复 Operator 资源也存在
问题
即使卸载 Operator 后,也会存在 Self Node Remediation Operator 资源,如守护进程集、配置 CR 和补救模板 CR。
解决方案

要删除 Self Node Remediation Operator 资源,请运行以下命令来删除每种资源类型的资源:

$ oc delete ds <self-node-remediation-ds> -n <namespace>
$ oc delete snrc <self-node-remediation-config> -n <namespace>
$ oc delete snrt <self-node-remediation-template> -n <namespace>

5.6.2.7. 收集自节点修复 Operator 的数据

要收集有关自助服务修复 Operator 的调试信息,请使用 must-gather 工具。有关自助 Node Remediation Operator 的 must-gather 镜像的详情,请参阅收集特定功能的数据

5.6.2.8. 其他资源

5.6.3. 使用机器健康检查修复节点

机器健康检查自动修复特定机器池中不健康的机器。

5.6.3.1. 关于机器健康检查

注意

您只能对使用 control plane 机器集的集群中的 control plane 机器应用机器健康检查。

要监控机器的健康状况,创建资源来定义控制器的配置。设置要检查的条件(例如,处于 NotReady 状态达到五分钟或 node-problem-detector 中显示了持久性状况)