容器把进程、文件系统和资源视图隔开,却不提供一套新的实时内核。容器中的线程仍由宿主机同一个调度器、同一组 IRQ、同一块缓存和同一套功耗策略管理。因此“进容器后 chrt 成功了”只证明进程拿到了调度权限,不证明它已经获得稳定的 CPU、内存或设备时延。
容器里实时性由哪几层共同决定
进程能否设置实时策略通常受 CAP_SYS_NICE、RLIMIT_RTPRIO 和宿主机安全策略约束;能在哪些 CPU 上运行由 cpuset 决定;普通 CPU 配额会限制 cgroup 的可用时间;内存节点选择则会影响 NUMA 本地性。不同内核版本和 cgroup 层级对实时带宽控制的支持也有差异,因此要查看实际 controller 和运行时配置,而不是假设 Docker/Kubernetes 有一个通用“实时模式”。
不要把特权当作解决方案
为了设置 FIFO,一些部署会直接给容器 --privileged。这扩大了攻击面,也掩盖了真正需要的最小权限。更好的做法是只授予需要的 capability、设定明确的 rtprio/memlock 限制,并通过 cpuset 限制容器不会漂移到不属于它的 CPU。权限让线程可以请求资源,资源规划才决定它能否按期完成。
容器内外应同时检查:
1 | # 容器内:调度类、优先级和允许的 CPU |
路径和 controller 名称会因 cgroup v1/v2、systemd 和运行时而不同,但“查看宿主机真相”这一步不能省。
一种可控的部署模式
将实时容器限制在一组专门 CPU,将非实时 API、日志、图像编码和批处理放在另一组 CPU;宿主机把无关 IRQ、RCU 和 worker 移到 housekeeping CPU。容器中的实时线程使用固定容量内存和 watchdog,控制器对超时输入进行安全降级。这样容器负责交付和隔离,宿主机仍负责系统级实时布局。
验收时必须同时制造容器内负载和宿主机负载,例如邻居容器 CPU/内存压力、网卡高流量、日志轮转、镜像更新。容器空载下的 P99 并不能代表共部署后的表现。
参考:Control Group v2 · sched(7)