Systemd 目标详解:有效管理启动状态与运行级别
理解 systemd 目标、运行级别对应关系、默认启动状态、隔离模式、救援模式及图形模式。
Systemd 目标详解:有效管理启动状态与运行级别
Systemd 目标是命名的系统状态。一个目标可以代表正常的服务器启动、图形桌面、救援 shell、关机,或您希望一起启动的自定义服务组。如果您来自较旧的 Linux 系统,目标是 systemd 对人们实际使用的运行级别部分的替代,但它们更加灵活,因为它们是基于依赖关系而非仅数字构建的。
您通常会在服务器启动到错误模式、桌面显示管理器无法启动、或恢复指南告诉您进入 rescue.target 时遇到目标。了解几个命令能让这些情况不再那么神秘。
从运行级别到 Systemd 目标的演进
历史上,Linux 系统使用称为 运行级别 的概念来定义系统在启动和运行时的操作状态。运行级别是一个数字标识符(0-6),决定了哪些服务启动或停止。例如,运行级别 3 通常表示多用户文本模式,而运行级别 5 表示图形多用户环境。这个系统虽然功能正常,但存在局限性:
- 僵化性: 运行级别通常以固定或发行版特定的方式定义,使得自定义特定状态下活跃的服务集合变得笨拙。
- 隐式依赖: 服务之间的依赖关系通常通过运行级别分配间接管理,导致潜在的冲突或遗漏服务。
- 缺乏粒度: 数字系统缺乏描述性清晰度,使得理解系统的预期状态更加困难。
Systemd 目标通过提供更明确、依赖驱动且描述性的方法来解决这些局限性。目标具有有意义的名称(例如 multi-user.target、graphical.target),而不是抽象的数字,清晰地指示了预期的系统状态。依赖关系在单元文件中明确定义,确保所有必要组件按正确顺序启动。
在许多 systemd 系统上,粗略的映射如下所示:
| 传统运行级别 | 常见 systemd 等效项 | 含义 |
|---|---|---|
| 0 | poweroff.target |
关机并断电 |
| 1 | rescue.target |
单用户救援模式 |
| 3 | multi-user.target |
多用户文本/服务器模式 |
| 5 | graphical.target |
多用户模式加图形登录 |
| 6 | reboot.target |
重启 |
请将此视为翻译辅助工具,而非定律。运行级别行为因发行版而异,而 systemd 目标可以表达旧运行级别无法表达的关系。
理解 Systemd 目标
Systemd 目标本身是一种单元类型。当目标单元被激活时,systemd 会尝试激活该目标单元文件中列为依赖项的所有单元。这会产生级联效应,确保所有必要的服务、设备和其他组件上线以达到所需的系统状态。
Systemd 目标的关键特性:
- 依赖管理: 目标定义了哪些其他单元需要处于活动状态,目标才能被视为已达成。这是其核心能力。
- 同步点: 它们在启动过程中充当同步点。系统在当前目标完全初始化之前不会进入下一阶段。
- 描述性命名: 目标被描述性地命名,使得理解系统的预期状态变得容易(例如
rescue.target、poweroff.target)。
目标通常自身不运行长期代码。它们对其他单元进行分组。您可以使用以下命令检查分组:
systemctl list-dependencies multi-user.target
systemctl list-dependencies graphical.target
这是回答“为什么这个服务在启动时启动?”的好方法。如果该单元出现在默认目标的依赖树中,则它正在被某处引入。
常见的 Systemd 目标
Systemd 附带一组预定义的目标,旨在覆盖常见的系统状态。理解这些目标是管理系统的关键。
multi-user.target
这是最基本的目标之一。它代表一个功能齐全的多用户系统,具有网络功能,但没有图形登录管理器或桌面环境。这通常是服务器的默认目标。
- 目的: 提供一个稳定的环境来运行服务,并允许多个用户通过文本控制台或 SSH 登录。
- 依赖项: 通常包括网络、系统服务和控制台登录提示的单元。
对于无头服务器,multi-user.target 通常是正确的默认值。它提供 SSH 和正常服务,而无需在显示管理器上消耗资源。
graphical.target
此目标代表一个功能齐全的多用户系统,具有可供用户交互的图形桌面环境。它通常是 multi-user.target 的依赖项,并添加了图形会话所需的组件。
- 目的: 启动图形显示管理器(如 GDM、LightDM、SDDM)和相关的桌面环境。
- 依赖项: 通常引入
multi-user.target行为,并添加显示管理器和图形会话组件的单元。
如果工作站启动到黑屏但 SSH 仍然有效,请比较以下内容:
systemctl get-default
systemctl status display-manager.service
journalctl -u display-manager.service -b
默认目标告诉您系统试图达到什么状态。显示管理器日志告诉您图形层为何未启动。
rescue.target
此目标提供一个最小的单用户环境。它主要用于系统维护和恢复。它启动基本系统和 root shell,但通常不启动网络或多用户服务。
- 目的: 为系统管理员提供一个安全的环境来执行维护任务,而不受其他服务的干扰。
- 依赖项: 最小的一组基本系统组件和一个 root shell。除非您手动启动,否则网络通常不可用。
emergency.target
这比 rescue.target 更小。它将系统启动到单个只读文件系统和 root shell。它用于即使基本服务也可能有问题的严重紧急情况。
- 目的: 用于关键系统恢复,即使
rescue.target可能也不合适。 - 依赖项: 仅最基本的系统组件和一个 root shell。根据故障和发行版,根文件系统可能以只读方式挂载。
reboot.target、poweroff.target、halt.target
这些是用于关闭或重启系统的特殊目标。当 systemd 激活这些目标之一时,它会停止所有正在运行的服务,然后执行指定的操作(重启、断电或停机)。
- 目的: 优雅地关闭或重启系统。
- 依赖项: 它们通常依赖于在系统关闭前需要停止的服务。
管理 Systemd 目标
Systemd 提供了几个命令行工具来与目标交互。主要工具是 systemctl。
查看当前和默认目标
要查看系统当前正在运行哪个目标以及系统在启动时默认使用哪个目标,请使用:
systemctl status
此命令提供大量信息,包括活动目标。要专门查询默认目标:
systemctl get-default
要查看所有可用目标:
systemctl list-unit-files --type=target
要查看活动的目标单元,请使用:
systemctl list-units --type=target
区别与服务相同:list-unit-files 显示 systemd 知道的目标文件,而 list-units 显示当前在运行系统中加载或活动的目标。
更改默认目标
如果您希望系统默认启动到不同的目标(例如,从图形到多用户,或反之),您可以使用 systemctl set-default:
将默认值设置为图形目标(常见于桌面系统):
sudo systemctl set-default graphical.target
将默认值设置为多用户目标(常见于服务器):
sudo systemctl set-default multi-user.target
重要: 更改默认目标仅在下一次重启时生效。
在底层,这会更改 default.target 符号链接。如果您正在调试损坏的启动映像,可以直接检查它:
systemctl get-default
ls -l /etc/systemd/system/default.target
切换到目标(无需重启)
您可以立即将系统切换到不同的目标而无需重启。这对于测试或临时更改系统状态非常有用。使用 systemctl isolate 命令:
切换到图形目标:
sudo systemctl isolate graphical.target
切换到多用户目标:
sudo systemctl isolate multi-user.target
注意: systemctl isolate 是一个强大的命令。隔离到像 rescue.target 或 emergency.target 这样的目标将停止大多数正在运行的服务。在使用前确保您了解其影响。您可能会失去网络连接或图形会话。
在远程服务器上,要特别小心使用 isolate rescue.target 或 isolate emergency.target。您可能会失去 SSH 并需要通过云提供商、虚拟机管理程序或物理机器进行控制台访问。如果您只需要在工作站上停止图形桌面,隔离到 multi-user.target 比直接跳入救援模式要温和得多。
目标与单元文件的关系
目标作为单元文件实现,通常位于 /usr/lib/systemd/system/ 或 /etc/systemd/system/。一个目标单元文件(例如 graphical.target)指定了对其他单元的依赖关系,包括其他目标和服务。
一个典型的 graphical.target 单元文件可能看起来像这样(简化版):
[Unit]
Description=图形多用户系统
Documentation=man:systemd.special(7)
# 此目标旨在作为图形登录管理器的先决条件。
# 如果未另行指定,系统将启动到此目标。
Wants=display-manager.service
Before=shutdown.target
[Install]
Alias=default.target
这里:
Wants=display-manager.service:表示应尽可能启动display-manager.service(实际的登录管理器,如 GDM 或 LightDM)。这是一个比Requires=更弱的依赖关系。Before=shutdown.target:确保在系统进入关机过程之前停止图形环境。Alias=default.target:这使得graphical.target充当默认值,如果default.target链接到它(桌面系统通常如此)。
创建自定义目标
虽然日常使用较少见,但您可以创建自己的自定义目标来定义具有独特服务集的特定系统状态。
创建自定义目标的步骤:
- 创建一个
.target单元文件: 将其放置在/etc/systemd/system/中(例如my-custom.target)。[Unit] Description=我的自定义目标 [Install] WantedBy=multi-user.target # 或其他适当的目标 - 创建
.service或其他单元文件: 定义应为您的自定义目标激活的服务和其他单元。 - 添加依赖关系: 在您的自定义目标单元文件中,使用
Requires=或Wants=指定必须或应该启动的单元。[Unit] Description=我的自定义目标 Wants=service1.service Wants=service2.service After=service1.service service2.service [Install] WantedBy=multi-user.target - 重新加载 systemd:
sudo systemctl daemon-reload
5. **启用/启动您的目标:** bash
sudo systemctl start my-custom.target
# 或使其可启动
sudo systemctl enable my-custom.target
```
用例: 想象一个开发环境,您需要特定的数据库和应用程序服务器运行。您可以创建一个 dev-env.target 来启动这些服务。
自定义目标对于类似设备系统也很有用。例如,一个信息亭机器可能有一个目标,启动网络、浏览器、本地看门狗和日志代理,但不启动正常桌面会话的其余部分。一个实验室服务器可能为测试堆栈和演示堆栈设置单独的目标,以便操作员可以一起启动一组已知的服务。
最佳实践和技巧
- 了解默认值: 知道您系统的默认目标(
graphical.target或multi-user.target),因为它决定了初始启动体验。 - 谨慎使用
isolate: 在使用systemctl isolate时要小心,尤其是在生产系统上,因为它可能会中断正在运行的服务。 - 检查依赖关系: 如果服务未启动,请使用
systemctl list-dependencies <target_name>检查与其关联的目标的依赖关系。 - 服务器与桌面: 在服务器上,出于安全性和资源效率考虑,几乎总是首选
multi-user.target。在桌面上,graphical.target是标准。 - 系统维护: 对于需要最小干扰的任务,
rescue.target很有用。对于关键恢复,可以使用emergency.target。
思考目标的实用方法
对于大多数管理工作,您只需要一个简短的心智模型:
systemctl get-default
systemctl set-default multi-user.target
systemctl isolate graphical.target
systemctl list-dependencies graphical.target
get-default 告诉您机器应该启动到哪里。set-default 更改下一次启动。isolate 更改当前状态,并可能停止该状态之外的服务。list-dependencies 解释目标引入了什么。
目标不仅仅是重命名的运行级别。它们是依赖组。一旦您这样对待它们,启动问题就变得更容易推理:找到系统试图达到的目标,检查它想要的服务,然后修复失败的单元或依赖关系。