記錄一次kubernetes集群cgroup泄露問題


服務器環境

  系統版本:CentOS Linux release 7.4.1708 (Core)

  系統內核:3.10.0-1127.el7.x86_64

  kubernetes版本:v1.10.7

  docker版本: 17.09.1-ce

問題記錄

  k8s創建pod在某台節點上無法創建並報錯:

  

unable to ensure pod container exists: faild to create container for /kubepods/burstable/podf1242523-2135abf-200cfcce08 : mkdir /sys/fs/cgroup/memory/kubepods/burstable/podf1242523-2135abf-200cfcce08: no space left on device

  在節點上創建容器失敗

docker: Error response from daemon: OCI runtime create failed: container_linux.go:348: starting container process caused "process_linux.go:279: applying cgroup configuration for process caused \"mkdir /sys/fs/cgroup/memory/docker/f88b5f802a5ddb0fc0b072f01e481911c3fd736092565f6b9047d3c1d0d08e26: cannot allocate memory\"": unknown.

在網上查詢發現是cgroup泄露導致cagroup memory在容器被刪除后沒有釋放,導致memory被占滿

 

騰訊容器雲解決方案地址:https://tencentcloudcontainerteam.github.io/2018/12/29/cgroup-leaking/

網上復現文章地址:http://www.linuxfly.org/kubernetes-19-conflict-with-centos7/?from=groupmessage

docker社區:https://github.com/moby/moby/issues/29638

kubernetes社區:https://github.com/kubernetes/kubernetes/issues/70324

解決方案

因為這個K8S集群本身是作為PASS平台的底層集群,如果升級集群可能會導致和PASS平台兼容出現問題,所以采取清理出現問題的節點把pod飄移出去盡量小的影響業務,然后重啟服務器來釋放。

規避方案

如果你用的低版本內核(比如 CentOS 7 v3.10 的內核)並且不方便升級內核,可以通過不開啟 kmem accounting 來實現規避,但會比較麻煩。

kubelet 和 runc 都會給 memory cgroup 開啟 kmem accounting,所以要規避這個問題,就要保證kubelet 和 runc 都別開啟 kmem accounting,下面分別進行說明:

runc

runc 在合並 這個PR  之后創建的容器都默認開啟了 kmem accounting,后來社區也注意到這個問題,並做了比較靈活的修復, PR 1921 給 runc 增加了 “nokmem” 編譯選項,缺省的 release 版本沒有使用這個選項, 自己使用 nokmem 選項編譯 runc 的方法:

1 cd $GO_PATH/src/github.com/opencontainers/runc/
2 make BUILDTAGS="seccomp nokmem"

docker-ce v18.09.1 之后的 runc 默認關閉了 kmem accounting,所以也可以直接升級 docker 到這個版本之后。

kubelet

如果是 1.14 版本及其以上,可以在編譯的時候通過 build tag 來關閉 kmem accounting:

    KUBE_GIT_VERSION=v1.14.1 ./build/run.sh make kubelet GOFLAGS="-tags=nokmem"

 

如果是低版本需要修改代碼重新編譯。kubelet 在創建 pod 對應的 cgroup 目錄時,也會調用 libcontianer 中的代碼對 cgroup 做設置,在 pkg/kubelet/cm/cgroup_manager_linux.goCreate 方法中,會調用 Manager.Apply 方法,最終調用 vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go 中的 MemoryGroup.Apply 方法,開啟 kmem accounting。這里也需要進行處理,可以將這部分代碼注釋掉然后重新編譯 kubelet。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM