独立服务器

裸机服务器上的容器资源限制与 cgroups

容器的优势在于可以封装应用程序及其依赖,而不必为每项工作负载各自运行完整操作系统。然而在裸机服务器上,容器运行环境会与主机共享内核,以及物理 CPU、内存、存储和网络路径。因此,清晰的资源策略十分重要。容器资源限制可以把物理容量转化为可执行的边界,避免单一工作负载耗尽其他服务所需的余量。

Linux 控制组(通常称为 cgroups)就是这些边界背后的内核机制。它会把进程组织成层级并记录资源使用量,让运营人员或编排平台对容器、Pod、服务或主机 slice 应用策略。了解 cgroups 对专用硬件尤其重要,因为管理员可以控制内核,并调整主机、容器运行环境与工作负载之间的关系。

cgroups 在裸机服务器上控制什么

cgroup 不是虚拟机,也不会模拟硬件,而是围绕一组进程建立的内核级资源边界。根据控制器及 Linux 版本,它可以限制或调节 CPU 时间、内存、进程数量、区块 I/O、设备访问,以及 CPU 或 NUMA 位置。容器运行环境在启动工作负载时创建并管理这些组,而 systemd 和 Kubernetes 也可能为服务及 Pod 创建额外的父级组。

  • 目前大部分发行版使用 cgroup v2,提供统一层级及一致接口,例如 cpu.max、memory.max、memory.high、pids.max 和 io.max。较旧的系统仍可能使用 cgroup v1,控制器会分开挂载。文件名称及运行行为会有所不同,因此运营团队在记录限制或编写自动化之前,应先确认主机的 cgroup 版本。
  • 资源路径通常有多个层次:主机内核、系统或服务管理器、容器运行环境,以及使用 Kubernetes 时的 kubelet 和 Pod 层级。一层的限制可能会与另一层互相影响。容器即使看似有可用 CPU,仍可能受到 Pod 配额或 system slice 限制;节点即使有空闲内存,也可能为操作系统及重要后台服务保留容量。

如需比较不同隔离模式,可参阅 Dataplugs 的 《裸机上的容器化与虚拟化:隔离及性能》文章。文章有助了解容器如何共享内核、虚拟机如何引入独立客户操作系统,以及为什么专用硬件上的资源边界必须明确设计。

实际目标不是把每个容器缩到最小,而是为每项工作负载提供可预测的运行范围,为恢复工作及平台服务保留足够主机余量,并在资源耗尽演变成故障前让问题可被发现。

CPU 和内存限制是第一层控制

CPU 限制可以用一段时间内的配额、相对权重,或指定工作负载可使用的 CPU 集合表示。配额限制持续 CPU 消耗;权重影响竞争时 CPU 时间如何分配;cpuset 则可以把对延迟敏感的工作隔离到指定核心。这些控制解决不同问题。如果没有考虑突发流量就应用配额,可能增加排队;只使用权重,则无法阻止繁忙容器在节点空闲时使用全部可用容量。

内存限制更难处理,因为内存不一定能够平稳回收。在 cgroup v2 中,memory.high 是会触发回收及节流的压力阈值,而 memory.max 是硬上限。当主机受压时,memory.min 或 memory.low 可以保护重要服务。正确数值取决于应用程序的工作集、缓存行为、启动峰值,以及 sidecar 或辅助进程使用的内存,而不只是平均常驻集。

  • 当工作负载达到内存硬上限,而回收又无法释放足够空间时,内核可能启动 cgroup 的内存不足处理流程并终止进程。这比让整台主机变得不稳定更安全,但不能代替应用程序层面的容量规划。应输出内存工作集、回收、节流及 OOM 事件,再与部署及重启策略连接,让运营人员分辨错误限制、内存泄漏或流量突增。
  • pids 控制器限制 cgroup 可以创建的进程及线程数量,有助防止 fork bomb、工作进程失控增加及进程池配置错误。设置时要了解运行环境、应用程序工作进程、语言线程、健康检查及短期工作。PID 限制过低时,即使 CPU 和内存指标正常,也可能看起来像应用程序故障。

io.max 和 io.weight 等区块 I/O 控制,可以保护对延迟敏感的服务,避免受到批处理工作或大量镜像部署影响。设备级限制在了解存储布局时最有用:NVMe 卷、RAID 设备及文件系统可能在不同位置出现压力。如果工作负载需要直接访问 GPU 或其他设备,应结合适当的运行环境及安全策略处理设备权限,不要把设备访问当成一般资源限制。

为裸机工作负载设计资源限制

先从测量开始,而不是随意选择一个整数。记录正常及突发流量下的 CPU 使用率、节流时间、内存工作集、页面错误、I/O 延迟、吞吐量、进程数量及启动峰值。新工作负载在预热、填充缓存及稳定运行期间都应测量。这些观察为请求、限制及主机规模提供可靠依据,也让日后调优不必过度依赖猜测。

  • 要有意识地为主机保留余量。操作系统、容器运行环境、日志、监控、存储代理程序、安全控制及编排组件,即使应用程序容器繁忙也需要资源。在裸机上,管理员还应计算内核内存、中断处理、文件系统缓存及恢复工作。把所有已安装 RAM 或所有逻辑 CPU 都视为可分配给应用程序的容量,可能让单一容器突增变成节点级事故。
  • 把有保障的基本容量与最大值分开。请求或保留值表示工作负载通常应获得的容量;限制则定义它最多可以增长到哪里。在 Kubernetes 中,requests 影响调度,而 limits 由运行环境及内核执行。在独立 Docker 主机上,同类策略可以写在 Compose 文件、systemd 单元或部署脚本中。把两个概念分开,有助厘清容量计划,避免所有数值都设置成一样。

硬件拓扑同样重要。在多插槽或 NUMA 系统中,可以在不同节点自由移动的容器,每次运行可能面对不同的内存延迟及缓存局部性。只有在测量显示有益时才应固定位置,因为过度严格的 CPU 或 NUMA 配置会降低可调度性。应记录 cpuset 设置、内存位置、中断亲和性与工作负载延迟目标之间的关系。如果设计包含 Kubernetes,可参阅 Dataplugs 关于 运行 Kubernetes 的专用服务器型号建议的指南,了解如何按集群角色匹配 CPU 拓扑、内存容量、NVMe 存储及网络行为。

监控及测试资源边界

监控应同时展示使用量及是否受到限制。把 CPU 使用量与节流秒数并列,把内存使用量与内存事件及 OOM 终止并列,再把 I/O 吞吐量与延迟及队列深度并列。Kubernetes 应结合节点、Pod 及容器指标;独立主机则应加入 systemd slice 及运行环境统计。只显示使用率的仪表板,可能看不出工作负载已经在被节流。

  • 要有意识地测试竞争情况。在非生产环境运行受控 CPU 压力、内存配置、进程创建或 I/O 工作,确认目标工作负载仍符合服务目标。验证故障信号、重启行为、日志消息、警报及恢复时间。同时测试相反情况:移除人为压力后,确认工作负载能再次使用获准的突发容量,而不是永久处于节流状态。
  • 把资源策略与应用程序发布放在一起。把 cgroup 设置、节点标签、运行环境参数及监控规则一起版本化,并记录每次改变限制的原因。审查人员应能回答测量了哪项工作负载、要防止哪种故障,以及哪个警报会发现错误数值。当团队从 cgroup v1 迁移至 v2 或更换容器运行环境时,这点尤其重要。

利用结果进行容量规划。经常触及的限制可能表示需要调优应用程序、增加节点、把工作负载移到更大型的裸机配置,或改变调度类别。未检查竞争情况就提高限制,只会把瓶颈移到另一处。改变硬件或策略前,应一并检查饱和、节流、OOM 事件、排队及恢复时间。

总结

容器资源限制及 cgroups 把裸机容量转化为一组受控且可测量的运行范围。最稳健的设计会分开处理 CPU、内存、进程、I/O 及设备问题;区分基本容量与上限;为主机保留余量;验证生成的层级;并测试触及边界时应出现的行为。

Dataplugs 独立服务器提供硬件隔离及管理权限,让团队可以为容器化应用程序调优这些控制。至于部署及可观测性所需的运营工具,可参阅 Dataplugs 关于 使用 Prometheus 和 Grafana 监控服务器健康状况的文章,并把资源策略版本化,随着工作负载变化定期检讨。

如需了解更多独立服务器基础设施信息,请浏览 Dataplugs 网站或联系 sales@dataplugs.com。

主页 » 最新消息 » 独立服务器 » 裸机服务器上的容器资源限制与 cgroups