容器实现原理

Linux 内核的 NamespaceCgroups 可以让程序在一个资源可控的独立(隔离)环境中运行,这就是容器运行运用到的核心技术。

通过 CRI 启动一个容器的时候,可以在宿主机上通过 ls -l /proc/<pid/ns/ 查看该容器的 Namespace 信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@docker-rancher:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fb59b89245b8 harbor.warnerchen.com/rancher/rancher:v2.11.1 "entrypoint.sh" 12 days ago Up 7 days 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp rancher

root@docker-rancher:~# docker inspect fb59b89245b8 | grep Pid
"Pid": 1322,
"PidMode": "",
"PidsLimit": null,

root@docker-rancher:~# ls -l /proc/1322/ns/
total 0
lrwxrwxrwx 1 root root 0 Jun 4 22:21 cgroup -> 'cgroup:[4026532399]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 ipc -> 'ipc:[4026532342]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 mnt -> 'mnt:[4026532340]'
lrwxrwxrwx 1 root root 0 May 28 14:43 net -> 'net:[4026532344]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 pid -> 'pid:[4026532343]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 pid_for_children -> 'pid:[4026532343]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 time -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 user -> 'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Jun 4 22:21 uts -> 'uts:[4026532341]'

可以发现 pid、user 等都指向了独立的 Namespace。

Namespace

Linux 内核的 Namespace 类型有很多种,如 cgroup、ipc、network、mount、pid、time、user、uts。

PID Namespace

在容器内查看所有进程,可以看到只运行了一个进程:

1
2
3
4
root@docker-rancher:~# docker exec -it clash-paofucloud ps -ef
PID USER TIME COMMAND
1 root 1:40 /clash
28 root 0:00 ps -ef

然后在宿主机上查看容器对应的进程,也是只有一个进程:

1
2
3
root@docker-rancher:~# ps -ef | grep clash
root 1316 1278 0 May28 ? 00:01:40 /clash
root 370255 369468 0 22:30 pts/0 00:00:00 grep --color=auto clash

这两个其实是同一个进程,但从容器和宿主机上看,PID 却不相同,这是因为创建容器的时候会创建出一个 PID Namespace,在 PID Namespace 下的进程编号从 1 开始。这其实和 Linux 一样,Linux 开机时就会启动一个 1 号进程,该进程是所有进程的父进程。

而在 PID Namesapce 中只能看到该 PID Namesapce 下的进程,看不到其他 PID Namesapce 下的进程,也就是为什么在容器中执行 ps -ef 的时候只会显示容器内本身的进程。

前面通过 docker inspect 获取到的 PID 就是容器内所有进程的父进程。

Network Namespace

具体实现可以参考:容器网络实现

Mount Namespace

具体实现可以参考:容器文件系统实现

IPC Namespace

IPC Namespace 用于隔离不同进程间的进程间通信(IPC)资源,在同一个 IPC Namespace 内的进程,可以共享 IPC 资源;不同 IPC Namespace 的进程之间,互不可见、无法通信。

User Namespace

User Namespace 主要是用来隔离用户和用户组的。

UTS Namespace

UTS Namespace 用于隔离容器的主机名和域名,意思是每个容器内的主机名都可以独立。

Time Namespace

Time Namespace 用于隔离容器的时间,但是容器并没有隔离时间,也就是说所有容器的时间是和宿主机一致的。

Cgroups

Cgroups(Control Groups) 是 Linux 内核提供的一种资源管理机制,用于限制、记录和隔离进程组使用的资源(如 CPU、内存、磁盘、网络等)。

Cgroups(Control Groups) 分为 cgroup v1 和 v2,是因为 cgroup v1 在设计和实际使用过程中暴露了不少架构和易用性问题,社区和内核开发者为了解决这些问题,引入了更统一、简洁、可扩展的 cgroup v2。

通过下面的命令可以确认目前使用的是 v1 还是 v2:

1
2
3
# tmpfs 代表 v1
# cgroup2fs 代表 v2
stat -fc %T /sys/fs/cgroup/

Cgroup V1

v1 目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@docker-test-0:~# ls -l /sys/fs/cgroup/
total 0
dr-xr-xr-x 11 root root 0 Jun 5 2025 blkio
lrwxrwxrwx 1 root root 11 Jun 5 2025 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Jun 5 2025 cpuacct -> cpu,cpuacct
dr-xr-xr-x 11 root root 0 Jun 5 2025 cpu,cpuacct
dr-xr-xr-x 2 root root 0 Jun 5 2025 cpuset
dr-xr-xr-x 11 root root 0 Jun 5 2025 devices
dr-xr-xr-x 3 root root 0 Jun 5 2025 freezer
dr-xr-xr-x 2 root root 0 Jun 5 2025 hugetlb
dr-xr-xr-x 11 root root 0 Jun 5 2025 memory
dr-xr-xr-x 2 root root 0 Jun 5 2025 misc
lrwxrwxrwx 1 root root 16 Jun 5 2025 net_cls -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jun 5 2025 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Jun 5 2025 net_prio -> net_cls,net_prio
dr-xr-xr-x 2 root root 0 Jun 5 2025 perf_event
dr-xr-xr-x 11 root root 0 Jun 5 2025 pids
dr-xr-xr-x 2 root root 0 Jun 5 2025 rdma
dr-xr-xr-x 12 root root 0 Jun 5 2025 systemd
dr-xr-xr-x 12 root root 0 Jun 5 2025 unified

其实这些就是 Cgroup 支持的子系统,其中就包含最常见的 CPU、内存子系统。

创建一个容器,并为其设置资源限制:

1
docker run -d --name nginx --memory=256m --cpus="1.5" harbor.warnerchen.com/library/nginx:mainline

此时在 /sys/fs/cgroup/<cpu/memory>/docker/<container_id>/ 下就可以看到相关的配置信息:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
root@docker-test-0:~# ls -l /sys/fs/cgroup/cpu/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23/
total 0
-rw-r--r-- 1 root root 0 Jun 5 10:27 cgroup.clone_children
-rw-r--r-- 1 root root 0 Jun 5 10:24 cgroup.procs
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.stat
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_all
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_percpu
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_percpu_sys
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_percpu_user
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_sys
-r--r--r-- 1 root root 0 Jun 5 10:27 cpuacct.usage_user
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpu.cfs_burst_us
-rw-r--r-- 1 root root 0 Jun 5 10:24 cpu.cfs_period_us
-rw-r--r-- 1 root root 0 Jun 5 10:24 cpu.cfs_quota_us
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpu.idle
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpu.shares
-r--r--r-- 1 root root 0 Jun 5 10:27 cpu.stat
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpu.uclamp.max
-rw-r--r-- 1 root root 0 Jun 5 10:27 cpu.uclamp.min
-rw-r--r-- 1 root root 0 Jun 5 10:27 notify_on_release
-rw-r--r-- 1 root root 0 Jun 5 10:27 tasks

root@docker-test-0:~# ls -l /sys/fs/cgroup/memory/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23/
total 0
-rw-r--r-- 1 root root 0 Jun 5 10:25 cgroup.clone_children
--w--w--w- 1 root root 0 Jun 5 10:24 cgroup.event_control
-rw-r--r-- 1 root root 0 Jun 5 10:24 cgroup.procs
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.failcnt
--w------- 1 root root 0 Jun 5 10:25 memory.force_empty
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.failcnt
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.limit_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.max_usage_in_bytes
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.slabinfo
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.tcp.failcnt
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.tcp.limit_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.tcp.max_usage_in_bytes
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.tcp.usage_in_bytes
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.kmem.usage_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:24 memory.limit_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.max_usage_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.memsw.failcnt
-rw-r--r-- 1 root root 0 Jun 5 10:24 memory.memsw.limit_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.memsw.max_usage_in_bytes
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.memsw.usage_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.move_charge_at_immigrate
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.numa_stat
-rw-r--r-- 1 root root 0 Jun 5 10:24 memory.oom_control
---------- 1 root root 0 Jun 5 10:25 memory.pressure_level
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.soft_limit_in_bytes
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.stat
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.swappiness
-r--r--r-- 1 root root 0 Jun 5 10:25 memory.usage_in_bytes
-rw-r--r-- 1 root root 0 Jun 5 10:25 memory.use_hierarchy
-rw-r--r-- 1 root root 0 Jun 5 10:25 notify_on_release
-rw-r--r-- 1 root root 0 Jun 5 10:25 tasks

也可以通过容器 PID 的方式获取 Cgroup 路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@docker-test-0:~# docker inspect nginx | grep Pid
"Pid": 1561,
"PidMode": "",
"PidsLimit": null,

root@docker-test-0:~# cat /proc/1561/cgroup
13:rdma:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
12:hugetlb:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
11:net_cls,net_prio:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
10:pids:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
9:blkio:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
8:cpuset:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
7:cpu,cpuacct:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
6:devices:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
5:perf_event:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
4:misc:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
3:freezer:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
2:memory:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
1:name=systemd:/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23
0::/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23

以内存为例,在其目录下就能看到限制的信息被写入了 memory.limit_in_bytes 中:

1
2
3
4
root@docker-test-0:~# cat /sys/fs/cgroup/memory/docker/ba9c3dfa1dfb45cbcb9448fbea2ab7fe91fcce7591ed1b73274d371b42ed4d23/memory.limit_in_bytes
268435456
root@docker-test-0:~# expr 268435456 / 1024 / 1024
256

Cgroup v2

可以通过修改内核参数,将 v1 切换为 v2:

1
vim /etc/default/grub

GRUB_CMDLINE_LINUX_DEFAULT,添加 systemd.unified_cgroup_hierarchy=1,反之,如果要从 v2 切到 v1,添加 systemd.unified_cgroup_hierarchy=0 即可:

1
GRUB_CMDLINE_LINUX_DEFAULT="systemd.unified_cgroup_hierarchy=0"

更新 GRUB 并进行重启:

1
2
update-grub
reboot

v2 目录结构如下:

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
26
27
28
29
30
31
32
root@docker-test-0:~# ls -l /sys/fs/cgroup/
total 0
-r--r--r-- 1 root root 0 Jun 5 2025 cgroup.controllers
-rw-r--r-- 1 root root 0 Jun 5 10:51 cgroup.max.depth
-rw-r--r-- 1 root root 0 Jun 5 10:51 cgroup.max.descendants
-rw-r--r-- 1 root root 0 Jun 5 2025 cgroup.procs
-r--r--r-- 1 root root 0 Jun 5 10:51 cgroup.stat
-rw-r--r-- 1 root root 0 Jun 5 2025 cgroup.subtree_control
-rw-r--r-- 1 root root 0 Jun 5 10:51 cgroup.threads
-rw-r--r-- 1 root root 0 Jun 5 10:51 cpu.pressure
-r--r--r-- 1 root root 0 Jun 5 10:51 cpuset.cpus.effective
-r--r--r-- 1 root root 0 Jun 5 10:51 cpuset.mems.effective
-r--r--r-- 1 root root 0 Jun 5 10:51 cpu.stat
drwxr-xr-x 2 root root 0 Jun 5 2025 dev-hugepages.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 dev-mqueue.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 init.scope
-rw-r--r-- 1 root root 0 Jun 5 10:51 io.cost.model
-rw-r--r-- 1 root root 0 Jun 5 10:51 io.cost.qos
-rw-r--r-- 1 root root 0 Jun 5 10:51 io.pressure
-rw-r--r-- 1 root root 0 Jun 5 10:51 io.prio.class
-r--r--r-- 1 root root 0 Jun 5 10:51 io.stat
-r--r--r-- 1 root root 0 Jun 5 10:51 memory.numa_stat
-rw-r--r-- 1 root root 0 Jun 5 10:51 memory.pressure
-r--r--r-- 1 root root 0 Jun 5 10:51 memory.stat
-r--r--r-- 1 root root 0 Jun 5 10:51 misc.capacity
drwxr-xr-x 2 root root 0 Jun 5 2025 proc-sys-fs-binfmt_misc.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 sys-fs-fuse-connections.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 sys-kernel-config.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 sys-kernel-debug.mount
drwxr-xr-x 2 root root 0 Jun 5 2025 sys-kernel-tracing.mount
drwxr-xr-x 38 root root 0 Jun 5 10:52 system.slice
drwxr-xr-x 3 root root 0 Jun 5 10:52 user.slice

运行容器后,在 /sys/fs/cgroup/system.slice/docker-<container_id>.scope/ 下就可以看到相关的配置信息,与 v1 不同的是所有配置都放在了一个目录中:

如果是 Kubernetes 通过 CRI 创建的容器,那么是在 /sys/fs/cgroup/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod<pod_id>.slice 路径下。

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
root@docker-test-0:~# ls -l /sys/fs/cgroup/system.slice/docker-aac538958e1c50f03d7e2725a1d38a3cd259d86580405093731fde3af7e267cb.scope
total 0
-r--r--r-- 1 root root 0 Jun 5 10:54 cgroup.controllers
-r--r--r-- 1 root root 0 Jun 5 10:54 cgroup.events
-rw-r--r-- 1 root root 0 Jun 5 10:54 cgroup.freeze
--w------- 1 root root 0 Jun 5 10:56 cgroup.kill
-rw-r--r-- 1 root root 0 Jun 5 10:56 cgroup.max.depth
-rw-r--r-- 1 root root 0 Jun 5 10:56 cgroup.max.descendants
-rw-r--r-- 1 root root 0 Jun 5 10:54 cgroup.procs
-r--r--r-- 1 root root 0 Jun 5 10:56 cgroup.stat
-rw-r--r-- 1 root root 0 Jun 5 10:54 cgroup.subtree_control
-rw-r--r-- 1 root root 0 Jun 5 10:56 cgroup.threads
-rw-r--r-- 1 root root 0 Jun 5 10:54 cgroup.type
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.idle
-rw-r--r-- 1 root root 0 Jun 5 10:54 cpu.max
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.max.burst
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.pressure
-rw-r--r-- 1 root root 0 Jun 5 10:54 cpuset.cpus
-r--r--r-- 1 root root 0 Jun 5 10:56 cpuset.cpus.effective
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpuset.cpus.partition
-rw-r--r-- 1 root root 0 Jun 5 10:54 cpuset.mems
-r--r--r-- 1 root root 0 Jun 5 10:56 cpuset.mems.effective
-r--r--r-- 1 root root 0 Jun 5 10:54 cpu.stat
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.uclamp.max
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.uclamp.min
-rw-r--r-- 1 root root 0 Jun 5 10:54 cpu.weight
-rw-r--r-- 1 root root 0 Jun 5 10:56 cpu.weight.nice
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.current
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.events
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.events.local
-rw-r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.max
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.rsvd.current
-rw-r--r-- 1 root root 0 Jun 5 10:56 hugetlb.1GB.rsvd.max
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.current
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.events
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.events.local
-rw-r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.max
-r--r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.rsvd.current
-rw-r--r-- 1 root root 0 Jun 5 10:56 hugetlb.2MB.rsvd.max
-rw-r--r-- 1 root root 0 Jun 5 10:56 io.max
-rw-r--r-- 1 root root 0 Jun 5 10:56 io.pressure
-rw-r--r-- 1 root root 0 Jun 5 10:56 io.prio.class
-r--r--r-- 1 root root 0 Jun 5 10:54 io.stat
-rw-r--r-- 1 root root 0 Jun 5 10:54 io.weight
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.current
-r--r--r-- 1 root root 0 Jun 5 10:54 memory.events
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.events.local
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.high
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.low
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.max
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.min
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.numa_stat
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.oom.group
-rw-r--r-- 1 root root 0 Jun 5 10:56 memory.pressure
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.stat
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.swap.current
-r--r--r-- 1 root root 0 Jun 5 10:56 memory.swap.events
-rw-r--r-- 1 root root 0 Jun 5 10:56 memory.swap.high
-rw-r--r-- 1 root root 0 Jun 5 10:54 memory.swap.max
-r--r--r-- 1 root root 0 Jun 5 10:56 misc.current
-rw-r--r-- 1 root root 0 Jun 5 10:56 misc.max
-r--r--r-- 1 root root 0 Jun 5 10:56 pids.current
-r--r--r-- 1 root root 0 Jun 5 10:56 pids.events
-rw-r--r-- 1 root root 0 Jun 5 10:54 pids.max
-r--r--r-- 1 root root 0 Jun 5 10:56 rdma.current
-rw-r--r-- 1 root root 0 Jun 5 10:56 rdma.max

通过容器 PID 获取 Cgroup 路径:

1
2
3
4
5
6
root@docker-test-0:~# docker inspect nginx | grep Pid
"Pid": 1620,
"PidMode": "",
"PidsLimit": null,
root@docker-test-0:~# cat /proc/1620/cgroup
0::/system.slice/docker-aac538958e1c50f03d7e2725a1d38a3cd259d86580405093731fde3af7e267cb.scope

再次目录下查看 CPU 和内存限制信息:

1
2
3
4
5
6
7
8
# 每 100ms 只能使用 150ms 的 CPU 时间,相当于 1.5 核 CPU 限制
root@docker-test-0:~# cat /sys/fs/cgroup/system.slice/docker-aac538958e1c50f03d7e2725a1d38a3cd259d86580405093731fde3af7e267cb.scope/cpu.max
150000 100000

root@docker-test-0:~# cat /sys/fs/cgroup/system.slice/docker-aac538958e1c50f03d7e2725a1d38a3cd259d86580405093731fde3af7e267cb.scope/memory.max
268435456
root@docker-test-0:~# expr 268435456 / 1024 / 1024
256

由此看来,cgroup v1 和 v2 的主要区别在于 v1 每个资源控制器是分开挂载的,层级结构各自独立,配置接口不统一;而 v2 所有控制器统一在一个挂载点下,共享层级结构,接口更简洁一致。v2 是对 v1 的重构,推荐在新系统和容器环境中使用。

Author

Warner Chen

Posted on

2025-06-04

Updated on

2025-06-05

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.
You forgot to set the business or currency_code for Paypal. Please set it in _config.yml.

Comments

You forgot to set the shortname for Disqus. Please set it in _config.yml.