2. CPU限制实战:使用--cpus参数限制容器CPU使用
CPU资源限制,是容器化部署中最基础也最关键的环节。我见过太多线上事故,都是因为某个容器把宿主机的CPU吃满,导致其他服务集体瘫痪。今天我们就来聊聊--cpus这个参数,怎么用、怎么测、怎么避坑。
2.1 为什么需要限制容器CPU?
你想想看,一台宿主机上跑十几个容器,如果每个容器都"野蛮生长",CPU资源抢着用,会发生什么?
- 某个高负载容器把CPU占满,其他容器直接"饿死"
- 业务高峰期,所有容器一起抢CPU,响应时间飙升
- 宿主机负载过高,连SSH都连不上去
说白了,不限制CPU的容器,就像没有刹车的跑车。我在项目中遇到过好几次,开发环境里跑个压测脚本,结果把整个测试集群搞崩了。从那以后,我要求所有容器必须显式声明CPU限制。
2.2 --cpus参数详解
--cpus是Docker 1.13版本引入的参数,用来限制容器能使用的CPU核心数。它支持小数,比如--cpus=1.5表示容器最多使用1.5个CPU核心。
核心概念:--cpus 限制的是CPU时间片,不是物理核心数。1个CPU = 1000毫核(millicores)。
举个例子:
# 限制容器最多使用1个CPU核心
docker run --cpus=1 -d nginx
# 限制容器最多使用0.5个CPU核心
docker run --cpus=0.5 -d nginx
# 限制容器最多使用2.5个CPU核心
docker run --cpus=2.5 -d nginx
2.3 实战:用stress工具验证CPU限制
光说不练假把式。我们来做个实验,看看--cpus到底有没有用。
首先,拉一个stress镜像:
docker pull polinux/stress
实验一:不限制CPU
docker run --rm -it polinux/stress --cpu 4 --timeout 30s
这个命令会启动4个CPU工作线程,每个线程疯狂计算。用docker stats看看:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT
a1b2c3d4e5f6 stress 398.5% 12.3MiB / 1.944GiB
看到没?CPU使用率接近400%,相当于吃满了4个核心。如果宿主机只有4核,其他容器基本没法用了。
实验二:限制为1个CPU
docker run --rm -it --cpus=1 polinux/stress --cpu 4 --timeout 30s
再看docker stats:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT
b2c3d4e5f6a7 stress 99.8% 12.5MiB / 1.944GiB
嗯,CPU使用率被稳稳地限制在100%左右。虽然容器内部启动了4个线程,但Docker通过CFS调度器,只给它分配了1个CPU的时间片。
我的经验:生产环境中,我习惯给每个容器预留20%的CPU余量。比如业务需要2个CPU,我就设--cpus=2.5。这样突发流量来了,容器还能扛一扛。
2.4 多容器场景下的CPU分配
假设你有一台4核的宿主机,要部署三个服务:
| 服务 | 建议CPU限制 | 说明 |
|---|---|---|
| Web服务 | 2.0 | 核心业务,需要稳定性能 |
| 数据处理 | 1.0 | 后台任务,可以慢一点 |
| 日志收集 | 0.5 | 非关键任务,别抢资源 |
这样分配,总限制是3.5个CPU,留了0.5个CPU给系统和其他进程。我曾经见过有人把三个容器都设成--cpus=2,结果总限制6个CPU,远超宿主机4核。你以为能超卖?实际上容器之间疯狂争抢,性能反而更差。
注意:--cpus的总和不要超过宿主机核心数。超卖会导致CPU资源竞争,所有容器性能都受影响。我曾经吃过这个亏,三个容器各设2个CPU,4核机器直接被打到100%负载,SSH都卡。
2.5 动态调整CPU限制
有时候容器已经跑起来了,才发现CPU限制设得太紧或太松。别慌,Docker支持动态调整:
# 查看当前限制
docker inspect <容器ID> | grep -i cpu
# 动态调整CPU限制(从1.0改为2.0)
docker update --cpus=2.0 <容器ID>
# 验证是否生效
docker stats <容器ID>
这个功能在线上排障时特别有用。我记得有一次,某个服务突然流量暴涨,我直接在线上把CPU限制从2.0调到4.0,服务立刻恢复正常。等流量降下来,再调回去就行。
2.6 与旧版CPU限制参数的对比
在--cpus出现之前,Docker用的是--cpu-quota和--cpu-period这两个参数。它们的关系是:
--cpus = --cpu-quota / --cpu-period
默认的--cpu-period是100000微秒(100ms)。如果你设--cpus=1.5,相当于:
--cpu-quota=150000 --cpu-period=100000
我个人建议直接用--cpus,简单直观。除非你有非常精细的调度需求,才去碰--cpu-quota和--cpu-period。
2.7 避坑指南
最后,分享几个我踩过的坑:
- 不要设成0:
--cpus=0不会限制CPU,等于没设。我曾经手滑输错过,排查了半天。 - 注意小数精度:
--cpus=0.1是100毫核,但有些旧版Docker不支持这么小的值。建议最小设到0.5。 - 配合--cpuset-cpus使用:如果想让容器绑定到特定CPU核心,可以用
--cpuset-cpus=0,1。但要注意,绑核后--cpus的限制依然有效。 - 监控不能少:设了限制不代表万事大吉。我习惯用
docker stats配合Prometheus,实时监控每个容器的CPU使用情况。
一句话总结:--cpus是容器CPU限制的"黄金参数",简单、直观、有效。生产环境务必给每个容器设置合理的CPU上限,这是保障集群稳定的第一步。
下一章,我们会聊--cpu-shares这个相对权重参数。它和--cpus有什么区别?什么时候该用哪个?到时候我们细说。