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 添加到允许的安全列表中:
sysctl | 描述 |
---|---|
|
当设置为 |
|
定义 TCP 和 UDP 用于选择本地端口的本地端口范围。第一个数字是第一个端口号,第二个数字是最后一个本地端口号。如果可能,如果这些数字有不同的奇偶校验(甚至一个单数值)。它们必须大于或等于 |
|
当设置了 |
|
这将限制 |
|
这将定义网络命名空间中的第一个无特权端口。要禁用所有特权端口,将其设置为 |
sysctl | 描述 |
---|---|
| 接受 IPv4 ICMP 重定向消息。 |
| 接受带有严格的源路由(SRR)选项的 IPv4 数据包。 |
| 使用没有出现在 ARP 表中的 IPv4 地址定义抓取 ARP 帧的行为:
|
| 定义 IPv4 地址和设备更改通知的模式。 |
| 禁用这个 IPv4 接口的 IPSEC 策略(SPD)。 |
| 接受 ICMP 将消息重定向到接口当前网关列表中列出的网关。 |
| 只有当节点充当路由器时,才会启用发送重定向。也就是说,主机不应发送 ICMP 重定向消息。路由器使用它来通知主机与特定目的地可用的更好路由路径。 |
| 接受 IPv6 路由器公告;使用它们自动配置。它还决定是否传输路由器请求。只有功能设置要接受路由器播发时,才会传输路由器请求。 |
| 接受 IPv6 ICMP 重定向消息。 |
| 接受带有 SRR 选项的 IPv6 数据包。 |
| 使用没有出现在 ARP 表中的 IPv6 地址定义抓取 ARP 帧的行为:
|
| 定义 IPv6 地址和设备更改通知的模式。 |
| 这个参数控制 IPv6 的邻居表中的硬件地址到 IP 映射生命周期。 |
| 为邻居发现消息设置重新传输计时器。 |
当使用 tuning
CNI 插件设置这些值时,请按字面使用值 IFNAME
。接口名称由 IFNAME
令牌表示,并替换为在运行时接口的实际名称。
其他资源
7.9.4. 使用安全 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
规格。
流程
创建一个定义示例 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 配置集。
运行以下命令来创建 pod:
$ oc apply -f sysctl_pod.yaml
运行以下命令验证 pod 是否已创建:
$ oc get pod
输出示例
NAME READY STATUS RESTARTS AGE sysctl-example 1/1 Running 0 14s
运行以下命令登录到 pod:
$ oc rsh sysctl-example
验证配置的 sysctl 标记的值。例如,通过运行以下命令找到值
kernel.shm_rmid_forced
:sh-4.4# sysctl kernel.shm_rmid_forced
预期输出
kernel.shm_rmid_forced = 1
7.9.5. 使用不安全 sysctl 启动 pod
带有不安全 sysctl 的 pod 无法在任何节点上启动,除非集群管理员在某个节点上明确启用了不安全 sysctl。与节点级 sysctl 一样,使用污点和容限功能或节点上的标签将这些 pod 调度到正确的节点。
以下示例使用 pod securityContext
设置安全 sysctl kernel.shm_rmid_forced
,以及两个不安全 sysctl net.core.somaxconn
和 kernel.msgmax
。在规格中,安全和不安全 sysctl 并无区别。
为了避免让操作系统变得不稳定,只有在了解了参数的作用后才修改 sysctl 参数。
以下示例演示了在 pod 规格中添加安全和不安全 sysctl 时会发生什么:
流程
创建一个 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"
使用以下命令创建 pod:
$ oc apply -f sysctl-example-unsafe.yaml
使用以下命令验证 pod 是否调度但没有部署,但没有部署不安全 sysctl:
$ oc get pod
输出示例
NAME READY STATUS RESTARTS AGE sysctl-example-unsafe 0/1 SysctlForbidden 0 14s
7.9.6. 启用不安全 sysctl
集群管理员可在非常特殊的情况下允许某些不安全 sysctl,比如高性能或实时应用程序性能优化。
如果要使用不安全 sysctl,集群管理员必须为特定类型的节点单独启用它们。sysctl 必须拥有命名空间。
您可以通过在 Security Context Constraints 的 allowedUnsafeSysctls
字段中指定 sysctl 模式列表来进一步控制 pod 中设置哪些 sysctl。
-
allowedUnsafeSysctls
选项用来控制特定的需求,如高性能或实时应用程序调整。
由于其不安全特性,使用不安全 sysctl 的风险由您自行承担,而且可能会造成严重问题,例如容器行为不当、资源短缺或节点受损。
流程
运行以下命令,列出 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
运行以下命令,在带有不安全 sysctl 的容器的机器配置池中添加标签:
$ oc label machineconfigpool worker custom-kubelet=sysctl
创建定义
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"
运行以下命令来创建对象:
$ oc apply -f set-sysctl-worker.yaml
运行以下命令,等待 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
创建一个 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"
运行以下命令来创建 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
运行以下命令验证 pod 是否已创建:
$ oc get pod
输出示例
NAME READY STATUS RESTARTS AGE sysctl-example-safe-unsafe 1/1 Running 0 19s
运行以下命令登录到 pod:
$ oc rsh sysctl-example-safe-unsafe
验证配置的 sysctl 标记的值。例如,通过运行以下命令查找
net.core.somaxconn
的值:sh-4.4# sysctl net.core.somaxconn
预期输出
net.core.somaxconn = 1024
现在,允许不安全的 sysctl,该值在更新的 pod 规格的 securityContext
规格中定义。