Docker 资源限制总结
Docker 资源限制总结
一、课程核心目标
- 掌握 Docker 容器底层技术原理,理解 namespace 隔离机制、cgroups 资源限制及联合文件系统的作用
- 熟练运用 Docker 命令对容器的内存、CPU、Block IO 等资源进行限制配置,避免单容器异常占用资源影响主机及其他容器
二、容器底层技术
Docker 底层依赖三大核心技术,共同实现容器的隔离、资源控制与镜像管理:
1. namespace:实现资源隔离
将 Linux 内核的全局资源封装,使每个 namespace 拥有独立资源实例,进程在各自 namespace 内操作资源不互相干扰,共 6 种核心类型:
类型 | 隔离内容 | 作用 |
---|---|---|
UTS | 主机名、域名 | 容器可设独立主机名 / 域名,网络中视为独立节点,不影响宿主机 |
IPC | 进程间通信(信号量、消息队列、共享内存) | 防止容器内进程与外部进程通过 IPC 干扰 |
PID | 进程号 | 同一进程在不同 PID namespace 中可拥有不同 PID,实现进程号隔离 |
Mount | 文件系统挂载点视图 | 不同容器看到的文件系统层次不同,实现文件系统隔离 |
User | 用户 / 用户组 ID | 进程的 User ID/Group ID 在 namespace 内外可不同,提升权限安全 |
Network | 网络设备、IP、端口等网络栈 | 容器拥有独立虚拟网络设备,端口不冲突,实现网络隔离 |
2. cgroups:实现资源限制
cgroups(Control Groups)是 Linux 内核提供的机制,可限制、记录、隔离进程组对 CPU、内存、IO 等物理资源的使用,核心特点如下:
- 默认风险:Docker 容器默认无内存限制,若容器内存泄漏可能导致主机 OOM(内存溢出)
- 查看路径:cgroups 配置文件位于
/sys/fs/cgroup/
,创建带资源限制的容器后,系统会在对应子目录(如memory/docker/
)生成该容器的资源限制文件(如memory.limit_in_bytes
记录内存限制值) - 支持资源类型:包含 blkio(块 IO)、cpu(CPU)、memory(内存)、cpuset(CPU 核心绑定)、pids(进程数)等 12 类资源限制
3. 联合文件系统:实现镜像分层存储
用于 Docker 镜像的分层管理与存储,支持镜像的复用、增量更新,减少存储空间占用
三、容器资源限制(含实操)
容器与 Docker host 共享内核,默认资源上限与主机一致,需通过参数主动限制,避免资源争抢。实操前需先构建stress
压力测试镜像(用于模拟资源占用):
# 编写Dockerfile
vim Dockerfile
FROM ubuntu:trusty
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["/usr/bin/stress", "--verbose"]# 构建镜像
docker build -t stress .
1. 内存限制
通过参数限制容器物理内存、交换分区、内核内存等,核心参数及实操如下:
参数 | 作用 | 取值要求 |
---|---|---|
-m, --memory | 物理内存硬限制 | 最小 4M,单位 b/k/m/g(如 50M) |
--memory-swap | 物理内存 + 交换分区总限制 | 需配合-m 使用,单位同上(如-m 50M --memory-swap=100M 表示 swap 为 50M) |
--memory-reservation | 内存软限制(非强制,资源空闲时可超) | 正整数,单位同上 |
--kernel-memory | 内核内存限制 | 最小 4M,单位同上 |
--oom-kill-disable | 禁止 OOM killer 杀死容器内进程 | 布尔值(默认 false),需配合-m 使用 |
--memory-swappiness | 内存使用交换分区的倾向 | 0-100(0 尽量不用 swap,100 优先用 swap) |
--oom-score-adj | OOM 杀死优先级 | -1000(最难被杀死)到 1000(最易被杀死),默认 0 |
实操示例:
-
限制物理内存 50M,运行 1 个内存进程占用 30M:
docker run -it --name a1 --rm -m 50M stress --vm 1 --vm-bytes 30M
-
限制物理内存 50M+swap50M,运行进程占用 70M:
docker run -it --name a1 --rm -m 50M --memory-swap=100M stress --vm 1 --vm-bytes 70M
-
禁止 OOM 杀死容器:
docker run -it -m 100M --oom-kill-disable centos:7
2. CPU 限制
通过参数控制容器 CPU 使用的权重、核心绑定、时间配额,核心参数及实操如下:
参数 | 作用 | 取值要求 |
---|---|---|
-c, --cpu-shares | CPU 相对权重(非绝对限制,资源竞争时生效) | 默认 1024,值越高优先级越高(如 512、1024) |
--cpu-period | 完全公平调度(CFS)的周期(微秒) | 默认 100000(100ms),需与--cpu-quota 配合 |
--cpu-quota | 周期内可使用的 CPU 时间(微秒) | 如--cpu-period=100000 --cpu-quota=50000 表示占 50% CPU |
--cpuset-cpus | 绑定容器使用的 CPU 核心 | 用逗号分隔(如 “1,3” 表示仅用 1、3 号核心) |
--cpuset-mems | 绑定内存节点 | 仅在 NUMA 架构主机生效 |
实操示例:
-
测试 CPU 权重:创建 a1(权重 512)、a2(权重 1024),均占满 CPU,通过
top
观察 a2CPU 使用率约为 a1 的 2 倍:
docker run -it --name a1 --rm -c 512 stress --cpu 4
docker run -it --name a2 --rm -c 1024 stress --cpu 4
top
(观察 stress 进程 % CPU,a2 进程使用率约 16.6%,a1 约 16.3%,符合权重比例)
-
绑定 CPU 核心:容器仅用 1、3 号核心,
top
可看到 1、3 号核心占用率接近 100%:
docker run -it --name a1 --rm --cpuset-cpus="1,3" stress --vm 2 --vm-bytes 100M
3. Block IO 限制
控制容器对块设备(如硬盘)的读写速率、优先级,核心参数及实操如下:
参数 | 作用 | 取值要求 |
---|---|---|
--blkio-weight | 块 IO 相对权重 | 10-1000(默认 500),值越高读写优先级越高 |
--device-read-bps | 限制设备读取速率 | 格式 “设备路径:值 + 单位”(如/dev/sda:1mb ),单位 kb/mb/gb |
--device-write-bps | 限制设备写入速率 | 同--device-read-bps |
--device-read-iops | 限制设备每秒读取 IO 次数 | 正整数(如 100 表示每秒 100 次读 IO) |
--device-write-iops | 限制设备每秒写入 IO 次数 | 同--device-read-iops |
实操示例:
-
测试 IO 权重:创建 cy1(权重 100)、cy2(权重 1000),均执行
dd
写盘,资源繁忙时 cy2 速度更快:
docker run --name cy1 -it --rm --blkio-weight 100 centos:7
docker run --name cy2 -it --rm --blkio-weight 1000 centos:7
容器内执行:
time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
(对比执行时间,权重高者更快)
-
限制写入速率:容器写
/dev/sda
速率不超过 1MB/s,
dd
测试 20M 数据需约 20 秒:
docker run --name cy3 -it --rm --device-write-bps /dev/sda:1mb centos:7
容器内执行:
time dd if=/dev/zero of=test.out bs=1M count=20 oflag=direct
(结果显示速度约 1.0 MB/s)
具体示例:
cgroups
cgroups是control groups的缩写,最初由google的工程师提出,后来被整合进Linux内核。cgroups是Linux内核提供的一种可以限制、记录、隔离进程组(process groups)所使用的物理资源(如:CPU、内存、IO等)的机制。在默认情况下,Docker容器并不会对容器内部进程使用的内存大小进行任何限制。对于直接使用Docker的用户而言,这非常危险。如果哪个业务容器,出现了内存泄漏;那么它可能会危害到整个主机系统,导致业务应用容器所在的主机出现OOM。
cgroups到底长什么样子呢?我们可以在/sys/fs/cgroup中找到它,创建一个新容器,并使用-m限制容器能够使用的内存大小[root@docker ~]# docker run --name sycentos1 -itd -m 200M centos:7 Unable to find image 'centos:7' locally 7: Pulling from library/centos 2d473b07cdd5: Pull complete Digest: sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4 Status: Downloaded newer image for centos:7 68d4c3ba477ff1287c2f071db32cd56aae9586d08632abe6cbbba1c64ad07a89
随着容器的创建启动,在/sys/fs/cgroup/memory/docker/目录中,Linux会创建该容器的cgroup目录,目录中包含了对容器所使用资源的限制
[root@docker ~]# cat /sys/fs/cgroup/memory/docker/68d4c3ba477ff1287c2f071db32cd56aae9586d08632abe6cbbba1c64ad07a89/memory.limit_in_bytes 209715200
在/sys/fs/cgroup/目录中还包含其他的资源限制
[root@docker ~]# ls /sys/fs/cgroup/ blkio cpuacct cpuset freezer memory net_cls,net_prio perf_event systemd cpu cpu,cpuacct devices hugetlb net_cls net_prio pids
资源管理
每个容器在运行时,都需要内存、CPU、IO等资源,用户可以根据需求为容器分配资源。
对于容器而言,容器中的资源大小与Docker host资源大小是一致的,因为它们都共享同一个
内核。如果运行多个容器,某个容器在运行过程中异常占用大量的资源,那么势必会对其他容
器造成影响
构建stress镜像,stress是一个容器压力测试工具,也能帮助我们学习docker的资源限制[root@docker ~]# vim Dockerfile FROM ubuntu:trusty RUN apt-get update && apt-get install -y stress ENTRYPOINT ["/usr/bin/stress","--verbose"] ~ [root@docker ~]# docker build -t stress . [+] Building 35.2s (6/6) FINISHED docker:default=> [internal] load build definition from Dockerfile 0.0s=> => transferring dockerfile: 147B 0.0s=> [internal] load metadata for docker.io/library/ubuntu:trusty 0.7s=> [internal] load .dockerignore 0.0s=> => transferring context: 2B 0.0s=> [1/2] FROM docker.io/library/ubuntu:trusty@sha256:64483f3496c1373bfd55348e88694d1c4d0c9b 20.6s=> => resolve docker.io/library/ubuntu:trusty@sha256:64483f3496c1373bfd55348e88694d1c4d0c9b6 0.0s=> => sha256:13b66b487594a1f2b75396013bc05d29d9f527852d96c5577cc4f187559875d 3.31kB / 3.31kB 0.0s=> => sha256:2e6e20c8e2e69fa5c3fcc310f419975cef5fbeb6f7f2fe1374071141281b6 70.69MB / 70.69MB 6.2s=> => sha256:0551a797c01db074ab0233ceb567e66b8ebdcb9de9a2e7baa36d57dfbca46 72.66kB / 72.66kB 0.3s=> => sha256:512123a864da5e2a62949e65b67106292c5c704eff90cac2b949fc8d7ac1e58e 189B / 189B 0.2s=> => sha256:64483f3496c1373bfd55348e88694d1c4d0c9b660dee6bfef5e12f43b9933b3 1.20kB / 1.20kB 0.0s=> => sha256:881afbae521c910f764f7187dbfbca3cc10c26f8bafa458c76dda009a901c29d 945B / 945B 0.0s=> => extracting sha256:2e6e20c8e2e69fa5c3fcc310f419975cef5fbeb6f7f2fe1374071141281b6a06 14.2s=> => extracting sha256:0551a797c01db074ab0233ceb567e66b8ebdcb9de9a2e7baa36d57dfbca463a3 0.0s=> => extracting sha256:512123a864da5e2a62949e65b67106292c5c704eff90cac2b949fc8d7ac1e58e 0.0s=> [2/2] RUN apt-get update && apt-get install -y stress 13.6s=> exporting to image 0.1s=> => exporting layers 0.1s=> => writing image sha256:19e70fe12fec2302ffed9e7869d501d63d70077f338c1bfdf77743fc9cc2c765 0.0s=> => naming to docker.io/library/stress
内存限制
容器资源限制参数说明
内存限制
容器对内存的使用限制一般会使用-m或者–memory,这个参数仅限制对物理内存的使用
[root@docker ~]# docker run -it --name a1 --rm -m 50M stress --vm 1 --vm-bytes 30M
stress: dbug: [7] allocating 31457280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 31457280 bytes
stress: dbug: [7] allocating 31457280 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
.......
在容器中也可以使用swap,这就需要用到–memory-swap参数,–memory-swap是指容器所用的
物理内存加sawp的总和,需要配合-m使用
[root@docker ~]# docker run -it --name a1 --rm -m 50M --memory-swap=100M stress --vm 1 --vm-bytes 70M
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 73400320 bytes ...
stress: dbug: [7] touching bytes in strides of 4096 bytes ...
stress: dbug: [7] freed 73400320 bytes
stress: dbug: [7] allocating 73400320 bytes ...
.......
Memory reservation是一种软性限制,用于节制容器内存使用
[root@docker ~]# docker run -it -m 100M --memory-reservation 50M centos:7
[root@b9c28d710b41 /]#
我们可以通过设置–oom-kill-disable选项来禁止OOM killer杀死容器内进程
[root@docker ~]# docker run -it -m 100M --oom-kill-disable centos:7
[root@8218723bb32c /]#
cpu限制
常用的容器CPU限制参数如表:
cpu限制
创建两个容器a1和a2,a1的cpu权重为512,a2的cpu权重为1024,,同时将Docker host上的cpu全部占满
[root@docker ~]# docker run -it --name a1 --rm -c 512 stress --cpu 4
stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 12000us
stress: dbug: [1] --> hogcpu worker 4 [7] forked
stress: dbug: [1] using backoff sleep of 9000us
stress: dbug: [1] --> hogcpu worker 3 [8] forked
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [9] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [10] forked
.....
按1键显示CPU核数
[root@docker ~]# top
top - 11:48:48 up 1:04, 2 users, load average: 0.69, 0.51, 0.80
Tasks: 200 total, 6 running, 193 sleeping, 1 stopped, 0 zombie
%Cpu0 : 99.4 us, 0.6 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4026372 total, 2177616 free, 562408 used, 1286348 buff/cache
KiB Swap: 4194300 total, 4193108 free, 1192 used. 3045872 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 13242 root 20 0 7312 96 0 R 100.0 0.0 0:16.73 stress 13244 root 20 0 7312 96 0 R 100.0 0.0 0:16.74 stress 13243 root 20 0 7312 96 0 R 99.7 0.0 0:16.75 stress 13245 root 20 0 7312 96 0 R 99.7 0.0 0:16.74 stress
[root@docker ~]# docker run -it --name a2 --rm -c 1024 stress --cpu 4
stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 12000us
stress: dbug: [1] --> hogcpu worker 4 [7] forked
stress: dbug: [1] using backoff sleep of 9000us
stress: dbug: [1] --> hogcpu worker 3 [8] forked
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [9] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [10] forked
......
[root@docker ~]# top
top - 11:49:51 up 1:05, 2 users, load average: 1.28, 0.79, 0.88
Tasks: 202 total, 6 running, 195 sleeping, 1 stopped, 0 zombie
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 98.5 us, 1.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4026372 total, 2176336 free, 563012 used, 1287024 buff/cache
KiB Swap: 4194300 total, 4193108 free, 1192 used. 3044740 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 13367 root 20 0 7312 92 0 R 100.0 0.0 0:06.07 stress 13368 root 20 0 7312 92 0 R 100.0 0.0 0:06.07 stress 13369 root 20 0 7312 92 0 R 100.0 0.0 0:06.07 stress 13370 root 20 0 7312 92 0 R 99.1 0.0 0:06.05 stress
cpu限制
参数-cpuset-cpus用于设置容器可以使用的CPU核数,示例如下,将容器中的工作进程运行在cpu1和cpu3上面
[root@docker ~]# docker run -it --name a1 --rm --cpuset-cpus="1,3" stress --vm 2 --vm-bytes 100M
[root@docker ~]# top
top - 15:30:18 up 5 min, 2 users, load average: 0.52, 0.21, 0.09
Tasks: 198 total, 3 running, 195 sleeping, 0 stopped, 0 zombie
%Cpu0 : 0.3 us, 4.4 sy, 0.0 ni, 95.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 3.5 us, 96.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.3 us, 3.4 sy, 0.0 ni, 96.2 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 3.4 us, 96.6 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
Block IO限制
Block IO限制常用参数如表:
blkio IO权重,默认情况下,所有的容器都是平级的读写磁盘,可以通过–blkio-weight参数设置容器读写磁盘的优先级
示例如下,使用下面的命令创建两个–blkio-weight值不同的容器:
[root@docker ~]# docker run --name sy1 -it --rm --blkio-weight 100 centos:7
[root@14d6b12e1acb /]# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 2.28117 s, 471 MB/sreal 0m2.288s
user 0m0.000s
sys 0m2.022s[root@docker ~]# docker run --name sy2 -it --rm --blkio-weight 1000 centos:7
[root@e1edecd17907 /]# time dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 2.27993 s, 471 MB/sreal 0m2.281s
user 0m0.000s
sys 0m1.966s
在容器中同时执行dd命令,进行测试,第一个是a1的执行结果,第二个是a2的执行结果,两个结果对比并不明显,因为Docker host不是那么的繁忙
device-write-bps,默认情况下,Docker对容器的写速度是没有限制的,我们可以使用–device-write-bps参数限制容器对硬盘些速度的限制
示例如下,使用下面的命令创建容器,并执行命令验证写速度的限制。通过直接结果可以得知,容器向硬盘写入20M的数据,以1.0 MB/s的速度写入
[root@docker ~]# docker run --name sy3 -it --rm --device-write-bps /dev/sda:1mb centos:7
[root@115d4a4e6bcf /]# time dd if=/dev/zero of=test.out bs=1M count=20 oflag=direct
20+0 records in
20+0 records out
20971520 bytes (21 MB) copied, 0.0276538 s, 758 MB/sreal 0m0.029s
user 0m0.000s
sys 0m0.026s
四、核心总结
- namespace 核心:Linux 内核实现 6 种 namespace(UTS、IPC、PID、Mount、User、Network),是容器隔离的基础
- cgroups 关键路径:容器创建后,
/sys/fs/cgroup/
下生成对应资源限制目录,记录容器资源配置 - 资源限制本质:Docker 仅限制容器的资源使用上限,但容器自身仍 “认为” 资源与主机一致,需主动配置限制避免风险