• 修复k8s内存泄露问题


     

    问题描述

    1. 当 k8s 集群运行日久以后,有的 node 无法再新建 pod,并且出现如下错误,当重启服务器之后,才可以恢复正常使用。查看 pod 状态的时候会出现以下报错。
      applying cgroup … caused: mkdir …no space left on device

    或者在 describe pod 的时候出现 cannot allocate memory。

    这时候你的 k8s 集群可能就存在内存泄露的问题了,当创建的 pod 越多的时候内存会泄露的越多,越快。

    1. 具体查看是否存在内存泄露
      $ 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>

    解决方案

    1. 解决方法思路:关闭 runc 和 kubelet 的 kmem,因为升级内核的方案改动较大,此处不采用。

    2. kmem 导致内存泄露的原因:

    内核对于每个 cgroup 子系统的的条目数是有限制的,限制的大小定义在 kernel/cgroup.c #L139,当正常在 cgroup 创建一个 group 的目录时,条目数就加 1。我们遇到的情况就是因为开启了 kmem accounting 功能,虽然 cgroup 的目录删除了,但是条目没有回收。这样后面就无法创建 65535 个 cgroup 了。也就是说,在当前内核版本下,开启了 kmem accounting 功能,会导致 memory cgroup 的条目泄漏无法回收。

    2.1 编译 runc

    • 配置 go 语言环境
      $ 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
    • 下载 runc 源码
      $ mkdir -p /data/Documents/src/github.com/opencontainers/
      $ cd /data/Documents/src/github.com/opencontainers/
      $ git clone https://github.com/opencontainers/runc
      $ cd runc/
      $ git checkout v1.0.0-rc9  # 切到v1.0.0-rc9 tag
    • 编译
      # 安装编译组件
      $ sudo yum install libseccomp-devel
      $ make BUILDTAGS='seccomp nokmem'
      # 编译完成之后会在当前目录下看到一个runc的可执行文件,等kubelet编译完成之后会将其替换

    2.2 编译 kubelet

    • 下载 kubernetes 源码
      $ mkdir -p /root/k8s/
      $ cd /root/k8s/
      $ git clone https://github.com/kubernetes/kubernetes
      $ cd kubernetes/
      $ git checkout v1.15.3
    • 制作编译环境的镜像(Dockerfile 如下)
      FROM centos:centos7.3.1611
      
      ENV GOROOT /usr/local/go
      ENV GOPATH /usr/local/gopath
      ENV PATH /usr/local/go/bin:$PATH
      
      RUN 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
    • 在制作好的 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"
    1. 替换原有的 runc 和 kubelet
    • 将原有 runc 和 kubelet 备份
      $ mv /usr/bin/kubelet /home/kubelet
      $ mv /usr/bin/docker-runc /home/docker-runc
    • 停止 docker 和 kubelet
      $ systemctl stop docker
      $ systemctl stop kubelet
    • 将编译好的 runc 和 kubelet 进行替换
      $ cp kubelet /usr/bin/kubelet
      $ cp kubelet /usr/local/bin/kubelet
      $ cp runc /usr/bin/docker-runc
    • 检查 kmem 是否关闭前需要将此节点的 pod 杀掉重启或者重启服务器,当结果为 0 时成功
      $ cat /sys/fs/cgroup/memory/kubepods/burstable/memory.kmem.usage_in_bytes
    • 检查是否还存在内存泄露的情况
      $ cat /sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo
  • 相关阅读:
    初学node.js-nodejs中实现用户登录路由
    初学node.js-nodejs中实现用户注册路由
    初学node.js-nodejs连接MongoDB(5)
    初学node.js-MongoDB安装和环境服务配置(4)
    初学node.js-nodejs中实现HTTP服务(3)
    初学node.js-npm使用(2)
    初学node.js-nodejs安装运行(1)
    python-两个图片相似度算法
    python-两个筛子数据可视化(直方图)
    从头学习网络编程——网络编程学习笔记 :什么是HTTP与CGI?
  • 原文地址:https://www.cnblogs.com/xiaoyuxixi/p/15458878.html
Copyright © 2020-2023  润新知