linux memory cgroup子系统
限制容器的内存使用需要借助memory cgroup子系统。
在使用cgroups时需要先挂载,例如在centos下memory cgroup子系统被挂载到了/sys/fs/cgroup/memory下,,在这个目录下是各个memory控制组目录,每个控制组目录下还可以有子目录,各个控制组形成了一个树状的层级关系。
例如在/sys/fs/cgroup/memory下创建一个名为foo的pids控制组目录,控制组目录中有如下内容:
cd /sys/fs/cgroup/memory
mkdir foo
cd foo && ls
cgroup.clone_children memory.kmem.limit_in_bytes memory.kmem.tcp.usage_in_bytes memory.memsw.max_usage_in_bytes memory.soft_limit_in_bytes tasks
cgroup.event_control memory.kmem.max_usage_in_bytes memory.kmem.usage_in_bytes memory.memsw.usage_in_bytes memory.stat
cgroup.procs memory.kmem.slabinfo memory.limit_in_bytes memory.move_charge_at_immigrate memory.swappiness
memory.failcnt memory.kmem.tcp.failcnt memory.max_usage_in_bytes memory.numa_stat memory.usage_in_bytes
memory.force_empty memory.kmem.tcp.limit_in_bytes memory.memsw.failcnt memory.oom_control memory.use_hierarchy
memory.kmem.failcnt memory.kmem.tcp.max_usage_in_bytes memory.memsw.limit_in_bytes memory.pressure_level notify_on_releasetask文件中是控制组中的进程id,可以把某个进程添加到这个控制组中,另外memory.usage_in_bytes是只读的,它的值是当前控制组中所有进程使用的内存总和。
重点关注memory.limit_in_bytes, memory.oom_control文件的值:
memory.limit_in_bytes: 用来设置控制组中所有进程可以使用内存的最大值
memory.oom_control用来设置当控制组中所有进程达到可以使用内存的最大值时,也就是发生OOM(Out of Memory)时是否触发linux的OOM killer杀死控制组内的进程。默认的配置是开启OOM killer的。
cat memory.oom_control
oom_kill_disable 0
under_oom 0下面演示如何删除上面创建的控制组foo目录,可以使用libcgroup-tools工具:
yum install libcgroup-tools
cgdelete memory:foo限制containerd容器内存
nerdctl run启动一个containerd容器时,可以使用-m选项指定容器的最大内存
nerdctl help run
......
--memory value, -m value Memory limit
......下面使用nerdctl启动一个containerd容器,限制其内存使用为100Mb,并在服务器上查找一下它的memory cgroup目录。
nerdctl run -m 100m -d redis:alpine3.14
98321686255a1a219651ee5c454fc2cb85f2b96aab9bda51c97a1f843c018689可以在/sys/fs/cgroup/memory/default目录下下出现了一个与容器ID同名的目录,目录中的memory.limit_in_bytes文件的值为104857600 bytes即100Mb:
cd /sys/fs/cgroup/memory/default/98321686255a1a219651ee5c454fc2cb85f2b96aab9bda51c97a1f843c018689
cat memory.limit_in_bytes
104857600注意/sys/fs/cgroup/memory中default目录是containerd中的namespace概念,默认是default,如果启动容器时指定了namespace,则就是对应的namespace目录。如nerdctl -n mynamespace run -m 100m -d redis:alpine3.14,则控制组就在/sys/fs/cgroup/memory/mynamespace目录的以容器id为名称的子目录里。
k8s如何使用memory cgroup限制容器cpu
最后根据结合Kubernetes中对容器的资源限制requests.memory和limits.memory,到k8s容器的memory控制组目录中看一下是如何设置的。
这个k8s集群的版本是1.21,容器运行时使用的是containerd。
在这个集群中部署了Kubernetes的Dashboard,设置了dashboard容器的资源限制情况如下:
resources:
limits:
cpu: '2'
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi即limits.memory为200Mi,requests.memory为200Mi。memory控制组目录的具体位置可以参考前面第29节中查找cpu控制组目录的方法,这里略过:
cd /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podaaf5f103_b1ee_43b7_a59e_7ff9bf9e377c.slice/cri-containerd-9788e7eefd4a3857e594680987cefc31f82915f2f8edce0ac1bad1bf7b4427cf.scope
cat memory.limit_in_bytes
209715200可以看到k8s里pod容器的requests.memory不会修改memory cgroup里的memory.limit_in_bytes,只是在k8s调度时用来计算使用的,看某个k8s节点上是否有可用内存分配给这个pod的容器。而k8s里pod容器的limits.memory被设置到memory cgroup里的memory.limit_in_bytes。