重学容器31: 容器资源限制之限制容器的内存
2021-07-30
linux memory cgroup子系统 #
限制容器的内存使用需要借助memory cgroup子系统。
在使用cgroups时需要先挂载,例如在centos下memory cgroup子系统被挂载到了/sys/fs/cgroup/memory
下,,在这个目录下是各个memory控制组目录,每个控制组目录下还可以有子目录,各个控制组形成了一个树状的层级关系。
例如在/sys/fs/cgroup/memory
下创建一个名为foo的pids控制组目录,控制组目录中有如下内容:
1cd /sys/fs/cgroup/memory
2
3mkdir foo
4cd foo && ls
5
6cgroup.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
7cgroup.event_control memory.kmem.max_usage_in_bytes memory.kmem.usage_in_bytes memory.memsw.usage_in_bytes memory.stat
8cgroup.procs memory.kmem.slabinfo memory.limit_in_bytes memory.move_charge_at_immigrate memory.swappiness
9memory.failcnt memory.kmem.tcp.failcnt memory.max_usage_in_bytes memory.numa_stat memory.usage_in_bytes
10memory.force_empty memory.kmem.tcp.limit_in_bytes memory.memsw.failcnt memory.oom_control memory.use_hierarchy
11memory.kmem.failcnt memory.kmem.tcp.max_usage_in_bytes memory.memsw.limit_in_bytes memory.pressure_level notify_on_release
task
文件中是控制组中的进程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的。
1cat memory.oom_control
2oom_kill_disable 0
3under_oom 0
下面演示如何删除上面创建的控制组foo目录,可以使用libcgroup-tools
工具:
1yum install libcgroup-tools
2
3cgdelete memory:foo
限制containerd容器内存 #
nerdctl run
启动一个containerd容器时,可以使用-m
选项指定容器的最大内存
1nerdctl help run
2......
3--memory value, -m value Memory limit
4......
下面使用nerdctl启动一个containerd容器,限制其内存使用为100Mb,并在服务器上查找一下它的memory cgroup目录。
1nerdctl run -m 100m -d redis:alpine3.14
298321686255a1a219651ee5c454fc2cb85f2b96aab9bda51c97a1f843c018689
可以在/sys/fs/cgroup/memory/default
目录下下出现了一个与容器ID同名的目录,目录中的memory.limit_in_bytes
文件的值为104857600 bytes
即100Mb:
1cd /sys/fs/cgroup/memory/default/98321686255a1a219651ee5c454fc2cb85f2b96aab9bda51c97a1f843c018689
2cat memory.limit_in_bytes
3104857600
注意/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容器的资源限制情况如下:
1resources:
2 limits:
3 cpu: '2'
4 memory: 200Mi
5 requests:
6 cpu: 100m
7 memory: 100Mi
即limits.memory为200Mi,requests.memory为200Mi。memory控制组目录的具体位置可以参考前面第29节中查找cpu控制组目录的方法,这里略过:
1cd /sys/fs/cgroup/memory/kubepods.slice/kubepods-burstable.slice/kubepods-burstable-podaaf5f103_b1ee_43b7_a59e_7ff9bf9e377c.slice/cri-containerd-9788e7eefd4a3857e594680987cefc31f82915f2f8edce0ac1bad1bf7b4427cf.scope
2
3cat memory.limit_in_bytes
4209715200
可以看到k8s里pod容器的requests.memory
不会修改memory cgroup里的memory.limit_in_bytes
,只是在k8s调度时用来计算使用的,看某个k8s节点上是否有可用内存分配给这个pod的容器。而k8s里pod容器的limits.memory
被设置到memory cgroup里的memory.limit_in_bytes
。