Systemd中的CGroup委托机制详解
systemd The systemd System and Service Manager 项目地址: https://gitcode.com/gh_mirrors/sy/systemd
前言
在现代Linux系统中,控制组(cgroup)是资源管理的关键技术。作为系统和服务管理器,systemd对cgroup提供了深度集成支持。本文将深入解析systemd中的cgroup委托机制,帮助开发者特别是容器管理器开发者理解如何正确与systemd的cgroup管理进行交互。
CGroup基础概念
CGroup v2的核心规则
在深入systemd实现前,必须理解cgroup v2的两条核心规则:
-
内部节点无进程规则:一个cgroup要么是内部节点(包含子cgroup),要么是叶节点(包含进程),但不能同时具备两种特性。内核会强制实施此规则。
-
单一写入者规则:每个cgroup应当只有一个管理进程拥有写入权限。这避免了多个管理器之间的冲突。
CGroup v1与v2的差异
- CGroup v1存在语义缺陷,许多功能表现与预期不符
- CGroup v2提供了更完整的功能集,包括:
- 可靠的cgroup空通知
- 每个cgroup的BPF功能
- 安全的cgroup树委托机制
- 新内核特性仅添加到v2,v1已停止发展
Systemd的CGroup支持模式
systemd支持三种cgroup层次结构模式:
-
统一模式(Unified):纯cgroup v2模式,所有控制器通过
/sys/fs/cgroup/
单一挂载点暴露。 -
传统模式(Legacy)(已弃用):传统cgroup v1模式,每个控制器有独立挂载点。
-
混合模式(Hybrid)(已弃用):保留v1兼容性的同时提供部分v2功能。
当前推荐仅使用统一模式,其他模式已在较新版本中移除。
Systemd的单元类型与CGroup
systemd通过三种单元类型暴露cgroup功能:
-
服务单元(.service):封装由systemd直接启动的进程,通常是cgroup树的叶节点。
-
范围单元(.scope):封装由外部进程启动的进程组,只能以临时方式创建。
-
切片单元(.slice):构成cgroup树的内部节点,不直接包含进程。
默认切片单元
systemd默认创建四个切片单元:
-.slice
:根切片,对应cgroup v2的顶层目录system.slice
:系统服务默认位置user.slice
:用户会话位置machines.slice
:虚拟机和容器位置
CGroup委托机制详解
委托的基本概念
委托允许将cgroup子树的管理权交给特定进程。在systemd中,可以通过设置服务或范围单元的Delegate=
属性来启用委托。
启用委托后:
- systemd不再干涉该单元下的子树
- 若使用
User=
,子树会被chown给指定用户 - BPF过滤器会设置
BPF_F_ALLOW_MULTI
标志
委托的使用方法
在单元文件中:
[Service]
Delegate=yes # 委托所有可用控制器
# 或
Delegate=cpu memory # 仅委托指定控制器
从systemd 236开始,Delegate=
可接受控制器列表,仅请求特定控制器的委托。
重要注意事项
-
仅限服务/范围单元:切片单元不支持委托,因为它们是内部节点。
-
.control子cgroup:若服务有
ExecStartPost
等命令,systemd会在.control/
子cgroup中执行它们。 -
线程化cgroups:如需使用线程化cgroups(Linux 4.14+),需要在主服务cgroup下两级创建。
-
控制器启用:委托后需手动写入
cgroup.subtree_control
启用控制器。
实践场景分析
场景1:深度集成(推荐)
适用:希望与系统深度集成的容器管理器
实现方式:
- 将每个容器注册为systemd服务或范围单元
- 启用
Delegate=
属性 - 可选择通过
systemd-machined
注册以获得额外集成功能
优点:
- 管理员可使用标准systemd工具管理容器资源
- 支持完整的系统集成功能
- 允许容器内运行cgroup感知程序(如嵌套systemd)
场景2:独立管理
适用:希望最小化与systemd交互的简单管理器
实现方式:
- 为主管理器服务启用
Delegate=
- 在分配的cgroup下自主管理子树
注意:必须将主进程移出初始cgroup才能创建子cgroup。
场景3:混合管理
适用:希望保持管理器独立但统一管理工作负载
实现方式:
- 不委托管理器自身的cgroup
- 为工作负载创建专用范围单元并启用委托
- 将所有工作进程放入该范围
最佳实践建议
-
优先选择统一模式:避免使用已弃用的传统/混合模式。
-
遵循单一写入者规则:即使技术上允许多个写入者,也应保持单一管理关系。
-
及时迁移进程:在创建子cgroup前,确保将主进程移出当前cgroup。
-
考虑使用systemd-machined:为容器管理提供更好的系统集成。
-
测试控制器可用性:委托时检查实际获得的控制器可能与请求不同。
通过正确理解和应用systemd的cgroup委托机制,开发者可以构建既能充分利用系统功能,又能保持必要独立性的资源管理方案。
systemd The systemd System and Service Manager 项目地址: https://gitcode.com/gh_mirrors/sy/systemd
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考