CPU配额

Docker使用cgroup来管理容器使用的CPU、内存、磁盘资源限额。

权重方式

--cpu-shares ​或者-c​参数可以为容器设置指定的权重值。容器默认的权重值为1024。当多个容器竞争 CPU 资源时,权重越高的容器将获得更多的 CPU 调度时间。

例如容器A的权重值为1024,容器B的权重值为512,则容器A与容器B在CPU资源竞争时,容器A所获得的CPU调度时间是容器B的两倍。

cgroup只有多个容器同一时间在竞争同一个CPU资源时,CPU配额才会生效。

启动一个容器,然后将其cpu配额设置为512。

docker run -it --cpu-shares 512 busybox /bin/sh

在容器内部使用cat /sys/fs/cgroup/cpu/cpu.shares​查看CPU配额

image

核心控制

使用--cpuset 使容器绑定到特定的CPU内核和内存节点上运行

--cpuset-cpus

--cpuset-mems

当两个容器使用--cpuset分别绑到了不同CPU上,例如容器A绑到cpu1、容器B绑到cpu2上,由于容器A和容器B不会争夺同一个CPU资源,所以设置的CPU配额并不会生效,只有两个容器绑到同一个CPU时,CPU配额才会生效。

压测

创建两个容器,分别为容器container​A和容器container​B,两个容器都绑定cpu0和cpu1,其中容器A的CPU权重为1024、容器B的CPU权重为512。

前提是服务器或者本地虚拟机cpu核心数要多于一个(建议2核以上,因为后面压测两个cpu时,如果你只有2核,那就会卡死😂),可以使用lscpu查看当前服务器的cpu核数

CPU(s):                   4
  On-line CPU(s) list:    0-3

也可以使用top命令,然后按1️⃣键显示CPU信息

image

docker run -itd --name containerA --cpu-shares 1024 --cpuset-cpus 0,1 alpine /bin/sh
docker run -itd --name containerB --cpu-shares 512 --cpuset-cpus 0,1 alpine /bin/sh

先进入containerB容器安装stress-ng(alpine中没有stress,所以用stress-ng)压测工具,容器A也重复这步。

docker exec -it containerB /bin/sh
apk update
apk add stress-ng

分别在两个容器中运行stress-ng进行压测。

stress-ng --cpu 2 --timeout 30000s

image

我们可以看到CPU0和CPU1跑满了,但是其他CPU没有受到影响。

在进程中出现了4条关于stress-ng的进程,我们可以使用cat /proc/PID(替换为具体的PID)/cgroup​命令查看进程所属容器,例如

cid=$(cat /proc/PID(替换为具体的PID)/cgroup | grep 'docker' | awk -F/ '{print $3}')
docker ps --no-trunc --format '{{.ID}} {{.Names}}' | grep "$cid"

可以使用一个脚本实现输出,创建一个pid2name.sh文件,内容如下

#!/bin/bash

# 获取 stress-ng-cpu 进程列表
ps -eo pid,comm,%cpu --no-headers | awk '$2=="stress-ng-cpu"{print $1, $3}' | while read pid cpu; do
  # 提取容器 ID(Docker cgroup)
  cid=$(awk -F/ '/docker/{print $3}' /proc/$pid/cgroup 2>/dev/null)

  # 如果找到了容器 ID
  if [ -n "$cid" ]; then
    # 获取容器名
    cname=$(docker ps -a --no-trunc --format '{{.ID}} {{.Names}}' | grep "$cid" | awk '{print $2}')
  else
    cname="host"  # 非容器进程
  fi

  echo "PID: $pid | CPU: $cpu% | Container: $cname"
done

输出结果如下

PID: 438781 | CPU: 65.2% | Container: containerA
PID: 438782 | CPU: 65.5% | Container: containerA
PID: 438138 | CPU: 32.4% | Container: containerB
PID: 438139 | CPU: 32.4% | Container: containerB

可以看到containerA容器的CPU使用率始终为containerB的两倍

内存控制

docker可以使用--memory或者-m参数实现容器内存使用量的控制

例如:

docker run -itd --name containerA -m 512m alpine /bin/sh

containerA容器只能使用512M的内存。

IO控制

--device-write-bps {设备名:值}​ 限制容器的写速度。

--device-read-bps {设备名:值}​限制容器的读速度。单位可以是kb、mb、gb