Docker-05 资源管理与 docker update:在线调整 CPU、内存与进程限制
本篇较长,按需跳转: docker update 概述 · 不是更新镜像 · CPU · 内存 · PIDs · 在线更新原理 · Compose 漂移 · cgroup v2 · 容器内视图 · docker stats · 排障清单
1. docker update:动态修改已有容器的运行配置
docker update 用于修改一个或多个已经创建的容器的部分运行配置。最常见的用途有两类:
- 在线调整 CPU、内存、进程数和块 I/O 等资源约束。
- 修改容器的 restart policy。
基本语法:
docker update [OPTIONS] CONTAINER [CONTAINER...]
docker container update [OPTIONS] CONTAINER [CONTAINER...]
docker update 和 docker container update 是同一组命令。它既能更新运行中的容器,也能更新已停止的容器:运行中的资源约束通常立即生效;已停止容器会在下次启动时采用新配置。
先用当前客户端确认本机版本支持的参数:
docker update --help
docker version
docker info
不同 Engine、操作系统、cgroup 版本和内核启用的 controller 不同,可用选项和实际效果也可能不同。下面重点讨论 Linux 上最常见的能力。
2. 它不是"更新镜像"
docker update 名称很容易让人误以为它会拉取新镜像或更新容器内应用。实际上它不会修改:
- 镜像和镜像 tag/digest。
ENTRYPOINT、CMD、工作目录和运行用户。- 环境变量、secret 和配置文件来源。
- 端口发布、network mode 和容器 hostname。
- bind mount、volume 和 tmpfs 挂载定义。
- logging driver、healthcheck 和大多数安全配置。
下面这类变更需要根据新配置重建容器:
docker pull example/api:1.1.0
docker rm -f api
docker run -d --name api ... example/api:1.1.0
实际项目应使用 Compose 或编排平台声明完整配置,让平台替换容器,而不是手工拼接旧参数:
docker compose pull api
docker compose up -d --no-deps api
因此要区分三个动作:
| 命令 | 修改对象 | 是否替换容器 | 是否更新应用镜像 |
|---|---|---|---|
docker update |
已有容器的部分 HostConfig | 否 | 否 |
docker restart |
已有容器的运行状态 | 否 | 否 |
docker compose up |
按声明配置协调服务 | 配置/镜像变化时通常会 | 可以 |
3. 查看更新前的基线
不要在没有基线的情况下直接修改生产容器。先保存容器配置和运行状态:
docker inspect api > api.inspect.before.json
docker inspect api | jq '.[0] | {
status: .State.Status,
pid: .State.Pid,
memory: .HostConfig.Memory,
memory_reservation: .HostConfig.MemoryReservation,
memory_swap: .HostConfig.MemorySwap,
nano_cpus: .HostConfig.NanoCpus,
cpu_shares: .HostConfig.CpuShares,
cpuset_cpus: .HostConfig.CpusetCpus,
pids_limit: .HostConfig.PidsLimit,
restart: .HostConfig.RestartPolicy
}'
还要记录应用指标。资源配置更新成功,只说明 daemon 接受了新配置,不代表业务延迟、吞吐量和错误率符合预期。
4. 动态调整 CPU
4.1 --cpus:设置 CPU 带宽上限
docker update --cpus 1.5 api
--cpus 1.5 表示容器在一个调度周期内最多获得约 1.5 个 CPU 的运行时间。它通常映射为 cgroup 的 quota/period,不代表绑定到某一个半物理核心,也不保证容器一定能获得这些 CPU。
在常见配置中,--cpus 1.5 大致相当于:
docker update --cpu-period 100000 --cpu-quota 150000 api
一般优先用更容易理解的 --cpus;只有需要直接控制调度周期和配额时才使用 --cpu-period、--cpu-quota。
验证 HostConfig 和 cgroup v2:
docker inspect api --format \
'NanoCpus={{.HostConfig.NanoCpus}} Period={{.HostConfig.CpuPeriod}} Quota={{.HostConfig.CpuQuota}}'
docker exec api cat /sys/fs/cgroup/cpu.max
docker exec api cat /sys/fs/cgroup/cpu.stat
cpu.stat 中持续增长的 throttling 指标说明进程经常用完配额。提高限额前要同时检查应用 CPU profile,避免用加资源掩盖忙循环、锁竞争或无效重试。
4.2 --cpu-shares:设置竞争时的相对权重
docker update --cpu-shares 512 api
--cpu-shares 是相对权重,不是硬上限:宿主 CPU 空闲时,容器仍可使用更多 CPU;多个 cgroup 竞争时,调度器才按权重分配。它不能代替 --cpus。
4.3 --cpuset-cpus:限制可运行的 CPU 集合
docker update --cpuset-cpus '0-3' api
docker inspect api --format '{{.HostConfig.CpusetCpus}}'
这会限制容器进程在哪些逻辑 CPU 上运行,适合 NUMA、缓存局部性或噪声隔离场景。更新前要确认目标 CPU 在线且属于父 cgroup 允许的集合;不要把所有关键服务都绑到相同核心。
在 NUMA 主机上还可能使用 --cpuset-mems 限制内存节点,但错误的 CPU/内存节点组合会导致远端内存访问或更新失败,需要结合 lscpu、numactl --hardware 和父 cgroup 配置验证。
5. 动态调整内存
5.1 --memory:硬上限
docker update --memory 768m api
--memory 设置容器内存硬上限。减小上限时要特别谨慎:如果当前使用量高于新上限,内核会回收内存,仍无法满足时可能触发 cgroup OOM,杀死容器进程。
更新前后观察:
docker stats --no-stream api
docker exec api sh -c '
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.events
'
docker inspect api --format \
'Memory={{.HostConfig.Memory}} Swap={{.HostConfig.MemorySwap}} Reservation={{.HostConfig.MemoryReservation}}'
运行时语言的 heap 只是容器内存的一部分。Go/C/Java 服务还会使用线程栈、mmap、共享库、socket buffer、page cache 和其他堆外内存;limit 必须保留余量。
5.2 --memory-reservation:软约束
docker update --memory-reservation 512m --memory 768m api
reservation 用于表达内存压力下的软目标,必须低于硬上限才有意义。它不是预留 512 MB 物理内存,也不能保证进程永远获得这部分容量。
5.3 --memory-swap:内存加 swap 总量
docker update --memory 768m --memory-swap 1g api
当 --memory 与 --memory-swap 同时设置时,后者通常表示内存 + swap 的总上限,所以上例最多可使用约 768 MB 内存和额外 256 MB swap。--memory-swap 与 --memory 的关系、-1 语义以及宿主是否启用 swap 会影响结果。
已有容器设置过 MemorySwap 时,调整 memory 可能需要在同一命令中提供兼容的 swap 总量,否则 daemon 会拒绝不合法组合。生产变更前先 inspect 当前两个值,并在相同 Engine/cgroup 版本的测试机验证。
swap 能缓解瞬时压力,但可能把内存故障变成长尾延迟。数据库和延迟敏感服务不能只靠扩大 swap 解决泄漏或错误容量规划。
6. 限制进程和线程数量
docker update --pids-limit 512 api
docker inspect api --format '{{.HostConfig.PidsLimit}}'
docker exec api sh -c '
cat /sys/fs/cgroup/pids.current
cat /sys/fs/cgroup/pids.max
'
PIDs controller 统计的是内核 task,通常包括进程和线程。限制过低时,应用可能出现:
fork: Resource temporarily unavailable。- 无法创建新线程。
- Go runtime、JVM、Nginx worker 或调试命令启动失败。
- 健康检查命令因不能 fork 而失败。
设置上限前要观察峰值线程/进程数并留余量。不同版本对 0、-1 或未设置的表示可能不同,以 docker update --help、inspect 和 pids.max 实际值为准。
7. 块 I/O 权重
docker update --blkio-weight 500 api
docker inspect api --format '{{.HostConfig.BlkioWeight}}'
块 I/O 权重通常在多个容器竞争同一块设备时才体现相对优先级。它的效果受存储驱动、I/O scheduler、cgroup 版本、direct/buffered I/O、设备映射和云盘后端影响,不能看到参数成功就断言磁盘吞吐会按比例变化。
数据库 I/O 治理需要结合 iostat、cgroup io.stat、应用 fsync 延迟和真实压测。对具体设备的吞吐/IOPS 限制也受 Engine 与平台支持,应先查看本机 docker update --help。
8. 修改 restart policy
docker update --restart unless-stopped api
docker update --restart on-failure:5 worker
docker update --restart no migration
这只修改后续退出时的处理策略,不会立即重启容器,也不会改变当前 PID。四种策略、手动停止、daemon 重启、OOM 和 healthcheck 的完整行为见第 04 篇。
注意 shell 中的 no 直接写通常没有问题;在 Compose YAML 中建议写成字符串 restart: "no",避免被某些 YAML 解析器当作布尔值。
9. 一次更新多个容器
docker update --cpus 1 --memory 512m api-1 api-2 api-3
多个容器可以放在一个命令中,但不要把它理解成数据库事务:如果某个容器不存在、某个约束不合法或内核不支持,可能出现部分目标已经更新、部分目标失败。批量更新后逐个核验:
for name in api-1 api-2 api-3; do
docker inspect "$name" --format \
'{{.Name}} memory={{.HostConfig.Memory}} nano_cpus={{.HostConfig.NanoCpus}} restart={{.HostConfig.RestartPolicy.Name}}'
done
关键服务应逐批修改、观察错误率/延迟/OOM/throttling,再继续下一批;这不是跨节点滚动发布机制。
10. 在线更新为什么通常不重启进程
对运行中的 Linux 容器,资源更新大致沿下面的路径发生:
docker CLI
↓ Engine API
dockerd / containerd
↓ 更新容器运行配置
cgroup controller 文件
├── cpu.max / cpu.weight
├── memory.max / memory.low 等映射
└── pids.max / io.*
内核调度器和内存控制器随即使用新值,容器的 namespace、rootfs 和 PID 1 通常不变。验证 PID:
before=$(docker inspect -f '{{.State.Pid}}' api)
docker update --cpus 1.25 api
after=$(docker inspect -f '{{.State.Pid}}' api)
printf 'before=%s after=%s\n' "$before" "$after"
“不重启"不等于"无影响”:收紧 CPU 会立即产生 throttling,收紧内存可能触发回收/OOM,收紧 PIDs 可能让新线程失败。在线变更也需要变更窗口、指标、回滚值和审计记录。
11. 已停止容器也能更新
docker stop api
docker update --memory 1g --cpus 2 --restart unless-stopped api
docker inspect api --format \
'status={{.State.Status}} memory={{.HostConfig.Memory}} nano_cpus={{.HostConfig.NanoCpus}}'
docker start api
更新已停止容器不会自动启动它。这样可以在启动前修正过低资源限制或 restart policy;但不能借此修改环境变量、端口和挂载,这些仍需要重建。
12. 回滚 docker update
docker update 没有通用的 undo 子命令。回滚依赖更新前保存的具体值:
# 示例:按变更前记录恢复,不要照抄示例值
docker update \
--cpus 2 \
--memory 1g \
--memory-reservation 768m \
--memory-swap 1536m \
--pids-limit 1024 \
--restart unless-stopped \
api
某些"取消限制"的值因选项、cgroup 和 Engine 版本而异,不能假设全部写 0 就表示无限。先查 docker update --help,并用一个临时容器验证再改生产。
回滚后同时验证 HostConfig、cgroup 和应用指标;仅比较 docker inspect JSON 仍不能证明性能已恢复。
13. Compose 管理下的配置漂移
如果容器由 Compose 创建,手工执行:
docker update --memory 1g demo-api-1
只改变当前容器,compose.yaml 并没有变化。这会造成两份事实:
声明状态:compose.yaml 中的资源配置
实际状态:当前容器 HostConfig / cgroup
手工值可能持续到容器被重建;一旦 Compose 因镜像或配置变化重建容器,手工修改会丢失。正确流程是:
- 紧急止损时可先
docker update,记录原值、命令、操作者和时间。 - 立即把最终值回写到 Compose/部署配置并走代码审查。
- 用
docker compose config查看最终声明。 - 在维护窗口
docker compose up -d;必要时--force-recreate消除漂移。 - inspect 新容器并验证业务指标。
Compose 示例:
services:
api:
image: example/api:1.0.0
cpus: 1.5
mem_limit: 768m
mem_reservation: 512m
pids_limit: 512
restart: unless-stopped
Compose 字段的支持和映射受版本/部署目标影响,以 docker compose config 和生成容器的 HostConfig 为准。
14. cgroup v2 对资源限制的影响
Docker 的资源限制最终映射到 Linux cgroup。现代发行版(Ubuntu 22.04+、RHEL 9+、Debian 12+)默认使用 cgroup v2,而早期系统使用 v1。两者的核心区别影响你对资源限制的理解和排障方式。
14.1 v1 和 v2 的区别
| 维度 | cgroup v1 | cgroup v2 |
|---|---|---|
| 层级结构 | 每个 controller(cpu、memory、pids)独立层级 | 所有 controller 统一层级 |
| 文件命名 | memory.limit_in_bytes、cpu.cfs_quota_us |
memory.max、cpu.max |
| 内存压力信号 | memory.soft_limit_in_bytes(效果有限) |
memory.high(内核主动回收) |
| PSI 压力指标 | 不支持 | /proc/pressure/{cpu,memory,io} |
| 线程级控制 | 部分支持 | threaded 类型 cgroup |
判断当前系统版本:
stat -fc %T /sys/fs/cgroup
# tmpfs → cgroup v1(或 hybrid)
# cgroup2fs → cgroup v2
# Docker 也会显示
docker info --format '{{.CgroupVersion}}'
14.2 v2 的关键控制文件
容器内可以直接查看 cgroup v2 控制文件:
docker exec api sh -c '
echo "=== 内存 ==="
echo "memory.max=$(cat /sys/fs/cgroup/memory.max)"
echo "memory.current=$(cat /sys/fs/cgroup/memory.current)"
echo "memory.high=$(cat /sys/fs/cgroup/memory.high)"
echo ""
echo "=== CPU ==="
cat /sys/fs/cgroup/cpu.max
echo ""
echo "=== PIDs ==="
echo "pids.max=$(cat /sys/fs/cgroup/pids.max)"
echo "pids.current=$(cat /sys/fs/cgroup/pids.current)"
'
关键文件含义:
| 文件 | 含义 | Docker 参数 |
|---|---|---|
memory.max |
硬上限,超出触发 OOM | --memory |
memory.high |
高水位线,超出后内核加大回收压力 | 无直接 CLI 参数 |
memory.current |
当前使用量(含 page cache) | docker stats MEM USAGE |
cpu.max |
quota period 格式,如 150000 100000 表示 1.5 CPU |
--cpus |
pids.max |
进程/线程数上限 | --pids-limit |
14.3 memory.high 的实际意义
memory.high 是 cgroup v2 引入的重要机制。它不是硬上限,而是"高水位线":
- 使用量超过
memory.high时,内核会对该 cgroup 施加更强的内存回收压力。 - 进程不会被杀死,但可能因为频繁回收而出现延迟抖动。
- 只有使用量超过
memory.max时,才触发 cgroup OOM kill。
很多生产中的"容器变慢但没有 OOM"问题,其实是 memory.high 触发了持续回收。Docker CLI 目前没有直接设置 memory.high 的参数,但编排平台或手工写 cgroup 文件可以使用它。
14.4 memory.events:内存事件统计
docker exec api cat /sys/fs/cgroup/memory.events
输出示例:
low 0
high 42
max 3
oom 1
oom_kill 1
oom_group_kill 0
| 字段 | 含义 |
|---|---|
low |
使用量降到 memory.low 以下的次数 |
high |
使用量超过 memory.high 的次数(频繁说明回收压力大) |
max |
使用量触及 memory.max 的次数 |
oom |
OOM 事件次数 |
oom_kill |
因 OOM 被杀死的进程次数 |
排障时 high 计数持续增长但 oom_kill 为 0,说明容器处于"没死但在挣扎"的状态,应考虑增大内存或优化应用。
14.5 cpu.stat:CPU 限流统计
docker exec api cat /sys/fs/cgroup/cpu.stat
输出示例:
usage_usec 1523456
user_usec 1234567
system_usec 288889
nr_periods 15234
nr_throttled 423
throttled_usec 8765432
| 字段 | 含义 |
|---|---|
nr_periods |
经过的调度周期总数 |
nr_throttled |
被限流的周期数 |
throttled_usec |
累计被限流的微秒数 |
限流比例 = nr_throttled / nr_periods。超过 10-20% 通常说明 CPU 配额不足或应用存在 CPU 密集型热点。
15. 容器内的 CPU 和内存视图:为什么 nproc 和 free 不准确
15.1 问题现象
在一个限制了 2 CPU 和 512 MB 内存的容器内:
docker run --rm --cpus 2 --memory 512m ubuntu bash -c '
echo "nproc: $(nproc)"
echo "free:"
free -m
'
你会发现 nproc 返回的是宿主机全部 CPU 核数(比如 16),free 返回的是宿主机全部内存(比如 64 GB)。这不是 Bug,而是设计如此。
15.2 原因
nproc、free、top、htop 等工具读取的是 /proc/cpuinfo 和 /proc/meminfo。Linux 的 /proc 文件系统反映的是宿主机内核视图,不会自动根据 cgroup 限制调整数据。cgroup 是资源限制机制,而 /proc 是内核信息接口,两者不联动。
验证:
docker run --rm --cpus 2 --memory 512m alpine sh -c '
echo "--- /proc 视图(宿主机数据)---"
echo "nproc: $(nproc)"
grep MemTotal /proc/meminfo
echo ""
echo "--- cgroup 视图(真实限制)---"
echo "cpu.max: $(cat /sys/fs/cgroup/cpu.max)"
echo "memory.max: $(cat /sys/fs/cgroup/memory.max)"
'
15.3 影响:运行时的错误资源计算
这个问题最常见的后果是应用运行时按宿主机资源初始化,实际被 cgroup 限制后性能异常或 OOM:
Java(8u191 之前):JVM 默认按 /proc/meminfo 计算最大 heap。一台 64 GB 宿主机上的 512 MB 容器,JVM 可能尝试分配 16 GB heap,随即被 cgroup OOM kill。
# Java 8u191+ / 11+ 默认开启容器感知
java -XX:+PrintFlagsFinal 2>&1 | grep UseContainerSupport
# 建议显式设置
java -XX:MaxRAMPercentage=75.0 -jar app.jar
Go:runtime.NumCPU() 返回宿主机核数,GOMAXPROCS 默认等于该值。16 核宿主上限制 2 CPU 的容器,Go 会启动 16 个 OS 线程竞争 2 CPU 配额,产生不必要的上下文切换和 throttling。
// 使用 uber-go/automaxprocs 自动适配 cgroup
import _ "go.uber.org/automaxprocs"
或者手动设置环境变量:
docker run --cpus 2 -e GOMAXPROCS=2 example/api:1.0.0
Node.js:os.cpus().length 同样返回宿主机核数。cluster 模式按此 fork worker,会在有限 CPU 配额上创建过多进程。
15.4 解决方案
| 方案 | 适用场景 | 说明 |
|---|---|---|
| 运行时容器感知 | Java 8u191+、Go automaxprocs | 运行时直接读取 cgroup 限制 |
| 环境变量 | GOMAXPROCS、UV_THREADPOOL_SIZE |
在 Compose 或 docker run 中显式设置 |
| 手动读 cgroup | 通用 | cat /sys/fs/cgroup/cpu.max 解析 quota/period |
| LXCFS | 需要 /proc 兼容的遗留应用 |
挂载模拟的 /proc/cpuinfo、/proc/meminfo |
LXCFS 通过 FUSE 文件系统重写 /proc 中的资源信息,让遗留应用无需修改即可看到"正确"的数值。但它增加了运维复杂度,现代应用优先使用运行时原生的容器感知能力。
16. docker stats 深入:每列含义与 cgroup 指标的关系
16.1 基本用法
docker stats # 持续刷新
docker stats --no-stream # 只打印一帧
docker stats --no-stream api db redis
docker stats --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.PIDs}}'
16.2 各列含义
| 列 | 含义 | 注意事项 |
|---|---|---|
| CPU % | 相对于宿主机全部 CPU 的百分比 | 4 核宿主上 --cpus 2 的容器满载时显示约 200%,不是 100% |
| MEM USAGE / LIMIT | 容器当前内存使用 / cgroup memory.max |
USAGE 包含 page cache |
| MEM % | USAGE / LIMIT 的百分比 |
未设 limit 时显示相对于宿主总内存 |
| NET I/O | 容器网络接口的累计收发字节 | 从容器启动开始累计,不是速率 |
| BLOCK I/O | 块设备累计读写字节 | 受存储驱动和 direct/buffered I/O 影响 |
| PIDS | 当前进程/线程数 | 对应 cgroup pids.current |
16.3 MEM USAGE 包含 page cache
docker stats 显示的内存使用量来自 cgroup memory.current,它包含了 page cache(文件系统缓存)。这意味着:
- 一个读取大量文件的容器,MEM USAGE 可能远高于应用实际 RSS。
- 内存压力下 page cache 会被回收,不一定意味着应用内存不足。
要区分实际 RSS 和 cache:
docker exec api cat /sys/fs/cgroup/memory.stat | grep -E '^(anon|file|shmem) '
其中 anon 大致对应应用实际使用的匿名内存(heap、stack、mmap 匿名页),file 是文件映射和 page cache。
16.4 与 cgroup 指标对照
docker exec api sh -c '
echo "=== 内存 ==="
echo "memory.current=$(cat /sys/fs/cgroup/memory.current)"
echo "memory.max=$(cat /sys/fs/cgroup/memory.max)"
echo ""
echo "=== CPU ==="
cat /sys/fs/cgroup/cpu.stat
echo ""
echo "=== PIDs ==="
echo "pids.current=$(cat /sys/fs/cgroup/pids.current)"
echo "pids.max=$(cat /sys/fs/cgroup/pids.max)"
'
docker stats 是快照工具,适合临时查看。生产环境应使用 Prometheus + cAdvisor、Datadog 或类似的时序监控方案,才能看到资源使用的趋势、峰值和关联告警。
16.5 CPU % 的计算和误解
docker stats 的 CPU % 是相对于宿主机全部 CPU 核数的百分比。在一台 8 核宿主上:
- 容器
--cpus 2,满载时 CPU % 约 200%(不是 100%)。 - 要计算"相对于限制的使用率",需要自己换算:
200% / (2 * 100%) = 100%。
或者直接用 cgroup 数据:
docker exec api cat /sys/fs/cgroup/cpu.stat
# nr_throttled > 0 且持续增长 → 说明在碰 CPU 天花板
17. 可复现实验
启动一个有初始限制的容器:
docker run -d --name update-lab \
--cpus 0.5 \
--memory 256m \
--pids-limit 128 \
--restart no \
alpine:3.20 sleep 1d
记录 PID 和限制:
docker inspect update-lab | jq '.[0] | {
pid: .State.Pid,
memory: .HostConfig.Memory,
nano_cpus: .HostConfig.NanoCpus,
pids: .HostConfig.PidsLimit,
restart: .HostConfig.RestartPolicy
}'
docker exec update-lab sh -c '
echo memory.max=$(cat /sys/fs/cgroup/memory.max)
echo cpu.max=$(cat /sys/fs/cgroup/cpu.max)
echo pids.max=$(cat /sys/fs/cgroup/pids.max)
'
在线更新:
pid_before=$(docker inspect -f '{{.State.Pid}}' update-lab)
docker update \
--cpus 1.25 \
--memory 384m \
--pids-limit 256 \
--restart on-failure:3 \
update-lab
pid_after=$(docker inspect -f '{{.State.Pid}}' update-lab)
printf 'pid_before=%s pid_after=%s\n' "$pid_before" "$pid_after"
docker exec update-lab sh -c '
echo memory.max=$(cat /sys/fs/cgroup/memory.max)
echo cpu.max=$(cat /sys/fs/cgroup/cpu.max)
echo pids.max=$(cat /sys/fs/cgroup/pids.max)
'
docker inspect update-lab --format '{{json .HostConfig.RestartPolicy}}'
预期 PID 不变,cgroup 文件和 restart policy 变成新值。实验结束:
docker rm -f update-lab
不要在远程生产 context 上做资源压力实验;执行前先运行 docker context show。
18. docker update 排障清单
命令被拒绝
├── 参数是否受当前 OS/Engine 支持? docker update --help
├── 宿主是否启用对应 cgroup controller? docker info + /sys/fs/cgroup
├── memory、reservation、swap 是否冲突? inspect 当前值
├── cpuset 是否属于允许且在线的 CPU? lscpu + cgroup cpuset
└── 是否连到了错误 Docker context? docker context show
命令成功但业务异常
├── 是否收紧 CPU 导致 throttling? cpu.stat + 应用延迟
├── 是否收紧内存触发回收/OOM? memory.events + dmesg
├── PIDs 是否导致线程/fork 失败? pids.current/max + 日志
├── I/O 权重是否被存储后端支持? io.stat + iostat
└── 是否产生 Compose 配置漂移? compose config + inspect
19. 本篇小结
docker update 是单机容器资源管理的核心工具:它通过修改 cgroup 控制文件实现 CPU、内存、PIDs 和 I/O 的在线调整,不重启进程、不重建容器。但它不能修改镜像、端口、挂载和环境变量,也不是跨节点的编排能力。
使用资源限制时要记住三件事:cgroup 限制的是内核视角的资源消耗(包含 page cache),/proc 中的信息不反映 cgroup 限制,而 docker stats 的百分比是相对于宿主机全部资源。生产环境必须在限制前后对照应用指标,而不是只看 docker inspect 的配置变化。
| 上一篇 | 下一篇 |
|---|---|
| 04-重启策略与健康检查 | 06-Dockerfile 与镜像构建 |