5.9. 在容器中使用 sysctl

Sysctl 设置可以通过 Kubernetes 来公开,允许用户在运行时为容器内的命名空间修改某些内核参数。只有拥有命名空间的 sysctl 才能独立于 pod 进行设置。如果 sysctl 没有命名空间,则称为节点级别,无法在 OpenShift Container Platform 中设置。此外,只有被认为是安全的 sysctl 才会默认列在白名单中;您可以在节点上手动启用其他不安全 sysctl 来供用户使用。

5.9.1. 关于 sysctl

在 Linux 中,管理员可通过 sysctl 接口在运行时修改内核参数。参数可通过 /proc/sys/ 虚拟进程文件系统提供。这些参数涵盖了各种不同的子系统,例如:

  • 内核(通用前缀:kernel.
  • 网络(通用前缀:net.
  • 虚拟内存(通用前缀:vm.
  • MDADM(通用前缀:dev.

如需了解更多子系统,请参阅 Kernel 文档。要获取所有参数的列表,请运行:

$ sudo sysctl -a

5.9.1.1. 命名空间和节点级 sysctl

许多 sysctl 在 Linux 内核中是有命名空间的。这意味着您可以针对节点上的每个 pod 单独设置它们。sysctl 必须拥有命名空间,才能在 Kubernetes 内的 pod 上下文中访问它们。

以下 sysctl 已知是拥有命名空间的:

  • kernel.shm*
  • kernel.msg*
  • kernel.sem
  • fs.mqueue.*

另外,net.* 组中的大多数 sysctl 都已知是拥有命名空间的。其命名空间的采用根据内核版本和发行方而有所不同。

无命名空间的 sysctl 被视为节点级别,且必须由集群管理员手动设置,或者通过使用节点的底层 Linux 发行版,如修改 /etc/sysctls.conf 文件,或者通过使用带有特权容器的 DaemonSet。

注意

可以考虑将带有特殊 sysctl 节点标记为污点。仅将 pod 调度到需要这些 sysctl 设置的节点。使用污点和容限功能来标记节点。

5.9.1.2. 安全与不安全 sysctl

sysctl 划分为安全不安全 sysctl。

sysctl 若要被视为安全,必须使用正确的命名空间,且必须在同一节点的不同 pod 之间进行适当的隔离。也就是说,如果您为一个 pod 设置了 sysctl,它不得:

  • 影响节点上的其他任何 pod
  • 危害节点的健康
  • 获取超过 pod 资源限制的 CPU 或内存资源

OpenShift Container Platform 支持(或列入白名单)安全集合中的以下 sysctl:

  • kernel.shm_rmid_forced
  • net.ipv4.ip_local_port_range
  • net.ipv4.tcp_syncookies

所有安全 sysctl 都默认启用。您可以通过修改 pod 规格在 pod 中使用 sysctl。

任何未在 OpenShift Container Platform 白名单中列出的 sysctl 都被视为对 OpenShift Container Platform 而言不安全。请注意,仅拥有命名空间还不足以使 sysctl 被视为安全。

所有不安全 sysctl 都默认禁用,集群管理员必须逐个节点手动启用它们。禁用了不安全 sysctl 的 Pod 会被调度,但不会启动。

$ oc get pod

NAME        READY   STATUS            RESTARTS   AGE
hello-pod   0/1     SysctlForbidden   0          14s

5.9.2. 为 pod 设置 sysctl

您可以使用 pod 的 securityContext 在 pod 上设置 sysctl。securityContext 适用于同一 pod 中的所有容器。

默认允许安全 sysctl。带有不安全 sysctl 的 pod 无法在任何节点上启动,除非集群管理员在某个节点上明确启用了不安全 sysctl。与节点级 sysctl 一样,使用污点和容限功能或节点上的标签将这些 pod 调度到正确的节点。

以下示例使用 pod securityContext 设置一个安全 sysctl kernel.shm_rmid_forced,以及两个不安全 sysctl net.ipv4.route.min_pmtukernel.msgmax。在规格中,安全不安全 sysctl 并无区别。

警告

为了避免让操作系统变得不稳定,只有在了解了参数的作用后才修改 sysctl 参数。

流程

使用安全和不安全 sysctl:

  1. 修改定义 pod 的 YAML 文件并添加 securityContext 规格,如下例所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sysctl-example
    spec:
      securityContext:
        sysctls:
        - name: kernel.shm_rmid_forced
          value: "0"
        - name: net.ipv4.route.min_pmtu
          value: "552"
        - name: kernel.msgmax
          value: "65536"
      ...
  2. 创建 pod:

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

    如果节点不允许不安全 sysctl,则 pod 会被调度,但不会部署:

    $ oc get pod
    
    NAME        READY   STATUS            RESTARTS   AGE
    hello-pod   0/1     SysctlForbidden   0          14s

5.9.3. 启用不安全 sysctl

集群管理员可在非常特殊的情况下允许某些不安全 sysctl,比如高性能或实时应用程序性能优化。

如果要使用不安全 sysctl,集群管理员必须为特定类型的节点单独启用它们。sysctl 必须拥有命名空间。

警告

由于其不安全特性,使用不安全 sysctl 的风险由您自行承担,而且可能会造成严重问题,例如容器行为不当、资源短缺或节点受损。

流程

  1. 在要运行带有不安全 sysctl 的容器的 MachineConfigPool 中添加标签:

    $ oc edit machineconfigpool worker
    apiVersion: machineconfiguration.openshift.io/v1
    kind: MachineConfigPool
    metadata:
      creationTimestamp: 2019-02-08T14:52:39Z
      generation: 1
      labels:
        custom-kubelet: sysctl 1
    1
    添加 key: pair 标签。
  2. 创建 KubeletConfig 自定义资源 (CR):

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: custom-kubelet
    spec:
      machineConfigPoolSelector:
        matchLabels:
          custom-kubelet: sysctl 1
      kubeletConfig:
        allowedUnsafeSysctls: 2
          - "kernel.msg*"
          - "net.ipv4.route.min_pmtu"
    1
    指定来自 MachineConfigPool 的标签。
    2
    列出您想要允许的不安全 sysctl。
  3. 创建对象:

    $ oc apply -f set-sysctl-worker.yaml

    创建了名称采用 99-worker-XXXXXX-XXXXX-XXXX-XXXXX-kubelet 格式的 MachineConfig。

  4. 使用 machineconfigpool 对象 status 字段等待集群重启:

    例如:

    status:
      conditions:
        - lastTransitionTime: '2019-08-11T15:32:00Z'
          message: >-
            All nodes are updating to
            rendered-worker-ccbfb5d2838d65013ab36300b7b3dc13
          reason: ''
          status: 'True'
          type: Updating

    集群就绪时会显示类似如下的消息:

       - lastTransitionTime: '2019-08-11T16:00:00Z'
          message: >-
            All nodes are updated with
            rendered-worker-ccbfb5d2838d65013ab36300b7b3dc13
          reason: ''
          status: 'True'
          type: Updated
  5. 集群就绪后,在新的 MachineConfig 中检查合并的 KubeletConfig

    $ oc get machineconfig 99-worker-XXXXXX-XXXXX-XXXX-XXXXX-kubelet -o json | grep ownerReference -A7
            "ownerReferences": [
                {
                    "apiVersion": "machineconfiguration.openshift.io/v1",
                    "blockOwnerDeletion": true,
                    "controller": true,
                    "kind": "KubeletConfig",
                    "name": "custom-kubelet",
                    "uid": "3f64a766-bae8-11e9-abe8-0a1a2a4813f2"

    现在,您可以根据需要为 pod 添加不安全 sysctl。