问题
在 Kubernetes 集群下运行的容器的内核参数是默认的, 但是对于某型类型的应用如 Nginx Ingress controller 而言, 默认的内核参数配置是不够的, 需要做出调整, 例如 somaxconn 是限制了接收新 TCP 连接侦听队列的大小, 它的默认值是 128, 但是对于反向代理的服务器而言, 这个配置实在是太小了. 那么我们自然想到需要去调整这个应用的容器的内核配置参数.
解决之道
Docker Daemon 的处理方式
对于 Docker 引擎而言, 可是使用 --sysctl 运行参数来设定需要更改的内核参数, 例如:
- docker run -it --sysctl net.core.somaxconn=65535 busybox
- # 在容器看看是否配置成功:
- cat /proc/sys/net/core/somaxconn
然后我们可以看看容器的详情:
可以看到, Docker 引擎对容器进行了相关的配置, 而无需使用特权模式来设置内核参数
Kubernetes 的处理之道
在 Kubernetes 里, Kubernetes 可以利用 Docker 引擎的这个 --sysctl 的能力, 也可以利用 privilege init container 的方式. 目前 sysctls 的能力还依然在 alpha 阶段, 选择时需要注意.
Kubernetes Sysctls
具体可以参考: Using Sysctls in a Kubernetes Cluster
实践过程如下:
需要在 kubelet 启动参数上配置对应的开关 --experimental-allowed-unsafe-sysctls. 例如在阿里云的 kubernetes 服务, 可以在 node 节点, 修改 / etc/systemd/system/kubelet.service.d/10-kubeadm.conf, 增加对应的配置并重新加载 systemctl daemon-reload, 然后重启 kubelet. 如下是允许配置和 net 相关的内核参数:
Kubernetes 允许配置的内核参数如下:
- kernel.shm*,
- kernel.msg*,
- kernel.sem,
- fs.mqueue.*,
- net.*.
启动 Pod 的时候设置对应的 annotation, 申明需要修改的内核参数, 以启动一个 nginx 为测试例子:
- apiVersion: v1
- kind: Pod
- metadata:
- name: test-sysctl
- annotations:
- security.alpha.kubernetes.io/unsafe-sysctls: net.core.somaxconn=65535
- spec:
- containers:
- - image: nginx
- name: nginx
- ports:
- - containerPort: 80
- protocol: TCP
- nodeSelector:
- kubernetes.io/hostname: cn-shenzhen.i-xxxxx
注意: 对于需要变更内核参数的应用, 建议部署到特定的机器上. 为了方便, 我是使用了 node selector.
如果对应的机器的 kubelet 没有打开这个对应的开关, 那么 pod 是部署不成功的. 我们可以通过 kubectl get event 来看看对应的日志:
那么这个方式背后的原理是什么呢? 其实就是 docker 的 --sysctl, 我们可以 pod 到对应的 node 接点去 docker inspect 看看. 但是奇怪的是, docker inspect 看不到任何 sysctl 的迹象, 是不是那里有误?
其实不是的, 因为真正执行 sysctl 是 kubernetes 的 pause container 也叫做 infra container, 我们找到对应的这个容器, 再 docker inspect 看看:
这个时候, 我们发现, 这个 pause 容器配置了 sysctls.
Kubernetes Init Container
Init container 的用法可以参考: Init Containers
使用 init container 的好处是, 无需去改变 kubelet 的配置, 但是需要给这个 init container 配置成 privilege 的权限.
以下是一个启动 Pod 的例子:
- apiVersion: v1
- kind: Pod
- metadata:
- name: test-sysctl-init
- namespace: default
- spec:
- containers:
- - image: nginx
- imagePullPolicy: Always
- name: nginx
- ports:
- - containerPort: 80
- protocol: TCP
- initContainers:
- - image: busybox
- command:
- - sh
- - -c
- - echo 10000 > /proc/sys/net/core/somaxconn
- imagePullPolicy: Always
- name: setsysctl
- securityContext:
- privileged: true
至于使用那种方式, 可以自行选择. 后续也要留意 kubernetes 对于 sysctls 的演进.
来源: http://zhuanlan.51cto.com/art/201809/582956.htm