问题一:报错 cannot allocate memory 或者 no space left on device,修复 Kubernetes 内存泄露问题
问题描述
一、当 Kubernetes 集群运行日久以后,有的 Node 无法再新建 Pod,并且出现如下错误,当重启服务器之后,才可以恢复正常使用。查看 Pod 状态的时候会出现以下报错。
applying cgroup … caused: mkdir …no space left on device
或者在 describe pod 的时候出现 cannot allocate memory
二、具体查看是否存在内存泄露
cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo
当出现 cat: /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo: Input/output error 则说明不存在内存泄露的情况
如果存在内存泄露会出现
slabinfo - version: 2.1# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
二、kmem 导致内存泄露的原因:
内核对于每个 cgroup 子系统的的条目数是有限制的,限制的大小定义在 kernel/cgroup.c #L139
,当正常在 cgroup 创建一个 group 的目录时,条目数就加1。我们遇到的情况就是因为开启了 kmem accounting 功能,虽然 cgroup 的目录删除了,但是条目没有回收。这样后面就无法创建 65535 个 cgroup 了。也就是说,在当前内核版本下,开启了 kmem accounting 功能,会导致 memory cgroup 的条目泄漏无法回收。
wget https://dl.google.com/go/go1.12.9.linux-amd64.tar.gz
tar xf go1.12.9.linux-amd64.tar.gz -C /usr/local/
写入bashrc
vim ~/.bashrc
export GOPATH="/data/Documents"export GOROOT="/usr/local/go"export PATH="$GOROOT/bin:$GOPATH/bin:$PATH"export GO111MODULE=off
验证source ~/.bashrc
go env
2、下载runc源码
mkdir -p /data/Documents/src/github.com/opencontainers/cd /data/Documents/src/github.com/opencontainers/
git clone https://github.com/opencontainers/runccd runc/
git checkout v1.0.0-rc9 # 切到v1.0.0-rc9 tag
3、编译
安装编译组件sudo yum install libseccomp-devel
make BUILDTAGS='seccomp nokmem'编译完成之后会在当前目录下看到一个runc的可执行文件,等kubelet编译完成之后会将其替换
二、编译 kubelet
1、下载 Kubernetes 源码
mkdir -p /root/k8s/cd /root/k8s/
git clone https://github.com/kubernetes/kubernetescd kubernetes/
git checkout v1.15.3
2、制作编译环境的镜像(Dockerfile如下)
FROM centos:centos7.3.1611ENV GOROOT /usr/local/go
ENV GOPATH /usr/local/gopath
ENV PATH /usr/local/go/bin:$PATHRUN yum install rpm-build which where rsync gcc gcc-c++ automake autoconf libtool make -y \
&& curl -L https://studygolang.com/dl/golang/go1.12.9.linux-amd64.tar.gz | tar zxvf - -C /usr/local
3、在制作好的go环境镜像中来进行编译 kubelet
docker run -it --rm -v /root/k8s/kubernetes:/usr/local/gopath/src/k8s.io/kubernetes build-k8s:centos-7.3-go-1.12.9-k8s-1.15.3 bash
cd /usr/local/gopath/src/k8s.io/kubernetes
#编译
GO111MODULE=off KUBE_GIT_TREE_STATE=clean KUBE_GIT_VERSION=v1.15.3 make kubelet GOFLAGS="-tags=nokmem"
三、替换原有的 runc 和 kubelet
1、将原有 runc 和 kubelet 备份
mv /usr/bin/kubelet /home/kubelet
mv /usr/bin/docker-runc /home/docker-runc
2、停止 Docker 和 kubelet
systemctl stop docker
systemctl stop kubelet
3、将编译好的 runc 和 kubelet 进行替换
cp kubelet /usr/bin/kubelet
cp kubelet /usr/local/bin/kubelet
cp runc /usr/bin/docker-runc
4、检查 kmem 是否关闭前需要将此节点的 Pod 杀掉重启或者重启服务器,当结果为0时成功
cat /sys/fs/cgroup/memory/kubepods/burstable/memory.kmem.usage_in_bytes
5、是否还存在内存泄露的情况
cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo
问题二:Kubernetes 证书过期问题的两种处理方法
Unable to connect to the server: x509: certificate has expired or is not yet valid
经网上搜索之后发现。应该是 Kubernetes 集群的证书过期了,使用命令排查证书的过期时间
kubeadm alpha certs check-expiration
发现确实是证书过期了。
kubeadm alpha certs renew all --config=kubeadm.yaml
systemctl restart kubelet
kubeadm init phase kubeconfig all --config kubeadm.yaml
然后将生成的配置文件替换,重启kube-apiserver、kube-controller、kube-scheduler、etcd这4个容器即可
首先在/etc/kubernetes/manifests/kube-controller-manager.yaml文件加入配置
spec:
containers:
- command:
- kube-controller-manager
# 设置证书有效期为10年
- --experimental-cluster-signing-duration=87600h
- --client-ca-file=/etc/kubernetes/pki/ca.crt
kubeadm alpha certs renew all --use-api --config kubeadm.yaml &
# 先拷贝静态Pod资源清单
cp -r /etc/kubernetes/manifests/ /etc/kubernetes/manifests.bak
vi /etc/kubernetes/manifests/etcd.yaml
......
spec:
containers:
- command:
- etcd
# 修改为CA文件
- --peer-trusted-ca-file=/etc/kubernetes/pki/ca.crt
- --trusted-ca-file=/etc/kubernetes/pki/ca.crt
......
volumeMounts:
- mountPath: /var/lib/etcd
name: etcd-data
- mountPath: /etc/kubernetes/pki # 更改证书目录
name: etcd-certs
volumes:
- hostPath:
path: /etc/kubernetes/pki # 将 pki 目录挂载到etcd中去
type: DirectoryOrCreate
name: etcd-certs
- hostPath:
path: /var/lib/etcd
type: DirectoryOrCreate
name: etcd-data
......
vi /etc/kubernetes/manifests/kube-apiserver.yaml
......
spec:
containers:
- command:
- kube-apiserver
# 将etcd ca文件修改为默认的ca.crt文件
- --etcd-cafile=/etc/kubernetes/pki/ca.crt
......
除此之外还需要替换 requestheader-client-ca-file 文件,默认是 /etc/kubernetes/pki/front-proxy-ca.crt 文件,现在也需要替换成默认的 CA 文件,否则使用聚合 API,比如安装了 metrics-server 后执行 kubectl top 命令就会报错:
cp /etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/front-proxy-ca.crt
cp /etc/kubernetes/pki/ca.key /etc/kubernetes/pki/front-proxy-ca.key
原文链接:https://zhuanlan.zhihu.com/p/343031257
侵权请私聊公众号删文
热文推荐
欢迎关注LemonSec
觉得不错点个“赞”、“在看”