创建pod

resources:
  limits:
    cpu: "4"
    memory: 4Gi
    nvidia.com/gpu: "1"
  requests:
    cpu: "4"
    memory: 4Gi
    nvidia.com/gpu: "1"
# cat /sys/fs/cgroup/memory/memory.limit_in_bytes
4294967296    / 4G
1
2
3
4
5
6
7
8
9
10

>>> import sys
>>> print(sys.getsizeof(my_list))
64
>>> my_list = [0]*2
>>> print(sys.getsizeof(my_list))
72
>>> my_list = [0]*3
>>> print(sys.getsizeof(my_list))
80

可见变量占用字节数: 64 + 8*(n-1)

# cat /sys/fs/cgroup/memory/memory.limit_in_bytes
4294967296

# cat /sys/fs/cgroup/memory/memory.usage_in_bytes
78319616

理论上可以申请的数组长度
n =((4294967296 - 78319616) - 64)/8 + 1 = 527080953

用这个值指导数组长度的创建

>>> my_list = [0]*526000000
>>> import sys
>>> print(sys.getsizeof(my_list))
4208000056
# cat /sys/fs/cgroup/memory/memory.usage_in_bytes
4294369280

容器剩余的内存字节byte

4294967296 - 4294369280 = 598016 字节

理论上可再创建的数组长度是(598016 - 64 )/8 + 1 = 74745

创建长度为10w的数组,进程因为oom而被杀死。

>>> my_list5 = [0]*100000
Killed

在容器中查看memory控制组管理的进程, 均为容器中启动的进程。从而可以控制整个容器所使用的系统资源

# cat /sys/fs/cgroup/memory/tasks
1
11
12
15
26
64
75
157
212
root@ruike-gpu-instance-1698738579-jqri0boj-557db69f4c-z95w2:/sys/fs/cgroup/memory# ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 07:49 ?        00:00:00 /bin/bash /start.sh
root          11       1  0 07:49 ?        00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 s
root          12       1  0 07:49 ?        00:00:01 /usr/bin/python3 /usr/local/bin/jupyter-lab --Se
root          15      11  0 07:50 ?        00:00:00 sshd: root@pts/0
root          26      15  0 07:50 pts/0    00:00:00 -bash
root          64      11  0 07:56 ?        00:00:00 sshd: root@pts/1
root          75      64  0 07:56 pts/1    00:00:00 -bash
root         157       0  0 12:31 pts/2    00:00:00 bash
root         216     157  0 13:05 pts/2    00:00:00 ps -ef

当在容器中执行top/free等命令时,容器侧和host侧看到的信息事一致的,这是因为

在调用libcontaienr库时将/proc/dev/dev/shm/sys目录以只读方式挂载(bind mount)到容器中,同时还会建立以下几个链接:

/proc/self/fd->/dev/fd
/proc/self/fd/0->/dev/stdin
/proc/self/fd/1->/dev/stdout
/proc/self/fd/2->/dev/stder

这样做的道理事保证系统 IO 不会出现问题,容器运行的进程和系统运行的进程查看操作系统事等价的。

而像free,top等命令会调用该挂在的目录, 所以呈现事一致的。

# strace free
execve("/usr/bin/free", ["free"], [/* 66 vars */]) = 0
...
statfs("/sys/fs/selinux", 0x7ffec90733a0) = -1 ENOENT (No such file or directory)
statfs("/selinux", 0x7ffec90733a0) = -1 ENOENT (No such file or directory)
open("/proc/filesystems", O_RDONLY) = 3
...
open("/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 3
...
open("/proc/meminfo", O_RDONLY) = 3

总结

1、Docker 是利用 CGroups 实现资源限制的,只能限制资源消耗的最大值,而不能隔绝其他程序占用自己的资源;

2、Namespace 的6项隔离看似完整,实际上依旧没有完全隔离 Linux 资源,比如/proc 、/sys 、/dev/sd*等目录未完全隔离,SELinux、time、syslog 等所有现有 Namespace 之外的信息都未隔离。
3. 内存是不可压缩资源,超过会出发oom将进程killed。其他进程还活着,而cpu是可压缩资源,超过不会被killed.

note

k8s docker 作用
requests.cpu –cpu-shares 当一个宿主机上有多个容器发生 CPU资源竞争时这个参数就会生效,参数值越大,越容易被分配到 CPU
requests.memory 没有使用 在 Kubernetes 的资源 QoS 管理时使用
limits.cpu –cpu-quota 另外一个参数–cpu-period 默认设置为100000,通过这两个参数限制容器最多能够使用的CPU核数
limits.memory –memory 限制容器内存

查看容器真实使用的资源

1、读取容器 CPU 核数

# 这个值除以100000得到的就是容器核数
~# cat  /sys/fs/cgroup/cpu/cpu.cfs_quota_us
400000

2、获取容器内存使用情况(USAGE / LIMIT)

~ # cat /sys/fs/cgroup/memory/memory.usage_in_bytes
4289953792
~ # cat /sys/fs/cgroup/memory/memory.limit_in_bytes
4294967296

3、获取容器是否被设置了 OOM,是否发生过 OOM

~ # cat /sys/fs/cgroup/memory/memory.oom_control

4、获取容器磁盘I/O

~ # cat /sys/fs/cgroup/blkio/blkio.throttle.io_service_bytes

5、获取容器虚拟网卡入/出流量
~ # cat /sys/class/net/eth0/statistics/rx_bytes
10167967741
~ # cat /sys/class/net/eth0/statistics/tx_bytes
15139291335