Files
security-book/00.基础阶段/02.Linux基础/15.Docker/07.Docker资源限制.md
2025-08-27 14:13:17 +08:00

12 KiB
Raw Blame History

07.Docker资源限制

07.Docker资源限制

1. Docker 容器资源限制与 OOM 异常处理

1.1 容器资源限制

默认情况下容器没有资源限制可以使用主机内核调度程序允许的尽可能多的给定资源。Docker 提供了控制容器可以使用多少内存或者 CPU 的方法,通过设置 docker run 命令的运行时配置标志来实现。

其中一些功能要求宿主机的内核支持 Linux 功能。要检查支持情况,可以使用 docker info 命令。如果内核中禁用了某项功能,可能会在输出结尾处看到警告。

1.2 OOM 异常

对于 Linux 主机,如果没有足够的内存来执行其他重要的系统任务,将会抛出 OOM 异常(内存溢出、内存泄漏、内存异常)。随后系统会开始杀死进程以释放内存,凡是运行在宿主机上的进程都有可能被 kill包括 dockerd 和其他的应用程序。如果重要的系统进程被 kill会导致和该进程相关的服务全部宕机。

产生 OOM 异常时,dockerd 会尝试通过调整 Docker 守护程序上的 OOM 优先级来减轻这些风险,以便它比系统上的其他进程更不可能被杀死。但是,容器的 OOM 优先级未调整时,单个容器被杀死的可能性更大(不推荐调整容器的优先级这种方式)。

1.3 Linux 进程 OOM 评分机制

Linux 会为每个进程计算一个分数,最终它会将分数最高的进程 kill 掉。相关文件说明如下:

  • /proc/PID/oom_score_adj
    • 范围为 -1000 到 1000。
    • 值越高越容易被宿主机 kill 掉。
    • 如果将该值设置为 -1000则进程永远不会被宿主机 kernel kill。
  • /proc/PID/oom_adj
    • 范围为 -17 到 +15。
    • 取值越高越容易被干掉。
    • 如果是 -17则表示不能被 kill。
    • 该设置参数的存在是为了和旧版本的 Linux 内核兼容。
  • /proc/PID/oom_score
    • 这个值是系统综合进程的内存消耗量、CPU 时间(utime + stime)、存活时间(uptime - start time)和 oom_adj 计算出的进程得分。
    • 消耗内存越多得分越高,越容易被宿主机 kernel 强制杀死。

2. 容器的内存限制

Docker可以强制执行硬性内存限制,即只允许容器使用给定的内存大小

Docker也可以执行非硬性内存限制,即容器可以使用尽可能多的内存,除非内核检测到主机上的内存不够用了

2.1 内存限制参数

2.1.1 -m--memory
  • 功能:限制容器最大可用内存。

  • 最小值4m。

  • 示例

    docker run -m 512m my_image
    
2.1.2 --memory-swap
  • 功能:限制容器可用的内存 + swap 总量。

  • 前提:需先设置 --memory

  • 特殊值-1 表示不限制 swap 使用。

  • 示例

    docker run --memory 256m --memory-swap 512m my_image
    
2.1.3 --memory-swappiness
  • 功能:控制容器使用 swap 的倾向性。

  • 范围0尽量不使用 swap到 100尽量使用 swap

  • 示例

    docker run --memory-swappiness 30 my_image
    
2.1.4 --kernel-memory
  • 功能:限制容器使用的内核内存。

  • 最小值4m。

  • 注意事项:不推荐设置,可能影响宿主机和其他容器。

  • 示例

    docker run --kernel-memory 64m my_image
    
2.1.5 --memory-reservation
  • 功能:设置软内存限制,低于 --memory

  • 激活条件:主机内存争用或不足时生效。

  • 注意事项:必须小于 --memory,且不保证容器一定不超过此限制。

  • 示例

    docker run --memory 1g --memory-reservation 512m my_image
    
2.1.6 --oom-kill-disable
  • 功能:禁止 OOM 时杀死容器内进程。

  • 前提:必须与 --memory 一起使用。

  • 注意事项:若未设置 --memoryOOM 时仍可能杀死进程。

  • 示例

    docker run --memory 512m --oom-kill-disable my_image
    

2.2 内从限制案例

如果一个容器未作内存使用限制,则该容器可以利用到系统内存最大空间,默认创建的容器没有做内存资源限制

一、拉取容器压测工具镜像

[root@localhost ~]# docker pull tylersmith22/docker-stress-ng
[root@localhost ~]# docker run -it --rm tylersmith22/docker-stress-ng -help

二、使用压测工具开启两个工作进程每个工作进程最大允许使用内存256M且宿主机不限制当前容器的最大内存

[root@localhost nginx]# docker run -it --rm --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O   PIDS
3ca32774fc20   test1     185.16%   514.3MiB / 1.781GiB   28.21%    648B / 0B   0B / 0B     5

# 可以看到容器的内存占用大概为256的两倍因为两个进程

三、宿主机限制最大内存使用

[root@localhost nginx]# docker run -it --rm -m 256m --name test2 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 2 vm

# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O         BLOCK I/O         PIDS
d612ce9b0776   test2     0.00%     255.9MiB / 256MiB   99.97%    1.02kB / 126B   4.83GB / 36.8GB   5

2.3 内存软限制

软限制不会真正限制到内存的使用

[root@localhost ~]# docker run -it --rm -m 256m --memory-reservation 128m --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m
[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT   MEM %     NET I/O     BLOCK I/O         PIDS
0ffb4b8fdbde   test1     174.52%   255.9MiB / 256MiB   99.95%    648B / 0B   5.33GB / 18.1GB   5

交换分区限制

[root@localhost ~]# docker run -it --rm -m 256m --memory-swap 512m --name test1 tylersmith22/docker-stress-ng --vm 2 --vm-bytes 256m

3. 容器的CPU限制

一个宿主机有几十个核心的cpu但是宿主机上可以同时运行成百上千个不同的进程用以处理不同的任务多进程共用一个cpu的核心依赖计数就是为可压缩资源即一个核心cpu可以通过调度而运行多个进程但是在同一个单位时间内只能由一个进程在cpu上运行那么这么多的进程怎么在cpu上执行和调度的呢进程优先级

默认情况下每个容器对主机cpu周期的访问权限是不受限制的但是我们可以人为干扰

3.1 CPU限制参数

3.1.1 --cpus
  • 功能:指定容器可以使用的 CPU 资源数量。

  • 示例:主机有 2 个 CPU设置 --cpus=1.5,容器最多可使用 1.5 个 CPU。

  • 示例命令

    docker run --cpus 1.5 my_image
    
3.1.2 --cpu-period--cpu-quota
  • 功能:设置 CPU 调度周期和配额。

  • 关系:必须一起使用,计算方式为 cpu-quota / cpu-period

  • 示例

    docker run --cpu-period 100000 --cpu-quota 50000 my_image
    
3.1.3 --cpuset-cpus
  • 功能:指定容器运行的 CPU 编号(绑核)。

  • 示例:限制容器在 CPU 0 和 CPU 1 上运行。

  • 示例命令

    docker run --cpuset-cpus 0,1 my_image
    
3.1.4 --cpuset-mems
  • 功能:设置容器使用的内存节点(仅对 NUMA 架构有效)。

  • 示例:限制容器使用内存节点 0。

  • 示例命令

    docker run --cpuset-mems 0 my_image
    
3.1.5 --cpu-shares
  • 功能:设置容器的 CPU 时间片权重。

  • 默认值1024。

  • 范围:最小 2最大 262144。

  • 示例:容器 A 设置为 1024容器 B 设置为 2048容器 B 的 CPU 时间片是容器 A 的两倍。

  • 示例命令

    docker run --cpu-shares 2048 my_image
    

3.2 CPU限制案例

3.2.1 未限制容器cpu
  • 启动1个进程占用4核cpu未限制容器会把cpu全部占完
# 查看我们宿主机的cup数量
[root@localhost ~]# top
top - 21:32:49 up 43 min,  2 users,  load average: 3.54, 1.82, 0.80
Tasks: 186 total,   1 running, 185 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni, 99.5 id,  0.0 wa,  0.5 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

[root@localhost ~]# docker run -it --rm --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu, 1 vm

# 新建窗口查看
[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O   PIDS
c6a795e4c09f   test1     396.78%   282.6MiB / 1.703GiB   16.21%    876B / 126B   0B / 0B     7

# 可以看出CPU的使用率大概是400% 因为我们是4个核心单个核心跑满是100%
3.2.2 限制容器cpu
[root@localhost ~]# docker run -it --rm --cpus 2 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4
stress-ng: info: [1] defaulting to a 86400 second run per stressor
stress-ng: info: [1] dispatching hogs: 4 cpu, 1 vm

[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O       BLOCK I/O   PIDS
5b7dcb36d738   test1     200.65%   279.7MiB / 1.703GiB   16.04%    876B / 126B   0B / 0B     7

[root@localhost ~]# top
top - 21:36:15 up 47 min,  3 users,  load average: 1.38, 1.92, 1.05
Tasks: 198 total,   8 running, 190 sleeping,   0 stopped,   0 zombie
%Cpu0  : 50.7 us,  1.4 sy,  0.0 ni, 47.2 id,  0.0 wa,  0.7 hi,  0.0 si,  0.0 st
%Cpu1  : 52.9 us,  0.0 sy,  0.0 ni, 47.1 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  : 50.7 us,  0.0 sy,  0.0 ni, 48.6 id,  0.0 wa,  0.7 hi,  0.0 si,  0.0 st
%Cpu3  : 50.4 us,  0.0 sy,  0.0 ni, 48.9 id,  0.0 wa,  0.7 hi,  0.0 si,  0.0 st

# 并且是平均使用所有的cup核心
3.2.3 将容器运行到指定的cpu上
[root@localhost ~]# docker run -it --rm  --cpus 2 --cpuset-cpus 0,2 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4 

[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O         PIDS
ee11d834dde5   test1     186.68%   1.488GiB / 1.781GiB   83.60%    648B / 0B   44.8GB / 95.7MB   25

[root@localhost ~]# top
top - 21:38:25 up 49 min,  3 users,  load average: 0.92, 1.40, 0.96
Tasks: 197 total,   6 running, 191 sleeping,   0 stopped,   0 zombie
%Cpu0  : 97.3 us,  2.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.7 hi,  0.0 si,  0.0 st
%Cpu1  :  0.3 us,  0.0 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.3 si,  0.0 st
%Cpu2  : 98.3 us,  1.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.7 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.3 hi,  0.0 si,  0.0 st
MiB Mem :   1743.4 total,    457.2 free,    924.2 used,    531.4 buff/cache
MiB Swap:   2048.0 total,   2047.2 free,      0.8 used.    819.2 avail Mem
  • 基于cpu-shares对cpu进行切分
[root@localhost ~]# docker run -it --rm  -d --cpu-shares 1000 --name test1 tylersmith22/docker-stress-ng --vm 1 --cpu 4 
[root@localhost ~]# docker run -it --rm  -d --cpu-shares 500 --name test2 tylersmith22/docker-stress-ng --vm 1 --cpu 4 

[root@localhost ~]# docker stats
CONTAINER ID   NAME      CPU %     MEM USAGE / LIMIT     MEM %     NET I/O     BLOCK I/O       PIDS
d6dd34edb722   test1     543.41%   819.6MiB / 1.781GiB   44.95%    648B / 0B   102MB / 154MB   13
154b07a94e2f   test2     241.15%   711.1MiB / 1.781GiB   39.00%    648B / 0B   406MB / 145MB