问题背景
在我自己的测试环境里,使用 kubeadm 来创建 k8s 集群,而我们知道 kubeadm 运行机制首先要求控制节点(简称 kmaster)上的 kubelet 需要先启动。
测试环境使用 systemd 对进程进行管理。
测试环境重启后,发现 kubelet 无法正常启动,表现如下:
root@kmaster135:~# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: activating (auto-restart) (Result: exit-code) since Sun 2019-04-07 22:06:29 PDT; 295ms ago
Docs: https://kubernetes.io/docs/home/
Process: 19593 ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_
Main PID: 19593 (code=exited, status=255)
Apr 07 22:06:29 kmaster135 systemd[1]: kubelet.service: Main process exited, code=exited, status=255/n/a
Apr 07 22:06:29 kmaster135 systemd[1]: kubelet.service: Unit entered failed state.
Apr 07 22:06:29 kmaster135 systemd[1]: kubelet.service: Failed with result 'exit-code'.
过程记录
kubelet 拉起实验
可以看到启动命令失败,而失败的具体原因,我们需要查看对应的进程日志,参考: 如何使用Journalctl查看并操作Systemd日志
,学习到可以使用journalctl _PID=<PID>
来查看对应进程的日志,在上面可以看到 kubelet 在最近一次重启失败的主进程 PID 是 19593。
root@kmaster135:~# journalctl _PID=19593 | vim -
-- Logs begin at Sun 2019-04-07 20:03:02 PDT, end at Sun 2019-04-07 22:08:53 PDT. --
Apr 07 22:06:29 kmaster135 kubelet[19593]: Flag --cgroup-driver has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.
Apr 07 22:06:29 kmaster135 kubelet[19593]: Flag --cgroup-driver has been deprecated, This parameter should be set via the config file specified by the Kubelet's --config flag. See https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/ for more information.
Apr 07 22:06:29 kmaster135 kubelet[19593]: I0407 22:06:29.445241 19593 server.go:408] Version: v1.12.3
Apr 07 22:06:29 kmaster135 kubelet[19593]: I0407 22:06:29.445739 19593 plugins.go:99] No cloud provider specified.
Apr 07 22:06:29 kmaster135 kubelet[19593]: I0407 22:06:29.449904 19593 certificate_store.go:131] Loading cert/key pair from "/var/lib/kubelet/pki/kubelet-client-current.pem".
Apr 07 22:06:29 kmaster135 kubelet[19593]: I0407 22:06:29.502617 19593 server.go:667] --cgroups-per-qos enabled, but --cgroup-root was not specified. defaulting to /
Apr 07 22:06:29 kmaster135 kubelet[19593]: F0407 22:06:29.503369 19593 server.go:262] failed to run Kubelet: Running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false. /proc/swaps contained: [Filename Type Size Used Priority /dev/sda5 partition 998396 0 -1]
重定向标准输出到 vim 是为了避免屏幕显示时被截断,没有自动换行,不是关键点。
根据 Fatal 级别的日志
Apr 07 22:06:29 kmaster135 kubelet[19593]: F0407 22:06:29.503369 19593 server.go:262] failed to run Kubelet: Running with swap on is not supported, please disable swap! or set --fail-swap-on flag to false.
可以看出来是因为开启了 swap,而 kubelet 在 1.8 版本以后强制要求 swap 必须关闭。
我之前是通过 swapoff -a
命令来关闭 swap 的,看来没有被固化。
root@kmaster135:~# free
total used free shared buff/cache available
Mem: 997616 97500 519460 10784 380656 713456
Swap: 998396 0 998396
先来测试一下,关闭 swap 后能否正常,再来考虑固化的问题。
root@kmaster135:~# swapoff -a
root@kmaster135:~# free
total used free shared buff/cache available
Mem: 997616 97180 519904 10784 380532 713992
Swap: 0 0 0
看起来没有直接退出了:
root@kmaster135:~# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
Loaded: loaded (/lib/systemd/system/kubelet.service; enabled; vendor preset: enabled)
Drop-In: /etc/systemd/system/kubelet.service.d
└─10-kubeadm.conf
Active: active (running) since Sun 2019-04-07 22:14:10 PDT; 46s ago
Docs: https://kubernetes.io/docs/home/
Main PID: 20719 (kubelet)
Tasks: 16
Memory: 50.6M
CPU: 3.764s
CGroup: /system.slice/kubelet.service
└─20719 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubecon
Apr 07 22:14:43 kmaster135 kubelet[20719]: W0407 22:14:43.334707 20719 cni.go:293] CNI failed to retrieve
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.695545 20719 cni.go:310] Error adding network:
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.696050 20719 cni.go:278] Error while adding to
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.827405 20719 remote_runtime.go:96] RunPodSandbo
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.827475 20719 kuberuntime_sandbox.go:65] CreateP
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.827498 20719 kuberuntime_manager.go:657] create
Apr 07 22:14:43 kmaster135 kubelet[20719]: E0407 22:14:43.827576 20719 pod_workers.go:186] Error syncing
Apr 07 22:14:44 kmaster135 kubelet[20719]: W0407 22:14:44.342386 20719 docker_sandbox.go:375] failed to r
Apr 07 22:14:44 kmaster135 kubelet[20719]: W0407 22:14:44.351209 20719 pod_container_deletor.go:75] Conta
Apr 07 22:14:44 kmaster135 kubelet[20719]: W0407 22:14:44.354070 20719 cni.go:293] CNI failed to retrieve
虽然还是有一些报错,按照上面的逻辑进一步排查可以发现是初始化阶段的报错,集群很快恢复了正常。
root@kmaster135:~# kubectl get cs
NAME STATUS MESSAGE ERROR
scheduler Healthy ok
controller-manager Healthy ok
etcd-0 Healthy {"health": "true"}
root@kmaster135:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
dnode136 Ready <none> 12d v1.12.3
dnode137 Ready <none> 12d v1.12.3
kmaster135 Ready master 12d v1.12.3
root@kmaster135:~# kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-world-6897d55fb-2crbf 1/1 Running 1 12d
hello-world-6897d55fb-ssc28 1/1 Running 1 12d
hello-world-6897d55fb-txg5j 1/1 Running 1 12d
swapoff 固化
kubelet 问题看起来解决了,接下来要解决 swap 设置如何固化的问题,参考 How do I disable swap?, 配置 /etc/fstab
root@kmaster135:~# cat /etc/fstab
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=aac6ee1b-f945-473b-8222-4be8c11e4822 / ext4 errors=remount-ro 0 1
# swap was on /dev/sda5 during installation
UUID=d36ffe9b-676a-419a-b6fb-b95dc12d93ac none swap sw 0 0
...
注释掉最下面的UUID=d36ffe9b-676a-419a-b6fb-b95dc12d93ac
这一行就可以了。
swap & kubelet
进一步了解一下,为什么 swap 打开对 kubelet 来说会是一个需要直接退出进程的错误呢??
参考 Why disable swap on kubernetes 和 Kubelet needs to allow configuration of container memory-swap #7294, 得出基本的知识总结:
- 一开始大家在讨论的是,如果容许 Pod 使用 Swap,应该怎么去衡量默认的 Swap 设置,以及调度器应该如何根据 Swap 来进行调度?
- 讨论了一段时间后,发现支持 Swap 很复杂。。。总之就是很复杂。一位大佬站出来说,真的有需要用到 Swap 的场景么?
- 然后大家就开始批判起 Swap 来了,Swap 带来各种性能上的不确定性啦,而且也找不到哪些场景一定要用 Swap 啦,经过大家高兴地一致决定,Swap 这个东西真的是有害而无利,而且要用起来还复杂,就是不用它好了(K8S 1.5版本)。
- 然后如果有人想用?一开始还是支持通过参数配置使用的,后来发现一个不推荐的用法,有人非得用,代码上各种坑,还不如大家一起坚决不用好了。
- 然后到了1.8后就是默认不用了,除非你强制打开,官方强烈不推荐,踩坑自己负责。
看 Issue 主要是觉得这个过程实在是一个很典型的,功能要不要的讨论,说来说去,没有明确的用户场景,就不要把一个事情搞复杂的哲学很重要。
更新--fail-swap-on flag含义
这个flag表示为:Makes the Kubelet fail to start if swap is enabled on the node.
也就是说如果为true(默认值)就要求必须要关闭swap,false是表示即使宿主开启了swap,kubelet也是可以成功启动,但是pod是允许使用swap
了,这部分代码因为经常出问题,所以直接swap在宿主上禁用会比较好。
总结
- 学习到了使用
journalctl _PID=<PID>
来输出 systemd 管理下的进程日志; - 对 kubelet 的启动限制有了进一步的了解;