容器内运行的命令是:
echo never | tee /sys/kernel/mm/transparent_hugepage/enabled
两个容器都以特权运行。但在 kubernetes docker 容器中,命令失败并显示错误:
tee: /sys/kernel/mm/transparent_hugepage/enabled: Read-only file system
并且只需简单的docker run -it --privileged alpine /bin/sh
命令就可以正常工作。
我已docker inspect
在 k8s 和非 k8s 容器上使用它来验证特权状态,但没有看到任何其他可能导致此问题的内容 - 我diff
在两个输出之间运行,然后使用docker run
修改来尝试在普通 docker 中重现该问题,但失败了(它仍然有效)。知道为什么 kubernetes docker 容器失败而普通 docker 容器成功吗?
这可以通过此处的 pod 定义重现:
apiVersion: v1
kind: Pod
metadata:
name: sys-fs-edit
spec:
containers:
- image: alpine
command:
- /bin/sh
args:
- -c
- echo never | tee /sys/kernel/mm/transparent_hugepage/enabled && sysctl -w net.core.somaxconn=8192 vm.overcommit_memory=1 && sleep 9999999d
imagePullPolicy: Always
name: sysctl-buddy
securityContext:
privileged: true
解决方法
虽然我仍然不知道造成差异的原因,但可以通过将 /sys 重新挂载为读写来缓解该问题。
apiVersion: v1
kind: Pod
metadata:
name: sys-fs-edit
spec:
containers:
- image: alpine
command:
- /bin/sh
args:
- -c
- echo never | tee /sys/kernel/mm/transparent_hugepage/enabled && sysctl -w net.core.somaxconn=8192 vm.overcommit_memory=1 && sleep 9999999d
imagePullPolicy: Always
name: sysctl-buddy
securityContext:
privileged: true
volumeMounts:
- mountPath: /sys
name: sys
readOnly: false
volumes:
- hostPath:
path: /sys
name: sys
答案1
在Kubernetes它的工作原理略有不同。privileged: true
在securityContext
a中设置 acontainer
不足以修改任何sysctl
此类容器。
看一眼这官方 kubernetes 文档中有这样一段描述在 Kubernetes 集群中使用 sysctls.正如你所读到的这里:
Sysctl 分为 安全的 和 不安全 sysctls。除了正确的命名空间之外, 安全的 sysctl 必须正确 孤立 同一节点上的 Pod 之间。这意味着设置 安全的 一个 pod 的 sysctl
- 不得对节点上的任何其他 pod 产生任何影响
- 绝不能损害节点的健康
- 不得允许获取超出 pod 资源限制的 CPU 或内存资源。
到目前为止,大多数 命名空间 不一定会考虑 sysctl 安全的. 支持以下 sysctl 安全的 放:
kernel.shm_rmid_forced
,net.ipv4.ip_local_port_range
,net.ipv4.tcp_syncookies
,net.ipv4.ping_group_range
(自 Kubernetes 1.18 起)。
简而言之,有安全和不安全的 sysctl。其中大多数被认为是不安全的,甚至许多命名空间的 sysctl 也是如此。集群管理员需要逐个节点地启用不安全的 sysctl:
全部 安全的 默认情况下,sysctls 是启用的。
全部 不安全 默认情况下,sysctl 处于禁用状态,必须由集群管理员根据每个节点手动允许。禁用了不安全 sysctl 的 Pod 将被调度,但无法启动。
考虑到上述警告,集群管理员可以允许某些 不安全 sysctls 用于非常特殊的情况,例如高性能或实时应用程序调整。 不安全 sysctls 是使用 kubelet 的标志在每个节点上启用的;例如:
kubelet --allowed-unsafe-sysctls \ 'kernel.msg*,net.core.somaxconn' ...
因此,你不能随意设置任何 sysctl,即使是privileged
在你的服务器上运行的容器中Kubernetes簇。
答案2
您尝试设置的 sysctl 适用于整个主机,而不是单个容器。无法在非特权容器内设置它,这就是为什么您无法在 Kubernetes 中执行此操作,但可以在特权 Docker 容器中执行此操作。
如果您需要此设置来运行特定容器,则应在集群中所有节点的主机上设置它,而不是在容器或 pod 定义中设置它。