容器技术回顾 - 如何修改容器的内核参数



背景
在某些场景中,我们需要调整内核参数,来调整操作系统行为。那在容器化场景中,我们是否可以调整?哪些可以调整?如何调整?
简要说明
系统参数分为全局参数和Namespaced参数
全局参数可在主机修改,对所有容器生效
全局参数,主机与容器内修改互相影响
全局参数无论是否可见,不可通过 SecurityContext 进行修改
全局参数可分为容器内可见(visiable)和容器内不可见参数,可通过主机修改影响全部容器
可见参数可以通过特权容器,在容器内执行命令进行修改,对主机和所有容器生效
不可见参数只能通过主机修改
Namespaced 系统参数
namespaced 参数为多个容器和主机可以各自独立设置的内核参数,目前仅有以下几类,其他均为全局参数
以下参数中依然存在特例的全局参数,如 net.netfilter.nf_conntrack_max(kernel 3.10)

系统参数

功能

kernel.shm*

共享内存相关参数
kernel.msg* 内核消息队列/IPC相关参数
kernel.sem 信号量相关参数
fs.mqueue.* posix消息队列相关参数
net.* 网络子系统相关参数

安全系统参数
kubernetes 将 namespaced 系统参数划分为 安全参数和非安全参数,安全系统参数要求:
必须不能影响到节点上的其他 Pod
必须不能损害节点的健康
必须不允许使用超出 Pod 的资源限制的 CPU 或内存资源。
最新 kubernetes 代码中默认允许修改的安全系统参数仅为表格中所列:

系统参数名称

功能

备注

kernel.shm_rmid_forced 强制执行共享内存段的资源限制。通过销毁不再使用的共享内存段,它可以防止内存泄漏,并有效地管理系统资源
net.ipv4.ip_local_port_range 参数定义了TCP和UDP流量选择本地端口时使用的本地端口范围
net.ipv4.tcp_syncookies 用于启用或禁用 TCP SYN cookies 机制,以防范 SYN 攻击
net.ipv4.ping_group_range 用于定义允许打开 ICMP echo sockets(也称为 ping sockets)的组 ID 范围,只有在这个范围内的组 ID 的用户才能创建 ICMP Echo sockets
net.ipv4.ip_unprivileged_port_start 用于指定网络命名空间中非特权端口的起始端口号
net.ipv4.ip_local_reserved_ports 用于保留特定的端口范围给特定的应用程序或服务使用,保留的端口不会被其他应用程序或服务使用 要求 kernel 3.16+

以上参数为kubelet默认允许配置的参数,对于非安全的系统参数,需要增加 kubelet 的启动参数允许配置:
kubelet --allowed-unsafe-sysctls 'kernel.msg*,net.core.somaxconn' ...Dockerfile
Dockerfile 不能直接修改内核参数,但是可以通过启动容器时传入参数来实现,例如:
# docker run -it --sysctl 'net.ipv4.ip_default_ttl=63' ubuntu sysctl net.ipv4.ip_default_ttlnet.ipv4.ip_default_ttl = 63
注意
只有 namespaced 参数才可以。否则会报错 ”invalid argument…”
这种方式只是在容器初始化过程中完成内核参数的修改,容器运行起来以后,/proc/sys 仍然是以只读方式挂载的,在容器中不能再次修改 sysctl 内核参数。
通过设置 /etc/sysfs.conf 也是不成功的,此外要在容器内通过命令行修改,必须使用 --privileged 模式:
FROM ubuntu:latest # 安装所需的工具和软件包RUN apt-get update && apt-get install -y \ sysfsutils # 修改内核参数RUN echo "net.ipv4.ip_default_ttl = 63" >> /etc/sysfs.conf # 设置容器启动命令CMD ["bash"]
结果:
#docker run -it --rm ubuntu:kernal /bin/bashroot@45c2e6c156d9:/# sysctl net.ipv4.ip_default_ttlnet.ipv4.ip_default_ttl = 64 root@45c2e6c156d9:/#cat /etc/sysfs.conf## /etc/sysfs.conf - Configuration file for setting sysfs attributes.## The sysfs mount directory is automatically prepended to the attribute paths.# The attribute paths support glob(7) wildcard patterns.## Syntax:# attribute = value# mode attribute = 0600 # (any valid argument for chmod)# owner attribute = root:wheel # (any valid argument for chown)## Examples:## Always use the powersave CPU frequency governor# devices/system/cpu/cpu0/cpufreq/scaling_governor = powersave## Use userspace CPU frequency governor and set initial speed# devices/system/cpu/cpu0/cpufreq/scaling_governor = userspace# devices/system/cpu/cpu0/cpufreq/scaling_setspeed = 600000## Set permissions of suspend control file# mode power/state = 0660# owner power/state = root:powernet.ipv4.ip_default_ttl = 63 root@45c2e6c156d9:/# sysctl net.ipv4.ip_default_ttl=63sysctl: setting key "net.ipv4.ip_default_ttl", ignoring: Read-only file system设置 Pod 的 Sysctl 参数
目前,在 Linux 内核中,有许多的 sysctl 参数都是 有命名空间的。这就意味着可以为节点上的每个 Pod 分别去设置它们的 sysctl 参数。在 Kubernetes 中,只有那些有命名空间的 sysctl 参数可以通过 Pod 的 securityContext 对其进行配置。
kernel.shm*,
kernel.msg*,
kernel.sem,
fs.mqueue.*,
那些可以在容器网络命名空间中设置的 net.*。但是,也有例外(例如 net.netfilter.nf_conntrack_max 和 net.netfilter.nf_conntrack_expect_max 可以在容器网络命名空间中设置,但在 Linux 5.12.2 之前它们是无命名空间的)。
没有命名空间的 sysctl 参数称为 节点级别的 sysctl 参数。如果需要对其进行设置,则必须在每个节点的操作系统上手动地去配置它们, 或者通过在 DaemonSet 中运行特权模式容器来配置。可使用 Pod 的 securityContext 来配置有命名空间的 sysctl 参数, securityContext 应用于同一个 Pod 中的所有容器。此示例中,使用 Pod SecurityContext 来对一个安全的 sysctl 参数 kernel.shm_rmid_forced 以及两个非安全的 sysctl 参数 net.core.somaxconn 和 kernel.msgmax 进行设置。在 Pod 规约中对 安全的 和 非安全的 sysctl 参数不做区分:
apiVersion: v1kind: Podmetadata: name: sysctl-examplespec: securityContext: sysctls: - name: kernel.shm_rmid_forced value: "0" - name: net.core.somaxconn value: "1024" - name: kernel.msgmax value: "65536"
由于 非安全的 sysctl 参数其本身具有不稳定性,在使用 非安全的 sysctl 参数时可能会导致一些严重问题, 如容器的错误行为、机器资源不足或节点被完全破坏。
总结
容器内 sysctl -a 能看到的参数,仅namepsaced参数可通过增加kubelet的系统参数白名单,通过 securityContext 修改
容器内 sysctl -a 看不到的参数,通过修改宿主机内核参数修改
容器内 sysctl -a 能看到的参数,根据内核版本有变更
参考
https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/sysctl-cluster/
https://tencentcloudcontainerteam.github.io/2018/11/19/kernel-parameters-and-container/
https://arthurchiao.art/blog/the-mysterious-container-somaxconn/
https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/sysctl/safe_sysctls.go
https://github.com/kubernetes/kubernetes/blob/v1.26.13/pkg/kubelet/sysctl/namespace.go
https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/component-helpers/node/util/sysctl/namespace.go
到顶部