7.9. 在容器中使用 sysctl

sysctl 设置通过 Kubernetes 公开,允许用户在运行时修改某些内核参数。只有拥有命名空间的 sysctl 才能独立于 pod 进行设置。如果 sysctl 没有命名空间(称为节点级别),则必须使用其他方法设置 sysctl,如使用 Node Tuning Operator。

网络 sysctl 是特殊的 sysctl 类别。网络 sysctl 包括:

  • 系统范围的 sysctl,如 net.ipv4.ip_local_port_range,适用于所有网络。您可以针对节点上的每个 pod 独立设置它们。
  • 特定于接口的 sysctl,如 net.ipv4.conf.IFNAME.accept_local,它们只适用于给定 pod 的特定额外网络接口。您可以为每个额外网络配置独立设置它们。您可以在网络接口创建后使用 tuning-cni 中的配置来设置它们。

此外,只有被认为是安全的 sysctl 才会默认列在白名单中;您可以在节点上手动启用其他不安全 sysctl 来供用户使用。

其他资源

7.9.1. 关于 sysctl

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

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

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

$ sudo sysctl -a

7.9.2. 命名空间和节点级 sysctl

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

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

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

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

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

注意

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

7.9.3. 安全和不安全 sysctl

sysctl 划分为安全不安全 sysctl。

要使系统范围 sysctl 被视为安全,必须具有命名空间。命名空间的 sysctl 可确保命名空间之间有隔离,因此 pod 会被隔离。如果为一个 pod 设置 sysctl,则不能添加以下任一 pod:

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

仅拥有命名空间还不足以使 sysctl 被视为安全。

任何未添加到 OpenShift Container Platform 上允许列表中的 sysctl 都被视为对 OpenShift Container Platform 而言是不安全的。

默认不允许不安全 sysctl。对于系统范围的 sysctl,集群管理员必须基于每个节点手动启用它们。禁用了不安全 sysctl 的 Pod 会被调度,但不会启动。

注意

您不能手动启用特定于接口的不安全 sysctl。

OpenShift Container Platform 将以下系统范围和特定于接口的安全 sysctl 添加到允许的安全列表中:

表 7.4. 系统范围安全 sysctl

sysctl描述

kernel.shm_rmid_forced

当设置为 1 时,当前 IPC 命名空间中的所有共享内存对象会自动强制使用 IPC_RMID。如需更多信息,请参阅 shm_rmid_forced

net.ipv4.ip_local_port_range

定义 TCP 和 UDP 用于选择本地端口的本地端口范围。第一个数字是第一个端口号,第二个数字是最后一个本地端口号。如果可能,如果这些数字有不同的奇偶校验(甚至一个单数值)。它们必须大于或等于 ip_unprivileged_port_start。默认值为 3276860999。如需更多信息,请参阅 ip_local_port_range

net.ipv4.tcp_syncookies

当设置了 net.ipv4.tcp_syncookies 时,内核通常会处理 TCP SYN 数据包,直至半开连接队列已满(此时SY cookie 功能启动)。这个功能允许系统接受有效连接,即使受拒绝服务攻击也是如此。如需更多信息,请参阅 tcp_syncookies

net.ipv4.ping_group_range

这将限制 ICMP_PROTO 数据报套接字到组范围内的用户。默认值为 1 0,代表没有用户可以创建 ping 套接字(即使是 root 也不行)。有关更多信息,请参阅 ping_group_range

net.ipv4.ip_unprivileged_port_start

这将定义网络命名空间中的第一个无特权端口。要禁用所有特权端口,将其设置为 0。特权端口不得与 ip_local_port_range 重叠。有关更多信息,请参阅 ip_unprivileged_port_start

表 7.5. 特定于接口的安全 sysctl

sysctl描述

net.ipv4.conf.IFNAME.accept_redirects

接受 IPv4 ICMP 重定向消息。

net.ipv4.conf.IFNAME.accept_source_route

接受带有严格的源路由(SRR)选项的 IPv4 数据包。

net.ipv4.conf.IFNAME.arp_accept

使用没有出现在 ARP 表中的 IPv4 地址定义抓取 ARP 帧的行为:

  • 0 - 不在 ARP 表中创建新条目。
  • 1 - 在 ARP 表中创建新条目。

net.ipv4.conf.IFNAME.arp_notify

定义 IPv4 地址和设备更改通知的模式。

net.ipv4.conf.IFNAME.disable_policy

禁用这个 IPv4 接口的 IPSEC 策略(SPD)。

net.ipv4.conf.IFNAME.secure_redirects

接受 ICMP 将消息重定向到接口当前网关列表中列出的网关。

net.ipv4.conf.IFNAME.send_redirects

只有当节点充当路由器时,才会启用发送重定向。也就是说,主机不应发送 ICMP 重定向消息。路由器使用它来通知主机与特定目的地可用的更好路由路径。

net.ipv6.conf.IFNAME.accept_ra

接受 IPv6 路由器公告;使用它们自动配置。它还决定是否传输路由器请求。只有功能设置要接受路由器播发时,才会传输路由器请求。

net.ipv6.conf.IFNAME.accept_redirects

接受 IPv6 ICMP 重定向消息。

net.ipv6.conf.IFNAME.accept_source_route

接受带有 SRR 选项的 IPv6 数据包。

net.ipv6.conf.IFNAME.arp_accept

使用没有出现在 ARP 表中的 IPv6 地址定义抓取 ARP 帧的行为:

  • 0 - 不在 ARP 表中创建新条目。
  • 1 - 在 ARP 表中创建新条目。

net.ipv6.conf.IFNAME.arp_notify

定义 IPv6 地址和设备更改通知的模式。

net.ipv6.neigh.IFNAME.base_reachable_time_ms

这个参数控制 IPv6 的邻居表中的硬件地址到 IP 映射生命周期。

net.ipv6.neigh.IFNAME.retrans_time_ms

为邻居发现消息设置重新传输计时器。

注意

当使用 tuning CNI 插件设置这些值时,请按字面使用值 IFNAME。接口名称由 IFNAME 令牌表示,并替换为在运行时接口的实际名称。

7.9.4. 更新特定于接口的安全 sysctl 列表

OpenShift Container Platform 包含预定义的安全接口 sysctl 列表。您可以通过更新 openshift-multus 命名空间中的 cni-sysctl-allowlist 来修改此列表。

重要

更新特定于接口的安全 sysctl 列表的支持只是一个技术预览功能。技术预览功能不受红帽产品服务等级协议(SLA)支持,且功能可能并不完整。红帽不推荐在生产环境中使用它们。这些技术预览功能可以使用户提早试用新的功能,并有机会在开发阶段提供反馈意见。

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

按照以下步骤修改预定义的安全 sysctl 列表。这个步骤描述了如何扩展默认允许列表。

流程

  1. 运行以下命令来查看现有的预定义列表:

    $ oc get cm -n openshift-multus cni-sysctl-allowlist -oyaml

    预期输出

    apiVersion: v1
    data:
      allowlist.conf: |-
        ^net.ipv4.conf.IFNAME.accept_redirects$
        ^net.ipv4.conf.IFNAME.accept_source_route$
        ^net.ipv4.conf.IFNAME.arp_accept$
        ^net.ipv4.conf.IFNAME.arp_notify$
        ^net.ipv4.conf.IFNAME.disable_policy$
        ^net.ipv4.conf.IFNAME.secure_redirects$
        ^net.ipv4.conf.IFNAME.send_redirects$
        ^net.ipv6.conf.IFNAME.accept_ra$
        ^net.ipv6.conf.IFNAME.accept_redirects$
        ^net.ipv6.conf.IFNAME.accept_source_route$
        ^net.ipv6.conf.IFNAME.arp_accept$
        ^net.ipv6.conf.IFNAME.arp_notify$
        ^net.ipv6.neigh.IFNAME.base_reachable_time_ms$
        ^net.ipv6.neigh.IFNAME.retrans_time_ms$
    kind: ConfigMap
    metadata:
      annotations:
        kubernetes.io/description: |
          Sysctl allowlist for nodes.
        release.openshift.io/version: 4.12.0-0.nightly-2022-11-16-003434
      creationTimestamp: "2022-11-17T14:09:27Z"
      name: cni-sysctl-allowlist
      namespace: openshift-multus
      resourceVersion: "2422"
      uid: 96d138a3-160e-4943-90ff-6108fa7c50c3

  2. 使用以下命令编辑列表:

    $ oc edit cm -n openshift-multus cni-sysctl-allowlist -oyaml

    例如,要允许您实现更严格的反向路径转发,您需要将 ^net.ipv4.conf.IFNAME.rp_filter$^net.ipv6.conf.IFNAME.rp_filter$ 添加到列表中,如下所示:

    # Please edit the object below. Lines beginning with a '#' will be ignored,
    # and an empty file will abort the edit. If an error occurs while saving this file will be
    # reopened with the relevant failures.
    #
    apiVersion: v1
    data:
      allowlist.conf: |-
        ^net.ipv4.conf.IFNAME.accept_redirects$
        ^net.ipv4.conf.IFNAME.accept_source_route$
        ^net.ipv4.conf.IFNAME.arp_accept$
        ^net.ipv4.conf.IFNAME.arp_notify$
        ^net.ipv4.conf.IFNAME.disable_policy$
        ^net.ipv4.conf.IFNAME.secure_redirects$
        ^net.ipv4.conf.IFNAME.send_redirects$
        ^net.ipv4.conf.IFNAME.rp_filter$
        ^net.ipv6.conf.IFNAME.accept_ra$
        ^net.ipv6.conf.IFNAME.accept_redirects$
        ^net.ipv6.conf.IFNAME.accept_source_route$
        ^net.ipv6.conf.IFNAME.arp_accept$
        ^net.ipv6.conf.IFNAME.arp_notify$
        ^net.ipv6.neigh.IFNAME.base_reachable_time_ms$
        ^net.ipv6.neigh.IFNAME.retrans_time_ms$
        ^net.ipv6.conf.IFNAME.rp_filter$
  3. 保存对文件的更改并退出。

    注意

    也支持删除 sysctl。编辑该文件,删除 sysctlsysctl,然后保存更改并退出。

验证

按照以下步骤为 IPv4 强制更严格的反向路径转发。有关反向路径转发的更多信息,请参阅反向路径转发

  1. 使用以下内容创建网络附加定义,如 reverse-path-fwd-example.yaml

    apiVersion: "k8s.cni.cncf.io/v1"
    kind: NetworkAttachmentDefinition
    metadata:
      name: tuningnad
      namespace: default
    spec:
      config: '{
        "cniVersion": "0.4.0",
        "name": "tuningnad",
        "plugins": [{
          "type": "bridge"
          },
          {
          "type": "tuning",
          "sysctl": {
             "net.ipv4.conf.IFNAME.rp_filter": "1"
            }
        }
      ]
    }'
  2. 运行以下命令来应用 yaml:

    $ oc apply -f reverse-path-fwd-example.yaml

    输出示例

    networkattachmentdefinition.k8.cni.cncf.io/tuningnad created

  3. 使用以下 YAML 创建 pod.yaml 等 pod:

    apiVersion: v1
    kind: Pod
    metadata:
      name: example
      labels:
        app: httpd
      namespace: default
      annotations:
        k8s.v1.cni.cncf.io/networks: tuningnad  1
    spec:
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: httpd
          image: 'image-registry.openshift-image-registry.svc:5000/openshift/httpd:latest'
          ports:
            - containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
    1
    指定配置的 NetworkAttachmentDefinition 的名称。
  4. 运行以下命令来应用 yaml:

    $ oc apply -f examplepod.yaml
  5. 运行以下命令验证 pod 是否已创建:

    $ oc get pod

    输出示例

    NAME      READY   STATUS    RESTARTS   AGE
    example   1/1     Running   0          47s

  6. 运行以下命令登录到 pod:

    $ oc rsh example
  7. 验证配置的 sysctl 标记的值。例如,通过运行以下命令查找 net.ipv4.conf.net1.rp_filter 的值:

    sh-4.4# sysctl net.ipv4.conf.net1.rp_filter

    预期输出

    net.ipv4.conf.net1.rp_filter = 1

7.9.5. 使用安全 sysctl 启动 pod

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

默认允许安全 sysctl。

这个示例使用 pod securityContext 来设置以下安全 sysctl:

  • kernel.shm_rmid_forced
  • net.ipv4.ip_local_port_range
  • net.ipv4.tcp_syncookies
  • net.ipv4.ping_group_range
警告

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

使用此流程启动带有配置的 sysctl 设置的 pod。

注意

在大多数情况下,您修改现有的 pod 定义并添加 securityContext 规格。

流程

  1. 创建一个定义示例 pod 的 YAML 文件 sysctl_pod.yaml 并添加 securityContext 规格,如下例所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sysctl-example
      namespace: default
    spec:
      containers:
      - name: podexample
        image: centos
        command: ["bin/bash", "-c", "sleep INF"]
        securityContext:
          runAsUser: 2000 1
          runAsGroup: 3000 2
          allowPrivilegeEscalation: false 3
          capabilities: 4
            drop: ["ALL"]
      securityContext:
        runAsNonRoot: true 5
        seccompProfile: 6
          type: RuntimeDefault
        sysctls:
        - name: kernel.shm_rmid_forced
          value: "1"
        - name: net.ipv4.ip_local_port_range
          value: "32770       60666"
        - name: net.ipv4.tcp_syncookies
          value: "0"
        - name: net.ipv4.ping_group_range
          value: "0           200000000"
    1
    runAsUser 控制使用哪个用户 ID 运行容器。
    2
    runAsGroup 控制容器使用哪个主要组 ID。
    3
    allowPrivilegeEscalation 决定 pod 是否请求允许特权升级。如果未指定,则默认为 true。这个布尔值直接控制在容器进程中是否设置了 no_new_privs 标志。
    4
    capabilities 允许特权操作,而不提供完整的 root 访问权限。此策略可确保从 pod 中丢弃了所有功能。
    5
    runAsNonRoot: true 要求容器使用 0 以外的任何 UID 运行。
    6
    RuntimeDefault 为 pod 或容器工作负载启用默认的 seccomp 配置集。
  2. 运行以下命令来创建 pod:

    $ oc apply -f sysctl_pod.yaml
  3. 运行以下命令验证 pod 是否已创建:

    $ oc get pod

    输出示例

    NAME              READY   STATUS            RESTARTS   AGE
    sysctl-example    1/1     Running           0          14s

  4. 运行以下命令登录到 pod:

    $ oc rsh sysctl-example
  5. 验证配置的 sysctl 标记的值。例如,通过运行以下命令找到值 kernel.shm_rmid_forced

    sh-4.4# sysctl kernel.shm_rmid_forced

    预期输出

    kernel.shm_rmid_forced = 1

7.9.6. 使用不安全 sysctl 启动 pod

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

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

警告

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

以下示例演示了在 pod 规格中添加安全和不安全 sysctl 时会发生什么:

流程

  1. 创建一个 YAML 文件 sysctl-example-unsafe.yaml,用于定义示例 pod 并添加 securityContext 规格,如下例所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sysctl-example-unsafe
    spec:
      containers:
      - name: podexample
        image: centos
        command: ["bin/bash", "-c", "sleep INF"]
        securityContext:
          runAsUser: 2000
          runAsGroup: 3000
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
        sysctls:
        - name: kernel.shm_rmid_forced
          value: "0"
        - name: net.core.somaxconn
          value: "1024"
        - name: kernel.msgmax
          value: "65536"
  2. 使用以下命令创建 pod:

    $ oc apply -f sysctl-example-unsafe.yaml
  3. 使用以下命令验证 pod 是否调度但没有部署,但没有部署不安全 sysctl:

    $ oc get pod

    输出示例

    NAME                       READY             STATUS            RESTARTS   AGE
    sysctl-example-unsafe      0/1               SysctlForbidden   0          14s

7.9.7. 启用不安全 sysctl

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

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

您可以通过在 Security Context Constraints 的 allowedUnsafeSysctls 字段中指定 sysctl 模式列表来进一步控制 pod 中设置哪些 sysctl。

  • allowedUnsafeSysctls 选项用来控制特定的需求,如高性能或实时应用程序调整。
警告

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

流程

  1. 运行以下命令,列出 OpenShift Container Platform 集群的现有 MachineConfig 对象,以确定如何标记您的机器配置:

    $ oc get machineconfigpool

    输出示例

    NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE
    master   rendered-master-bfb92f0cd1684e54d8e234ab7423cc96   True      False      False      3              3                   3                     0                      42m
    worker   rendered-worker-21b6cb9a0f8919c88caf39db80ac1fce   True      False      False      3              3                   3                     0                      42m

  2. 运行以下命令,在带有不安全 sysctl 的容器的机器配置池中添加标签:

    $ oc label machineconfigpool worker custom-kubelet=sysctl
  3. 创建定义 KubeletConfig 自定义资源(CR)的 YAML 文件 set-sysctl-worker.yaml

    apiVersion: machineconfiguration.openshift.io/v1
    kind: KubeletConfig
    metadata:
      name: custom-kubelet
    spec:
      machineConfigPoolSelector:
        matchLabels:
          custom-kubelet: sysctl 1
      kubeletConfig:
        allowedUnsafeSysctls: 2
          - "kernel.msg*"
          - "net.core.somaxconn"
    1
    指定机器配置池中的标签。
    2
    列出您想要允许的不安全 sysctl。
  4. 运行以下命令来创建对象:

    $ oc apply -f set-sysctl-worker.yaml
  5. 运行以下命令,等待 Machine Config Operator 生成新呈现的配置并将其应用到机器:

    $ oc get machineconfigpool worker -w

    几分钟后 UPDATING 状态从 True 变为 False:

    NAME     CONFIG                                             UPDATED   UPDATING   DEGRADED   MACHINECOUNT   READYMACHINECOUNT   UPDATEDMACHINECOUNT   DEGRADEDMACHINECOUNT   AGE
    worker   rendered-worker-f1704a00fc6f30d3a7de9a15fd68a800   False     True       False      3              2                   2                     0                      71m
    worker   rendered-worker-f1704a00fc6f30d3a7de9a15fd68a800   False     True       False      3              2                   3                     0                      72m
    worker   rendered-worker-0188658afe1f3a183ec8c4f14186f4d5   True      False      False      3              3                   3                     0                      72m
  6. 创建一个 YAML 文件 sysctl-example-safe-unsafe.yaml,它定义了一个 pod 示例并添加 securityContext 规格,如下例所示:

    apiVersion: v1
    kind: Pod
    metadata:
      name: sysctl-example-safe-unsafe
    spec:
      containers:
      - name: podexample
        image: centos
        command: ["bin/bash", "-c", "sleep INF"]
        securityContext:
          runAsUser: 2000
          runAsGroup: 3000
          allowPrivilegeEscalation: false
          capabilities:
            drop: ["ALL"]
      securityContext:
        runAsNonRoot: true
        seccompProfile:
          type: RuntimeDefault
        sysctls:
        - name: kernel.shm_rmid_forced
          value: "0"
        - name: net.core.somaxconn
          value: "1024"
        - name: kernel.msgmax
          value: "65536"
  7. 运行以下命令来创建 pod:

    $ oc apply -f sysctl-example-safe-unsafe.yaml

    预期输出

    Warning: would violate PodSecurity "restricted:latest": forbidden sysctls (net.core.somaxconn, kernel.msgmax)
    pod/sysctl-example-safe-unsafe created

  8. 运行以下命令验证 pod 是否已创建:

    $ oc get pod

    输出示例

    NAME                         READY   STATUS    RESTARTS   AGE
    sysctl-example-safe-unsafe   1/1     Running   0          19s

  9. 运行以下命令登录到 pod:

    $ oc rsh sysctl-example-safe-unsafe
  10. 验证配置的 sysctl 标记的值。例如,通过运行以下命令查找 net.core.somaxconn 的值:

    sh-4.4# sysctl net.core.somaxconn

    预期输出

    net.core.somaxconn = 1024

现在,允许不安全的 sysctl,该值在更新的 pod 规格的 securityContext 规格中定义。

7.9.8. 其他资源