---
title: Docker容器的资源限制
date: 2021-04-10 17:41:17
tags: [DevOps, Docker, Resource Limit, CPU, Memory, IO]
categories:
  - [DevOps, Docker]
---
在默认情况下，Docker对于其中正在运行的容器的资源请求是会尽可能的满足的，容器对于资源的请求无非以下几种：CPU、内存和IO。<!--more-->在没有经过特殊设定的时候，Docker所能够给予容器的最大资源只受限于系统的最大资源，系统内的最大资源数量可以通过`docker info`命令查询。

容器的资源限制在容器创建的时候就需要固定下来，在容器运行过程中不能再变化。如果需要调整容器的资源配置，那就需要将容器重建。容器在创建的时候其资源限制是通过一系列的选项实现的，这些选项可以普遍用在`docker create`和`docker run`中，但是在编写Docker Compose编排脚本时，对于资源的控制会变得更加容易。

## 内存限制

默认情况下，Docker不会限制容器所使用的内存，容器可以使用宿主机上所有的内存。但是如果容器内出现恶意软件，侵占了大量内存，此时就有可能导致宿主机上的进程被杀掉释放内存，从而导致服务中断。Docker对于容器内存的限制主要是通过限制容器使用内存的上下限以及交换内存的量来实现的。

对于内存的限制，可以使用以下选项参数以及设置项。

- `--memory`，设置容器可以使用的最大内存大小，在编排文件中使用`mem_limit`设置。最大内存大小可以设置的最小值为`4m`，要求使用正数。
- `--memory-swap`，设置容器可以使用的交换空间大小，在编排文件中使用`memswap_limit`设置。交换空间的设置是有一定技巧的，如果设置的不正确会导致内存计算复杂度上升，影响调度器的工作效率，降低Docker服务的性能。交换空间的设置必须搭配内存限制同时设置才能够起效。在设置不同的值的时候会产生以下不同的规则。
   - `memory-swap`设置为一个正值，若大于`memory`的值，则容器能够使用的总内存数量为`memory-swap`的值，可以使用的交换空间的数量则为`memory-swap`减去`memory`的数量。
   - `memory-swap`设置为与`memory`相同的值，表示不允许容器使用交换空间。这在内存充分够用的情况下，可以有效的提升容器的性能。
   - `memory-swap`设置为`0`，相当于没有设置`memory-swap`。
   - 如果`memory-swap`没有设置，那么容器将可以使用`memory`指定数量的内存以及同等数量的交换空间，例如`memory`设置为`500m`，但未设置`memory-swap`，此时容器将可以使用`500m`内存以及`500m`的交换空间，合计可以使用`1g`的空间。
   - 如果`memory-swap`设置为`-1`，表示容器可以使用无限量的交换空间，但是可以使用的内存空间还依旧受`memory`的限制。
- `--memory-swapness`，允许宿主机把容器所使用的匿名内存页置换出来的比例。在编排文件中使用`mem_swapness`设置。
- `--memory-reservation`，设置需要给宿主机保留的内存量，如果宿主机的内存小于这个值，Docker就会执行容器内存管理动作。编排文件中使用`mem_reservation`设置。
- `--kernel-memory`，设置容器所允许使用的最大核心内存数量，编排文件中没有此项设置。核心内存是一个不能被交换出来的内存空间，如果一个容器占据了过多的核心内存，那么将会对宿主机本身的运行造成影响。
- `--oom-kill-disable`，设置是否关闭当容器发生内存不足时杀掉容器进程的功能。编排文件中使用`oom_kill_disable`设置。`oom-kill-disable`在设置为`false`的时候必须搭配`memory`一起使用，否则容器会无限制的占用内存而使得宿主机中的进程被杀掉。

> 在发生OOM的时候，容器中的进程被杀掉的优先级比宿主机中的进程要低，这是由Docker控制的，所以在宿主机发生OOM的时候，优先被杀掉的是宿主机的进程，而不是容器中的进程。

## CPU限制

Docker同样不会限制容器中的进程对于CPU的使用。进程共享CPU的机制是时间片轮转，限制一个容器所能够使用的CPU资源，也就是限制容器所能够使用的CPU时间片数量。默认状态下，Docker从用CFS（公平调度）调度器来控制进程对于CPU的使用。CFS调度器通过计算进程所消耗的CPU时间来确定进程的调度。当调整容器的CPU限制时，Docker会相应的调整容器在系统中Cgroup中的配置。

对于CPU的限制，可以使用以下选项参数以及设置项。

- `--cpus`，设置容器可以使用的最多的CPU资源数量，编排文件中使用`cpus`设置。CPU资源可以取的值为浮点数，表示容器可以占用CPU的百分比。例如取值`1.5`，表示可以使用一个半的CPU核心，即一个核心可以使用到100%，另一个核心至多使用到50%。
- `--cpuset-cpus`，限制容器能够使用的CPU核心，设置之后容器将被绑定到指定的核心上运行，编排文件中使用`cpuset`设置。CPU的第一个核心编号从`0`开始，例如`0,3`表示容器可以使用第一个和第四个核心。
- `--cpu-shares`，设定容器使用CPU的权重，默认值是`1024`，设置比`1024`高的值将会使容器获得更多的CPU时间片，编排文件中使用`cpu_shares`设置。

此外还有`--cpu-period`和`--cpu-quota`两个选项可以用来配置容器可用的CPU资源，但是这两个选项需要同时使用，并且其主要是控制CFS的参数，相对其他的选项较为低级，所以一般推荐采用其他更加方便的选项，例如`--cpus`。

## IO限制

一般对IO的限制主要是限制容器对于磁盘的读写速度和所使用的磁盘容量。Docker目前能够对容器进行限制的主要是磁盘的读写速度，而对于容量来说，并没有能够限制容器使用磁盘容量的方法。

对于IO的限制，命令行和编排文件中是不甚相同的。在命令行中主要通过以下几个选项来实现。

- `--blkio-weight`，设置容器进行设备读写的操作权重，与`--cpu-shares`类似，取值范围是`10-1000`。容器中各个block的读写速度与权重值成反比。
- `--blkio-weight-device`，设置容器对于指定设备的读写权重。
- `--device-read-bps`，限制指定设备每秒最多可以读多少比特，设备以及限制的指定使用格式：`<设备路径>:<限制数量>[单位]`。（下同）
- `--device-read-iops`，限制指定设备每秒最多可以执行多少次IO读操作。
- `--device--write-bps`，限制指定设备每秒最多可以写多少比特。
- `--device--write-iops`，限制指定设备每秒最多可以执行多少次IO写操作。

在编排文件里主要是在`blkio_config`设置项中完成的，`blkio_config`中可以使用以下键来设定容器的IO限制。

- `weight`，相当于`--blkio-weight`。
- `weight_device`，相当于`--blkio-weight-device`，可以接受一个设置设备的列表，列表中可以使用以下两个键来设定指定的设备。
   - `path`，设备所在路径。
   - `weight`，对于设备的读写权重。
- `device_read_bps`、`device_write_bps`、`device_read_iops`、`device_write_iops`，相当于前文中的各个同名设定选项，同样都接受一个设置设备的列表，列表中可以使用以下两个键来设定指定设备。
   - `path`，设备所在的路径。
   - `rate`，读写频率值，可以为整型数值或者带单位标识的字符串。
