资源限制

1 CPU 和 内存

body = {
    "Memory": int(self.container["flavor"]["memoryInMB"]["limit"]) * 1024 * 1024,
    "MemorySwap": int(self.container["flavor"]["memoryInMB"]["limit"]) * 1024 * 1024,
    "CpuShares": int(self.container["flavor"]["cpuInCore"]["quota"]) * 1024,
    "CpuQuota": int(self.container["flavor"]["cpuInCore"]["limit"]) * 100000
}
docker update --help

Usage:  docker update [OPTIONS] CONTAINER [CONTAINER...]

Update configuration of one or more containers

Options:
      --blkio-weight uint16        Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0)
      --cpu-period int             Limit CPU CFS (Completely Fair Scheduler) period
      --cpu-quota int              Limit CPU CFS (Completely Fair Scheduler) quota
      --cpu-rt-period int          Limit the CPU real-time period in microseconds
      --cpu-rt-runtime int         Limit the CPU real-time runtime in microseconds
  -c, --cpu-shares int             CPU shares (relative weight)
      --cpus decimal               Number of CPUs
      --cpuset-cpus string         CPUs in which to allow execution (0-3, 0,1)
      --cpuset-mems string         MEMs in which to allow execution (0-3, 0,1)
      --kernel-memory bytes        Kernel memory limit
  -m, --memory bytes               Memory limit
      --memory-reservation bytes   Memory soft limit
      --memory-swap bytes          Swap limit equal to memory plus swap: '-1' to enable unlimited swap
      --pids-limit int             Tune container pids limit (set -1 for unlimited)
      --restart string             Restart policy to apply when a container exits

1.1 CPU

线上的 4c 的容器 CPU 配置

2 磁盘限速

  • bps 是 byte per second,每秒读写的数据量。

  • iops 是 io per second,每秒 IO 的次数。

  • --device-read-bps,限制读某个设备的 bps。

  • --device-write-bps,限制写某个设备的 bps。

  • --device-read-iops,限制读某个设备的 iops。

  • --device-write-iops,限制写某个设备的 iops。

2.1 Direct I/O 和 Buffered I/O

Linux 的两种文件 I/O 模式了:Direct I/O 和 Buffered I/O

  • Direct I/O 模式,用户进程如果要写磁盘文件,就会通过 Linux 内核的文件系统层(filesystem) -> 块设备层(block layer) -> 磁盘驱动 -> 磁盘硬件

  • Buffered I/O 模式,那么用户进程只是把文件数据写到内存中(Page Cache)就返回了,而 Linux 内核自己有线程会把内存中的数据再写入到磁盘中。

在 Linux 里,由于考虑到性能问题,绝大多数的应用都会使用 Buffered I/O 模式。

经过测试发现 Direct I/O 可以通过 blkio Cgroup 来限制磁盘 I/O,但是 Buffered I/O 不能被限制。

原因就是被 Cgroups v1 的架构限制了。

这个 Buffered I/O 限速的问题,在 Cgroup V2 里得到了解决,其实这个问题也是促使 Linux 开发者重新设计 Cgroup V2 的原因之一。

2.2 Cgroup v1 Vs v2

2.2.1 /sys/fs/cgroup/

v1

v2

v1 的 cgroup 为每个控制器都使用独立的树(目录), 每个目录就代表了一个 cgroup subsystem,各个 Subsystem 各自为政,看起来比混乱,难以管理

2.3 系统开启 Cgroup v2

/etc/default/grub 添加 systemd.unified_cgroup_hierarchy=1 参数

更新 grub 并重启

检查

2.4 Docker 配置

未开启 Cgroup V2 时,docker info 输出以下信息

Cgroup Driver: cgroupfs Cgroup Version: 1

Cgroup Driver:

  • cgroupfs:Docker 默认的驱动,直接操作文件系统中的 cgroup 目录(如 /sys/fs/cgroup/)。

  • systemd:利用 systemd 作为 cgroup 管理器,将容器进程纳入 systemd 的单元(unit)层级中,实现更精细的资源控制和日志管理。

如果要修改容器的容器默认的 cgroup 父路径(默认是 "/system.slice"),可以添加如下配置:

2.5 测试

2.5.1 创建容器

2.5.2 dd 测试

2.5.3 查看磁盘 io

2.5.4 磁盘 io 限制

返回结果中的 253:16 是磁盘编号, 可以通过 lsblk 获取

$ lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT vda 253:0 0 20G 0 disk `-vda1 253:1 0 20G 0 part / vdb 253:16 0 100G 0 disk /mnt

cgroup v1 在通过如下方式获取

  • blkio.throttle.read_bps_device

  • blkio.throttle.read_iops_device

  • blkio.throttle.write_bps_device

  • blkio.throttle.write_iops_device

$ cat /sys/fs/cgroup/blkio/docker/{container_id}/blkio.throttle.write_bps_device

253:16 4000

2.6 Docker API 限制磁盘 IO

Cgroup v1 无法限制 Page Cache 刷盘速度

Cgroup v2 通过 Buffered I/O 写入文件时,会秒级完成写入,但是从 Page Cache 往磁盘写入时会限速

创建容器时的 API 参数

在 Docker API 中,BlkioDeviceReadBpsHostConfig 的一个字段,格式为:

示例

获取磁盘设备

2.7 示例

综合限制磁盘 IOPS 和 IO BPS

  • 读 IOPS ≤ 100 次/秒,读带宽 ≤ 1MB/s。

  • 写 IOPS ≤ 50 次/秒,写带宽 ≤ 512KB/s。

2.8 对运行中的容器进行限制磁盘 IO

https://github.com/moby/moby/blob/master/daemon/container/container_unix.go#L248 (截止2025年9月15日)

Docker 原生不支持运行时修改块设备I/O限制,需要通过 cgroup 来进行修改

2.9 获取磁盘编号

Last updated