2、目标单元(Target)基础:什么是Target单元,Target与传统运行级别的对应关系
2.1 Target单元的定义与作用
在systemd体系中,Target单元(目标单元)是一种特殊的单元类型,用于将其他单元(如服务单元、套接字单元、挂载单元等)逻辑地分组,形成一个同步点或系统状态快照。Target单元本身不执行任何操作,它只通过依赖关系(Wants、Requires、After、Before)来协调一组单元的启动顺序和并行度。
Target单元的核心作用包括:
- 状态聚合:将多个服务单元聚合为一个逻辑状态(如“网络就绪”、“图形界面就绪”)。
- 启动同步:确保在进入某个目标之前,其依赖的所有单元都已成功启动。
- 系统切换:通过切换默认Target(如从
multi-user.target切换到graphical.target),实现运行级别的动态变更。 - 故障隔离:当某个关键服务启动失败时,Target单元可以阻止系统进入更高层次的状态,从而暴露问题。
关键理解: Target单元类似于“里程碑”或“检查点”。系统启动过程就是从一个Target过渡到下一个Target,直到达到默认的启动目标。每个Target代表系统的一个特定功能层级。
2.2 Target与传统运行级别的对应关系
在SysVinit时代,运行级别(Runlevel)用数字0-6表示系统的不同状态。systemd使用Target单元替代了运行级别,但保留了向后兼容性。下表展示了传统运行级别与systemd Target的精确对应关系:
| 传统运行级别 | SysVinit描述 | 对应的systemd Target | systemd Target描述 |
|---|---|---|---|
| 0 | 关机(Halt) | poweroff.target |
关闭系统并切断电源 |
| 1 | 单用户模式(Single-user) | rescue.target |
最小化环境,挂载根文件系统,仅启动基本服务,用于维护和修复 |
| 2 | 多用户模式(无网络) | multi-user.target |
多用户文本模式,启动所有非图形服务,包括网络服务 |
| 3 | 多用户模式(有网络) | multi-user.target |
与运行级别2相同,systemd将2、3、4统一映射到multi-user.target |
| 4 | 保留/自定义 | multi-user.target |
与运行级别2、3相同,通常不单独使用 |
| 5 | 图形界面模式(X11) | graphical.target |
在multi-user.target基础上启动显示管理器和桌面环境 |
| 6 | 重启(Reboot) | reboot.target |
重新启动系统 |
重要差异: SysVinit的运行级别是互斥的(一次只能处于一个级别),而systemd的Target单元可以同时激活多个。例如,
graphical.target会通过依赖关系自动激活multi-user.target,形成层级叠加。此外,systemd允许创建自定义Target,灵活性远超传统运行级别。
2.3 Target单元的层级结构与依赖关系
Target单元之间通过依赖关系形成层级结构。系统启动时,systemd按照依赖顺序依次激活各个Target。下图展示了从系统启动到图形界面的典型Target层级:
2.4 默认Target的查看与设置
系统启动时,systemd会读取默认Target(default target),并激活该Target及其所有依赖。默认Target通常是一个符号链接,指向/etc/systemd/system/default.target。
常用命令:
# 查看当前默认Target
systemctl get-default
# 设置默认Target为多用户模式(文本界面)
sudo systemctl set-default multi-user.target
# 设置默认Target为图形界面模式
sudo systemctl set-default graphical.target
# 查看当前系统正在运行的Target(激活状态)
systemctl list-units --type=target --state=active
# 查看所有可用的Target单元
systemctl list-units --type=target --all
故障排查提示: 如果系统启动后无法进入图形界面,首先检查默认Target是否为
graphical.target。使用systemctl get-default确认。如果默认Target正确,再检查graphical.target的依赖是否完整:systemctl list-dependencies graphical.target。常见问题包括显示管理器(如gdm、lightdm)服务未启用或启动失败。
2.5 Target单元的配置文件结构
每个Target单元对应一个配置文件,通常位于/usr/lib/systemd/system/(系统默认)或/etc/systemd/system/(用户自定义覆盖)。配置文件以.target为后缀。
示例:graphical.target 配置文件
# /usr/lib/systemd/system/graphical.target
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
After=multi-user.target
Conflicts=rescue.target
AllowIsolate=yes
关键指令说明:
| 指令 | 含义 | 在Target中的典型用法 |
|---|---|---|
Requires= |
强依赖:如果依赖单元启动失败,本Target也会失败 | graphical.target 依赖 multi-user.target |
Wants= |
弱依赖:依赖单元启动失败不影响本Target | graphical.target 希望启动 display-manager.service |
After= |
排序约束:本Target在指定单元之后启动 | graphical.target 在 multi-user.target 之后启动 |
Conflicts= |
冲突关系:本Target与指定单元不能同时激活 | graphical.target 与 rescue.target 冲突 |
AllowIsolate= |
是否允许通过 systemctl isolate 切换到此Target |
通常设置为 yes,允许动态切换运行级别 |
2.6 Target单元在故障排查中的价值
在systemd初始化阶段故障排查中,Target单元是定位问题的关键锚点。以下是基于Target的排查思路:
- 确定故障发生的层级:使用
systemctl list-dependencies <target>查看某个Target的依赖链,找出哪个服务单元启动失败。 - 检查Target激活状态:
systemctl status <target>可以查看Target是否成功激活,以及其依赖中是否有失败的服务。 - 逐步隔离测试:通过
systemctl isolate rescue.target进入救援模式,然后逐步切换到multi-user.target,观察哪个步骤失败。 - 分析依赖循环:使用
systemd-analyze verify检查Target配置中是否存在循环依赖。
实战案例: 某服务器启动后卡在“A start job is running for wait for network to be configured”超时。排查步骤:
1. 运行
2. 发现
3. 修改该服务的
1. 运行
systemctl list-dependencies network-online.target 查看依赖。2. 发现
systemd-networkd-wait-online.service 配置了超时时间过长。3. 修改该服务的
TimeoutStartSec 参数,或禁用 network-online.target 的等待依赖,问题解决。
2.7 自定义Target的创建方法
在实际运维中,有时需要创建自定义Target来管理一组特定的服务。例如,创建一个 myapp.target 来统一管理某业务应用的所有服务。
创建步骤:
# 1. 创建自定义Target配置文件
sudo vim /etc/systemd/system/myapp.target
# 文件内容:
[Unit]
Description=My Application Target
Requires=myapp-database.service myapp-web.service
After=network.target
AllowIsolate=yes
# 2. 重新加载systemd配置
sudo systemctl daemon-reload
# 3. 启用自定义Target(可选,设置为默认启动目标)
sudo systemctl enable myapp.target
# 4. 手动切换到自定义Target
sudo systemctl isolate myapp.target
最佳实践: 自定义Target应放在
/etc/systemd/system/ 目录下,避免与系统默认Target冲突。命名建议使用 <应用名>.target 格式,便于识别。在Target中尽量使用 Wants= 而非 Requires=,避免因单个服务故障导致整个Target无法激活。