一、背景

当生产环境中因为内存分配不合理、或者使用不合理,导致容器OOM后需要提升内存限制

但是提升内存限制需要重启pod才能生效,对于多数生产环境中是不可接受的,需要考虑运行中动态修改的方案。

二、思路

k8s是通过cgroup设置pod资源限制的,cgroup是linux中一个独立组件,早于k8s就已经存在。

也就是说k8s和cgroup之间只是调用的关系,观察发现k8s只有在pod创建时才会设置cgroup,之后就不管了,所以可以通过后期手动设置cgroup来达到目的。

cgroup有v1和v2两个版本,我们目前用的是v1,接下来会基于v1版本展开。

cgroup比较友好的接口就是procfs,通过cat读取配置,通过io重定向写入配置,所以完全可以通过命令行来解决。

三、实现

1、在docker中找到容器的id:

sql
1
2
3
[root@master10 ~]# docker ps|grep redis
99bf05e5697d 53aa81e8adfa "redis-server --maxm…" 8 hours ago Up 8 hours k8s_redis_redis-8668c46ff7-2tp7t_redis_03381db2-cfcb-43ca-b5d5-a49b6f4a33f2_4
5c1e4e64e197 google_containers/pause:3.2 "/pause" 3 months ago Up 3 months k8s_POD_redis-8668c46ff7-2tp7t_redis_03381db2-cfcb-43ca-b5d5-a49b6f4a33f2_3

2、根据容器id找到cgroup路径信息

plaintext
1
2
3
[root@master10 ~]# docker inspect 99bf05e5697d |grep -E 'CgroupParent|Id'
"Id": "99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202",
"CgroupParent": "/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2",

这里解释一下:

k8s的Pod在docker中是由pause容器和工作容器组成的,所以为了管理这些容器,会有一个cgroup组的概念,即CgroupParent,所有容器会在在这个目录下创建以自身Id为名的子目录

sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[root@master10 pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2]# cd /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2/
[root@master10 pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2]# ls -la
总用量 0
drwxr-xr-x 4 root root 0 1231 19:18 .
drwxr-xr-x 55 root root 0 1231 19:18 ..
drwxr-xr-x 2 root root 0 1231 19:19 5c1e4e64e1972b049e11d20b831e27cdfb6409586e7459781ac279f56d0bf328
drwxr-xr-x 2 root root 0 424 08:02 99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202
-rw-r--r-- 1 root root 0 4月 24 15:08 cgroup.clone_children
-rw-r--r-- 1 root root 0 4月 24 15:08 cgroup.procs
-r--r--r-- 1 root root 0 4月 24 15:08 cpuacct.stat
-rw-r--r-- 1 root root 0 4月 24 15:08 cpuacct.usage
-r--r--r-- 1 root root 0 4月 24 15:08 cpuacct.usage_all
-r--r--r-- 1 root root 0 4月 24 15:08 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 4月 24 16:53 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 4月 24 16:53 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 4月 24 16:53 cpuacct.usage_sys
-r--r--r-- 1 root root 0 4月 24 16:53 cpuacct.usage_user
-rw-r--r-- 1 root root 0 12月 31 19:18 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 12月 31 19:18 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 4月 24 16:53 cpu.rt_period_us
-rw-r--r-- 1 root root 0 4月 24 16:53 cpu.rt_runtime_us
-rw-r--r-- 1 root root 0 12月 31 19:18 cpu.shares
-r--r--r-- 1 root root 0 4月 24 15:08 cpu.stat
-rw-r--r-- 1 root root 0 4月 24 16:53 notify_on_release
-rw-r--r-- 1 root root 0 4月 24 16:53 tasks

3、拼凑cgroup路径

plaintext
1
2
3
4
5
6
7
8
9
cpu限制的路径:
/sys/fs/cgroup/ + cpu,cpuacct/ + CgroupParent/ + Id

即:/sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2/99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202

内存限制的路径:
/sys/fs/cgroup/ + memory/ + CgroupParent/ + Id

即:/sys/fs/cgroup/memory/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2/99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202

4、设置cpu限制

cpu限制的相关配置项为cpu.cfs_quota_us, 单位us,100Mi对应数值为100*1000

这里需要对cgroup组和自身容器同时进行设置,组=各容器之和,我们通常是单容器的,所以设置成一样值就行了,内存限制同理。

plaintext
1
2
3
4
cpu=$((100*1000))
cd /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2/99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202
echo $((cpu+1)) > ../cpu.cfs_quota_us
echo $cpu > cpu.cfs_quota_us

注:这里group的要求大于container,不然会提示无效参数

5、设置内存限制

内存限制的相关配置项为:

  • memory.soft_limit_in_bytes

      内存软上限,一般设置成-1,即不限制

  • memory.limit_in_bytes

内存硬上限,一般是k8s limits中的值

  • memory.memsw.limit_in_bytes

内存+sw之和的上限,一般跟limit_in_bytes一样,不过k8s会把group的设置为-1

plaintext
1
2
3
4
5
6
7
8
9
10
11
12
size=$((12*1024*1024*1024))

cd /sys/fs/cgroup/memory/kubepods/burstable/pod03381db2-cfcb-43ca-b5d5-a49b6f4a33f2/99bf05e5697d52cf8755136e826b9a2087b3d5a971f40169b699a1f69d809202

echo -1 > ../memory.memsw.limit_in_bytes
echo $size > ../memory.limit_in_bytes
echo -1 > ../memory.soft_limit_in_bytes


echo $size > memory.memsw.limit_in_bytes
echo $size > memory.limit_in_bytes
echo -1 > memory.soft_limit_in_bytes

注:这里需要注意顺序,不然可能会提示无效参数,具体顺序:

  • group > container

  • memory.memsw. > memory.

  • limit_in_bytes > soft_limit_in_bytes

参考
https://www.cnblogs.com/sctb/p/17576082.html