linux容器资源限制依赖cgroups内核机制,内存限制防oom杀进程,cpu限制分配时间片而非绑定核心,io限速需按真实设备路径配置,pid限制防fork炸弹。

Linux容器的资源限制核心靠cgroups实现,不是靠Docker或Podman本身“限制”,而是它们调用内核接口配置cgroups。真正起作用的是内核对CPU、内存、IO等子系统的控制能力。
内存限制:避免OOM杀进程
容器内存超限时,内核OOM Killer可能直接杀死容器内主进程(如PID 1)。设置--memory(如--memory=512m)会限制cgroup v1的memory.limit_in_bytes,或cgroup v2的memory.max。建议同时配--memory-swap=512m禁用swap,防止内存压力转移到磁盘;若允许swap,设为--memory-swap=1g(即内存+swap总和)。
- 查看实际限制:进入容器后读/sys/fs/cgroup/memory.max(cgroup v2)或/sys/fs/cgroup/memory/memory.limit_in_bytes(v1)
- 监控使用量:查/sys/fs/cgroup/memory.current,比docker stats更底层、无延迟
- 注意软限制无效:--memory-reservation仅作提示,不强制生效,不能替代硬限制
CPU限制:控制时间片而非核心数
CPU限制本质是分配CPU时间比例,不是绑定物理核心(那是--cpuset-cpus干的事)。常用两种方式:
- --cpus=1.5:在cgroup v2下设cpu.max = 150000 100000(表示每100ms最多用150ms CPU时间),适合突发负载场景
- --cpu-quota=15000 --cpu-period=10000:等价于1.5核,但需手动配周期,v1/v2均支持
- 避免只设--cpu-shares:它只在CPU争抢时起相对权重作用,空闲时不生效,不适合做硬约束
IO限速:按设备路径精细控制
Docker默认不限IO,需显式配置。关键点在于设备路径必须真实存在且被容器挂载:
- --device-read-bps=/dev/sda:1mb:限制读吞吐为1MB/s,适用于数据库容器防IO打满
- --device-write-iops=/dev/sdb:50:限制写IOPS为50次/秒,适合日志密集型服务
- 注意:宿主机/dev/sda在容器里可能变成/dev/nvme0n1,需先用lsblk确认实际设备名再配置
- cgroup v2下IO策略更统一,推荐启用systemd.unified_cgroup_hierarchy=1启动参数
PID与进程数限制:防fork炸弹
默认容器PID数无上限,一个恶意进程反复fork可耗尽宿主机pid_max。通过--pids-limit可硬限制:
- --pids-limit=100对应cgroup v2的pids.max,超过则fork失败并返回EAGAIN
- Java应用注意:JVM线程数 + GC线程 + 应用线程总和不能超此值,否则启动报java.lang.OutOfMemoryError: unable to create native thread
- 配合--ulimit nproc=50双重防护,限制单用户进程数(影响shell内启动的子进程)










