轉自:Kubernetes 設計分析: 為什么 kubelet 運行時不能打開 swap?
問題背景
在我自己的測試環境里,使用 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在宿主上禁用會比較好。