最近在部署Kubernetes集群时遇到了一个典型问题:当节点服务器重启后,kubelet服务无法正常启动,日志中反复出现"Failed to start kubelet: failed to run Kubelet: misconfiguration: kubelet cgroup driver: "systemd" is different from docker cgroup driver: "cgroupfs""的错误提示。经过排查发现,根本原因是服务器重启后swap分区被自动挂载,而Kubernetes从1.8版本开始就明确要求禁用swap。
这个问题看似简单,但涉及Linux系统初始化、Kubernetes调度原理和容器运行时配置等多个技术层面的交互。我在三个不同环境的集群中都遇到了相同情况,说明这绝非个案。下面就把完整的排查思路和解决方案分享给大家。
Kubernetes设计之初就将swap禁用作为硬性要求,主要基于三个核心考量:
性能可预测性:swap会导致内存页频繁换入换出,使得容器应用的性能表现变得不可预测。对于需要稳定延迟的微服务架构,这种不确定性是不可接受的。
调度准确性:kube-scheduler依赖节点的内存统计信息做调度决策。如果存在swap,实际内存使用量会被低估,可能导致调度到资源不足的节点。
OOM处理机制:Linux OOM Killer在内存不足时会根据复杂算法选择进程终止。启用swap会延迟OOM事件触发,可能导致Kubernetes的优先级机制失效。
这个问题通常出现在以下环境配置中:
关键症状表现为:
code复制systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
Active: activating (auto-restart) (Result: exit-code) since Tue 2023-05-16 09:23:18 CST; 5s ago
Process: 10234 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS (code=exited, status=1/FAILURE)
Main PID: 10234 (code=exited, status=1/FAILURE)
查看详细日志会发现:
code复制journalctl -xeu kubelet
...
error: failed to run Kubelet: running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false
...
对于已经出现问题的节点,立即执行:
bash复制swapoff -a
这个命令会立即卸载所有swap分区,但只是临时生效,重启后问题会再次出现。
修改/etc/fstab文件:
bash复制sudo sed -i '/swap/s/^/#/' /etc/fstab
对于使用cloud-init的云服务器,还需要检查/etc/cloud/cloud.cfg.d/目录下是否有相关配置:
bash复制grep -r "swap" /etc/cloud/cloud.cfg.d/
虽然可以通过修改kubelet配置绕过检查:
bash复制sudo sed -i 's/^KUBELET_EXTRA_ARGS=.*/KUBELET_EXTRA_ARGS="--fail-swap-on=false"/' /etc/default/kubelet
但这种方法存在严重隐患:
执行以下命令确认swap已完全禁用:
bash复制free -h
total used free shared buff/cache available
Mem: 15Gi 4.2Gi 8.4Gi 456Mi 2.4Gi 10Gi
Swap: 0B 0B 0B
在新服务器部署时就应该:
bash复制sudo dd if=/dev/zero of=/swapfile bs=1M count=1024
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapoff /swapfile
sudo rm -f /swapfile
在kubeadm init时显式指定配置:
yaml复制apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
nodeRegistration:
kubeletExtraArgs:
fail-swap-on: "false" # 仅用于测试环境
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
controllerManager:
extraArgs:
node-monitor-grace-period: "10s"
创建override配置文件:
bash复制sudo mkdir -p /etc/systemd/system/kubelet.service.d
cat <<EOF | sudo tee /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
[Service]
Environment="KUBELET_EXTRA_ARGS=--node-ip=<实际IP> --fail-swap-on=false"
EOF
sudo systemctl daemon-reload
sudo systemctl restart kubelet
经过多次实践验证,推荐采用以下方案:
物理机环境:
云环境:
hcl复制provisioner "remote-exec" {
inline = [
"sudo swapoff -a",
"sudo sed -i '/swap/d' /etc/fstab",
"sudo systemctl restart kubelet"
]
}
关键配置检查清单:
/proc/swaps内容为空vm.swappiness = 0已设置当问题仍然出现时,按以下步骤排查:
检查所有可能的内存交换源:
bash复制grep -i swap /proc/meminfo
grep -r swap /etc/*
验证内核参数:
bash复制sysctl -a | grep swap
分析系统启动过程:
bash复制journalctl -b | grep swap
检查是否有残留的swap文件:
bash复制sudo find / -type f -name "*.swp"
最终确认命令:
bash复制sudo kubelet --fail-swap-on=false --v=4 2>&1 | grep -i swap
对于确实需要内存缓冲的场景,可以考虑:
使用临时文件系统:
bash复制mount -t tmpfs -o size=1G tmpfs /mnt/tmpfs
配置内存cgroup限制:
yaml复制apiVersion: v1
kind: Pod
metadata:
name: memory-demo
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
调整内核内存参数:
bash复制echo 1 > /proc/sys/vm/overcommit_memory
echo 80 > /proc/sys/vm/overcommit_ratio
经过以上系统化的处理和优化,Kubernetes集群的swap问题可以得到彻底解决。在实际生产环境中,我建议将swap检查纳入部署检查清单,避免因系统重启导致的服务中断。