知用网
白蓝主题五 · 清爽阅读
首页  > 网络运维

网络容器CPU内存控制实战技巧

容器资源限制不是摆设

跑个 Docker 容器,顺手就用默认配置,结果线上服务一跑起来,某个 Java 应用直接吃满主机内存,把别的服务全挤下去了。这种情况在小团队里太常见了。别以为容器天然隔离,不设限就跟裸奔差不多。

其实从启动容器那一刻起,就得考虑 CPU 和内存的分配。Docker、Kubernetes 这些平台都提供了精细的控制手段,关键是怎么用到位。

CPU 控制:别让一个容器抢走全部算力

假设你有台 4 核服务器,跑了三个服务容器:API 网关、日志处理、后台任务。如果不做限制,其中一个计算密集型任务可能占满所有 CPU 时间,导致接口响应变慢。

Docker 提供了 --cpus 参数,可以按比例分配。比如给 API 网关分 1.5 核:

docker run -d --name api-gateway --cpus=1.5 my-api:latest

这个值其实是 CPU 时间的权重比例,并非硬性隔离。系统空闲时,容器仍可短暂 burst 超过限额,但长期占用会被调度器压制。

更细粒度的控制可以用 --cpu-shares,它设定的是相对权重。比如:

docker run -d --name logger --cpu-shares 512 my-logger

而主服务设为 1024,那么在 CPU 竞争时,后者能拿到两倍于前者的执行时间。

内存限制:防止“内存杀手”出现

最怕哪种容器?那种默默增长内存使用,直到触发 OOM(Out of Memory)被系统杀掉的。尤其是 Java 应用,JVM 堆没设好,容器内存超限是常事。

-m--memory 可以硬性限制容器最大可用内存。例如限制为 512MB:

docker run -d --name worker -m 512m my-worker:latest

这时候即使应用想申请更多内存,也会被 cgroup 拦下,不会影响宿主机和其他容器。

配合使用 --memory-swap 可以控制是否允许使用交换空间。设成和 memory 一样大小,就等于禁用 swap:

docker run -d --name worker -m 512m --memory-swap 512m my-worker

对延迟敏感的服务,建议禁用 swap,避免因换页导致响应抖动。

Kubernetes 中的资源配置

在 K8s 里,这些控制通过 Pod 的 resources 字段实现。比如:

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: my-frontend
    resources:
      requests:
        memory: "256Mi"
        cpu: "250m"
      limits:
        memory: "512Mi"
        cpu: "500m"

这里 requests 是调度依据,limits 是运行上限。Kubelet 会根据 limits 设置 cgroup 规则。

特别注意:Java 应用在容器里跑时,JVM 不一定能感知到容器内存限制。建议加上 -XX:+UseContainerSupport 参数,或者显式设置 -Xmx,比如 -Xmx400m,留点空间给堆外内存。

监控与调整不能少

设了限不代表万事大吉。得用 Prometheus + Grafana 搭套监控,看各个容器的实际 CPU 和内存走势。经常发现某些服务申请了 1G 内存,实际只用 200M,白白浪费调度资源。

反过来,也有设得太紧的,频繁触发接近 limit 的告警。这时候就得结合日志和性能数据,逐步调优。

资源限制不是一次性的配置,而是随着业务变化持续调整的过程。上线前压测,上线后观察,才能找到最合适的配额。