资源限制
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
--cpu-shares 用来设置 CPU 的权重,当 CPU 资源充足时,设置 CPU 的权重是没有意义的。只有在容器争用 CPU 资源的情况下, CPU 的权重才能让不同的容器分到不同的 CPU 用量。
--cpus=2 和 --cpu-period=100000 --cpu-quota=200000 是同等作用,其实就是限制了可用的 CPU 个数为 2(通过进程消耗的 CPU 时间片来统计出进程占用 CPU 的百分比)
线上的 4c 的容器 CPU 配置
docker update --cpu-shares 4096 --cpu-quota 400000 {container_name}
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 的架构限制了。
进程 pid,它可以分别属于 memory Cgroup 和 blkio Cgroup。
但是在 blkio Cgroup 对进程 pid 做磁盘 I/O 做限制的时候,blkio 子系统是不会去关心 pid 用了哪些内存,哪些内存是不是属于 Page Cache,而这些 Page Cache 的页面在刷入磁盘的时候,产生的 I/O 也不会被计算到进程 pid 上面。
就是这个原因,导致了 blkio 在 Cgroups v1 里不能限制 Buffered I/O。
这个 Buffered I/O 限速的问题,在 Cgroup V2 里得到了解决,其实这个问题也是促使 Linux 开发者重新设计 Cgroup V2 的原因之一。
2.2 Cgroup v1 Vs v2
2.2.1 /sys/fs/cgroup/
v1
$ tree -L 1 /sys/fs/cgroup/
/sys/fs/cgroup/
|-- blkio
|-- cpu -> cpu,cpuacct
|-- cpuacct -> cpu,cpuacct
|-- cpu,cpuacct
|-- cpuset
|-- devices
|-- freezer
|-- hugetlb
|-- memory
|-- net_cls -> net_cls,net_prio
|-- net_cls,net_prio
|-- net_prio -> net_cls,net_prio
|-- perf_event
|-- pids
|-- rdma
`-- systemd
16 directories, 0 files
v2
$ tree -L 1 /sys/fs/cgroup/
/sys/fs/cgroup/
|-- cgroup.controllers
|-- cgroup.max.depth
|-- cgroup.max.descendants
|-- cgroup.procs
|-- cgroup.stat
|-- cgroup.subtree_control
|-- cgroup.threads
|-- cpu.pressure
|-- cpuset.cpus.effective
|-- cpuset.mems.effective
|-- cpu.stat
|-- init.scope
|-- io.pressure
|-- io.stat
|-- memory.numa_stat
|-- memory.pressure
|-- memory.stat
|-- system.slice
`-- user.slice
3 directories, 16 files
v1 的 cgroup 为每个控制器都使用独立的树(目录), 每个目录就代表了一个 cgroup subsystem,各个 Subsystem 各自为政,看起来比混乱,难以管理
2.3 系统开启 Cgroup v2
/etc/default/grub 添加
systemd.unified_cgroup_hierarchy=1
参数
GRUB_CMDLINE_LINUX="... systemd.unified_cgroup_hierarchy=1"
更新 grub 并重启
$ grub2-mkconfig -o /boot/grub2/grub.cfg
$ reboot
检查
$ stat -fc %T /sys/fs/cgroup/
如果输出是 cgroup2fs,则表示使用的是cgroup v2。
如果输出是 tmpfs,则表示使用的是cgroup v1。
2.4 Docker 配置
$ docker info | grep Cgroup
Cgroup Driver: systemd
Cgroup Version: 2
如果要修改容器的容器默认的 cgroup 父路径(默认是 "/system.slice"),可以添加如下配置:
/etc/docker/daemon.json
{
"cgroup-parent": "/docker.slice"
}
2.5 测试
2.5.1 创建容器
docker run -d -v /mnt/container/docker_bind/ceshi:/home --device-write-bps /dev/vdb:1M --name test registry.baidubce.com/scs_test_cce/mysql:v1.0
2.5.2 dd 测试
进入到容器中 /home 目录
# Direct I/O
dd if=/dev/zero of=test.out bs=1M count=1024 oflag=direct
# Buffered I/O
dd if=/dev/zero of=test.out bs=1M count=1024
2.5.3 查看磁盘 io
iostat -kx 1
2.5.4 磁盘 io 限制
$ cat /sys/fs/cgroup/system.slice/docker-a576b0762a93d006841a4a7e20eb7ef7886c1810b2fdd2352a5ba1da96450a65.scope/io.max
253:16 rbps=max wbps=1048576 riops=max wiops=max
2.6 Docker API 限制磁盘 IO
Cgroup v1 无法限制 Page Cache 刷盘速度
Cgroup v2 通过 Buffered I/O 写入文件时,会秒级完成写入,但是从 Page Cache 往磁盘写入时会限速
创建容器时的 API 参数
BlkioDeviceReadBps
BlkioDeviceWriteBps
BlkioDeviceReadIOps
BlkioDeviceWriteIOps
在 Docker API 中,BlkioDeviceReadBps
是 HostConfig
的一个字段,格式为:
{
"BlkioDeviceReadBps": [
{
"Path": "/dev/sda",
"Rate": 1048576 # 1MB = 1024*1024=1048576 字节/秒
}
]
}
示例
curl -X POST \
-H "Content-Type: application/json" \
--unix-socket /var/run/docker.sock \
"http://v1.41/containers/create?name=my_container" \
-d '{
"Image": "nginx",
"HostConfig": {
"BlkioDeviceReadBps": [
{
"Path": "/dev/sda",
"Rate": 1048576
}
]
}
}'
获取磁盘设备
[[ -d "/mnt/container" ]] && df -h "/mnt/container" | grep dev | awk '{print $1}'
/dev/vdb
2.7 示例
综合限制磁盘 IOPS 和 IO BPS
docker run -it \
--device-read-iops /dev/sda:100 \
--device-write-iops /dev/sda:50 \
--device-read-bps /dev/sda:1MB \
--device-write-bps /dev/sda:512KB \
centos /bin/bash
读 IOPS ≤ 100 次/秒,读带宽 ≤ 1MB/s。
写 IOPS ≤ 50 次/秒,写带宽 ≤ 512KB/s。
Last updated