一直以来,自己物理机装的k8s经常会卡死,摸索了很久也不知道什么原因,之前把内核给升级了好像卡的频率会相对低点,但还是会卡,今天无意中查看一下dmesge发现有这样的提示:
Unable to allocate memory on node -1
网上一通搜索,得到如下结论:
在某些内核版本上,cgroup 的 kmem account 特性有内存泄露问题,很不幸我就是那个某些,解决方法有如下几种:
一、升级内核
二、重新编译runc
三、重新编译kubelet
四、修改虚机启动的引导项 grub 中的cgroup.memory=nokmem,让机器启动时直接禁用 cgroup的 kmem 属性
我内核已经是4.4+了,所以第一种排除,第二种我也试过了,没有效果,第4种要重新电脑,麻烦就不试了,今天就做第3种的实验
1、因为kubelet是golang写的,所以编译需要安装golang
curl -s https://mirror.go-repo.io/centos/go-repo.repo | tee /etc/yum.repos.d/go-repo.repo
yum install golang
2、下载kubelrnetes完整包
git clone https://github.com.cnpmjs.org/kubernetes/kubernetes.git cd kubernetes git checkout v1.16.15
3、查看 cross 镜像的版本号
[root@node02 kubernetes]# cat build/build-image/cross/VERSION v1.13.15-1
4、拉国内的镜像,然后改名
docker pull registry.aliyuncs.com/k8sxio/kube-cross:v1.13.15-1 docker tag registry.aliyuncs.com/k8sxio/kube-cross:v1.13.15-1 us.gcr.io/k8s-artifacts-prod/build-image/kube-cross:v1.13.15-1
5、用下面的命令进行编译,
./build/run.sh make kubelet GOFLAGS="-v -tags=nokmem" KUBE_BUILD_PLATFORMS=linux/amd64
网上的这个命令编译完kubectl get node会得到notready的状态
make BUILDTAGS="nokmem" WHAT=cmd/kubelet GOFLAGS=-v GOGCFLAGS="-N -l"
查看编译完成的
ls -l _output/dockerized/bin/linux/amd64/
6、备份旧Kubelet,将编译好的kubelet进行替换,然后重启
验证方法
kubectl run nginx-1 --image=hub.baidubce.com/cce/nginx-alpine-go:latest --port=80 --restart=Never --requests='cpu=100m,memory=100Mi' --limits="cpu=200m,memory=200Mi" docker ps |grep nginx-1
将得到的容器id进行过滤
find /sys/fs/cgroup/memory -name "memory.kmem.slabinfo"|grep ab876d139c1b /sys/fs/cgroup/memory/kubepods/burstable/pod4f6a6db3-b18c-4094-86b2-e9cd7abce849/ab876d139c1b3609e6b347274dc2bbfdb021a6e008457b2c7fc69f158320689a/memory.kmem.slabinfo
直接查看这一串信息
cat /sys/fs/cgroup/memory/kubepods/burstable/pod4f6a6db3-b18c-4094-86b2-e9cd7abce849/ab876d139c1b3609e6b347274dc2bbfdb021a6e008457b2c7fc69f158320689a/memory.kmem.slabinfo
如果出现报错,提示没有信息则表示关闭成功,如果出现一堆详细信息说明不成功,我这边出现一堆信息,说明关闭kubelet的kmen accout还没有效果,我决定再做关闭runc的实验
关闭runc的kmem account
1、查看commit
[root@node01 kubepods]# runc --version runc version 1.0.0-rc93 commit: 12644e614e25b05da6fd08a38ffa0cfe1903fdec spec: 1.0.2-dev go: go1.15.11 libseccomp: 2.3.3
根据commit跳转链接
https://github.com/opencontainers/runc/commit/12644e614e25b05da6fd08a38ffa0cfe1903fde
根据链接找到了是这个tag
https://github.com/opencontainers/runc/tree/v1.0.0-rc93
2、下载源码
git clone https://github.com/opencontainers/runc.git
cd runc
git checkout v1.0.0-rc93
3、构建镜像,直接make shell会报错,因为我这边的git一次不稳定,我试了好几次才成功
由先前make shell得到的镜像名是
runc_dev:HEAD
构建一下
docker build -t runc_dev:HEAD .
4、运行容器进行编译
docker run -ti --privileged --rm -v $PWD:/go/src/github.com/opencontainers/runc runc_dev:HEAD bash
make BUILDTAGS="seccomp selinux apparmor nokmem" static
5、编译完后退出容器,在当前目录生成runc文件,添加可执行权限后拷贝到/usr/bin/runc
chmod +x runc
6、验证是否重新编译成功,运行以下命令
docker run --rm --name test --kernel-memory 100M nginx:1.14.2 docker: Error response from daemon: OCI runtime create failed: container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: process_linux.go:458: setting cgroup config for procHooks process caused: kernel memory accounting disabled in this runc build: unknown. 提示disable说明重新编译成功
参考文章:https://zhangguanzhang.github.io/2021/04/08/kubelet-runc-disable-kmem/
参考文章:https://cloud.tencent.com/developer/article/1739289