在 ubuntu 内核中启用 cgroup cpu 实时运行时

Bap*_*SCH 5 real-time linux-kernel docker

我正在尝试在 Ubuntu 18.04 上运行的 docker 容器中使用实时调度。

我已经按照此处给出的方法安装了实时内核。我选择了内核版本 5.2.9 及其相关的 rt 补丁。

的输出uname -a确认实时内核已正确安装并运行:

Linux myLaptop 5.2.9-rt3 #1 SMP PREEMPT RT ...
Run Code Online (Sandbox Code Playgroud)

要运行我的容器,我发出以下命令:

docker run --cpu-rt-runtime=95000 \
    --ulimit rtprio=99 \
    --ulimit memlock=102400 \
    --cap-add=sys_nice \
    --privileged \
    -it \
    myimage:latest
Run Code Online (Sandbox Code Playgroud)

但是,我得到的输出是:

docker: Error response from daemon: Your kernel does not support cgroup cpu real-time runtime.
Run Code Online (Sandbox Code Playgroud)

我已经看到这可能与此处CONFIG_RT_GROUP_SCHED问题中详述的缺失有关。事实上,如果我运行此页面提供的脚本来检查内核与 Docker 的兼容性,我会得到:

- CONFIG_RT_GROUP_SCHED: missing
Run Code Online (Sandbox Code Playgroud)

这似乎证实了 Docker 正在使用它进行实时调度,但内核中并未提供,尽管已修补为实时。

从那里,我试图徒劳地寻找解决方案。我不太精通内核配置,不知道是否需要使用特定选项编译它,以及选择哪个选项来添加缺少的CONFIG_RT_GROUP_SCHED.

非常感谢您的建议和帮助。

2b-*_*b-t 3

当谈论实时 Linux 时,有不同的方法,从单内核方法(如PREEMPT_RT)到双内核方法(如Xenomai)。您可以将具有实时功能的 Docker 与所有这些 Docker 结合使用(显然您的主机的内核必须匹配)来生成具有实时功能的系统,但方法有所不同。在您的情况下,您混合了两种不同的方法:您PREEMPT_RT遵循PREEMPT_RT.


默认情况下,Linux 内核可以使用不同级别的抢占能力进行编译(参见Reghenzani 等人 - “实时 Linux 内核:PREEMPT_RT 调查”):

  • PREEMPT_NONE没有办法强制抢占
  • PREEMPT_VOLUNTARY在某些位置可以进行抢占以减少延迟
  • PREEMPT抢占可以发生在内核的任何部分(不包括自旋锁和其他关键部分)

这些可以通过在内核编译期间设置来与控制组(cgroups简称)的功能相结合,为某个(用户定义的)组的进程保留一定比例的CPU时间。CONFIG_RT_GROUP_SCHED=y

PREEMPT_RT开发自PREEMPT, 是一组补丁,旨在使内核完全可抢占,甚至在关键部分 ( PREEMPT_RT_FULL)。为此目的,例如自旋锁大部分被互斥锁所取代。截至 2021 年,它正在慢慢合并到主线中,并将向公众开放,无需修补内核。如此处 所述PREEMPT_RT,目前无法使用 进行编译CONFIG_RT_GROUP_SCHED,因此不能与对照组一起使用(请参阅此处进行比较)。据我所知,这是由于高延迟峰值造成的,我已经通过cyclicytests方法在对照组中观察到了这一点。

这意味着您可以编译内核(有关详细信息,请参阅Ubuntu 手册)

  • 不使用PREEMPT_RT但使用CONFIG_RT_GROUP_SCHED(有关详细信息,请参阅这篇文章)并按照控制组的实时 Docker 指南以及我的帖子此处进行操作。根据我的经验,这虽然具有相当高的延迟峰值,但这对于实时系统来说是不可取的,因为最坏情况的延迟比平均延迟重要得多。

  • With PREEMPT_RTwithoutCONFIG_RT_GROUP_SCHED(也可以从 Debian 软件包安装,例如这个)。--privileged --net=host在这种情况下,使用 options或 Docker-compose 等效项执行 Docker 就足够了privileged: true network_mode: host。然后,Docker 内部的任何进程都可以设置实时优先级rtprio(例如,通过::pthread_setschedparam从代码内部调用或chrt从命令行使用)。

    如果您没有在 Docker 中使用rootas 用户,您还必须为自己指定一个用户名,该用户名属于在您的主机上具有实时权限的组(请参阅 参考资料$ ulimit -r)。这可以通过复制用户组的部分并创建新组(例如)或直接添加用户(例如)来相应地配置PAM 限制/etc/security/limits.conf文件)(如此处所述)完成:@realtime@some_groupsome_user

    @some_group     soft    rtprio          99
    @some_group     soft    priority        99
    @some_group     hard    rtprio          99
    @some_group     hard    priority        99
    
    Run Code Online (Sandbox Code Playgroud)

    在这种情况下,rtprio是非特权进程允许的最大实时优先级。该限制是可以设置的hard实际限制。soft这些hard限制由超级用户设置并由内核强制执行。用户不能将其代码提升到高于hard限制的优先级运行。soft另一方面,限制是受限制限制的默认值hard。有关更多信息,请参见此处

我将后一个选项用于具有实时功能的机器人应用程序,并且无法观察到使用和不使用 Docker 之间的延迟差异。您可以在我的 Github 上找到有关如何设置PREEMPT_RT和自动化脚本来构建它的指南。