什么是cgroup

Cgroup 是一个 Linux 内核特性,对一组进程的资源使用(CPU、内存、磁盘 I/O 和网络等)进行限制、审计和隔离。

cgroups(Control Groups) 是 linux 内核提供的一种机制,这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。简单说,cgroups 可以限制、记录任务组所使用的物理资源。本质上来说,cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。

什么是cgroupfs

docker默认的Cgroup Driver是cgroupfs

[root@VM-16-9-centos ~]# docker info | grep cgroup
 Cgroup Driver: cgroupfs

Cgroup提供了一个原生接口并通过cgroupfs提供(从这句话我们可以知道cgroupfs就是Cgroup的一个接口的封装)。类似于procfs和sysfs,是一种虚拟文件系统。并且cgroupfs是可以挂载的,默认情况下挂载在/sys/fs/cgroup目录。

什么是Systemd?

Systemd也是对于Cgroup接口的一个封装。systemd以PID1的形式在系统启动的时候运行,并提供了一套系统管理守护程序、库和实用程序,用来控制、管理Linux计算机操作系统资源。

为什么使用systemd而不是croupfs

这里引用以下kubernetes官方的原话:

当某个 Linux 系统发行版使用 systemd 作为其初始化系统时,初始化进程会生成并使用一个 root 控制组(cgroup),并充当 cgroup 管理器。 Systemd 与 cgroup 集成紧密,并将为每个 systemd 单元分配一个 cgroup。 你也可以配置容器运行时和 kubelet 使用 cgroupfs。 连同 systemd 一起使用 cgroupfs 意味着将有两个不同的 cgroup 管理器。

单个 cgroup 管理器将简化分配资源的视图,并且默认情况下将对可用资源和使用 中的资源具有更一致的视图。 当有两个管理器共存于一个系统中时,最终将对这些资源产生两种视图。 在此领域人们已经报告过一些案例,某些节点配置让 kubelet 和 docker 使用 cgroupfs,而节点上运行的其余进程则使用 systemd; 这类节点在资源压力下 会变得不稳定。

ubuntu系统,debian系统,centos7系统,都是使用systemd初始化系统的。systemd这边已经有一套cgroup管理器了,如果容器运行时和kubelet使用cgroupfs,此时就会存在cgroups和systemd两种cgroup管理器。也就意味着操作系统里面存在两种资源分配的视图,当操作系统上存在CPU,内存等等资源不足的时候,操作系统上的进程会变得不稳定。

我们可以简单得理解为一山不要容二虎,一个国家只能有一个国王。

注意事项: 不要尝试修改集群里面某个节点的cgroup驱动,如果有需要,最好移除该节点重新加入。

如何修改docker默认的cgroup驱动

增加"exec-opts": ["native.cgroupdriver=systemd"]配置,重启docker即可

root@cfdcub7217s:~# cat /etc/docker/daemon.json 
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "registry-mirrors": [
    "https://docker.mirrors.ustc.edu.cn",
    "http://hub-mirror.c.163.com"
  ],
  "max-concurrent-downloads": 10,
  "log-driver": "json-file",
  "log-level": "warn",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
    },
  "data-root": "/var/lib/docker"
}

kubelet配置cgroup驱动

参考官方

说明: 在版本 1.22 中,如果用户没有在 KubeletConfiguration 中设置 cgroupDriver 字段, kubeadm init 会将它设置为默认值 systemd

# kubeadm-config.yaml
kind: ClusterConfiguration
apiVersion: kubeadm.k8s.io/v1beta3
kubernetesVersion: v1.21.0
---
kind: KubeletConfiguration
apiVersion: kubelet.config.k8s.io/v1beta1
cgroupDriver: systemd

然后使用kubeadm初始化

kubeadm init --config kubeadm-config.yaml