systemctl — systemd 系统与服务管理器控制详解
systemctl 是 Linux 下 systemd 系统与服务管理器(system and service manager)的控制前端。它并非直接操作进程,而是作为客户端通过 D-Bus 总线与 PID 1 的 systemd 守护进程通信,用于查看和改变系统、服务的状态。几乎每一个"我要管理这个 Linux 系统的进程与服务"的操作,都通过 systemctl 完成。
1. 概述
1.1 systemctl 是什么
systemctl 的功能分为两大块:
- 探查(introspect):查看 systemd 当前管理的所有单元(unit)、任务(job)、系统运行状态。
- 控制(control):启动/停止/重启服务、设置开机自启、进入救援模式、关机重启等。
命令语法:systemctl [OPTIONS...] COMMAND [UNIT...],默认与系统管理器通信;加 --user 则与当前用户的用户管理器通信。
org.freedesktop.systemd1 完成,因此你可以在脚本中通过 systemctl show 读取机器可解析的属性,而不是解析人读输出。
- systemd — 现代 Linux 的 init 系统(PID 1),负责系统启动时拉起所有服务并管理它们。
- systemctl — systemd 的控制命令行客户端(本页主角)。
- 单元 unit — systemd 管理的最小单位,用一个
*.service、*.target之类的配置文件描述"做什么"。 - 单元类型 unit type — 按后缀区分:service(服务)、socket(套接字)、target(目标)、timer(定时器)、mount(挂载)、path(路径)、device(设备)、slice(切片)、scope(作用域)等。
- 任务 job — 系统执行的一次原子状态操作(start / stop / restart 等),有 pending / running 等状态。
- 目标 target — 一组单元的集合,用于表达"运行级别"式的状态,如
multi-user.target、rescue.target。 - D-Bus — 桌面/系统总线,systemctl 通过它向 systemd 发请求。
- drop-in 片段 — 不修改原单元文件、用
xxx.service.d/*.conf追加覆盖配置的机制。
1.2 单元文件的查找路径
systemd 按优先级从高到低在以下目录查找单元文件,同名文件优先级高的生效:
| 目录 | 优先级 | 用途 |
|---|---|---|
/etc/systemd/system/ | 高(持久) | 管理员自定义/覆盖(enable 的符号链接也在这里) |
/run/systemd/system/ | 高(临时) | 本次开机有效,重启即失(--runtime) |
/usr/lib/systemd/system/ | 低(厂商) | 软件包自带的服务定义 |
三者是"栈式叠加":高优先级文件未定义的项会回落到低优先级文件,而非整体替换。每处目录都可存在 foo.service.d/ 子目录存放 drop-in 片段。
1.3 enable 与 start 是正交的
这是新手最容易混淆的点:
- enable(自启)—— 只在
/etc/systemd/system/下按[Install]段创建符号链接,让单元在开机时被拉起。不启动当前。 - start(运行)—— 立即激活单元,spawn 进程。不改变开机自启设置。
用 systemctl enable --now foo 可一步完成两件事;同理 disable --now = 取消自启 + 停止。
systemctl enable nginx # 只设置开机自启 systemctl start nginx # 只立即启动 systemctl enable --now nginx # 自启 + 立即启动
1.4 定位:systemd 只是 Linux 的主流 init 系统,并非全部
systemctl 只对 systemd 有效。而 Linux 世界并非全员 systemd,Apple 系则是另一套体系。先分清"面前的机器用哪个 init 系统"再选命令,否则会得到 command not found。
| 家族 | 典型系统 | init / 服务管理器 | 说明 |
|---|---|---|---|
| Linux(主流) | Ubuntu / Debian / Fedora / RHEL / Arch / openSUSE | systemd | 覆盖 90%+ 的服务器与桌面发行版 |
| Linux(例外) | Alpine | OpenRC | Docker 官方镜像默认,容器里最常见 |
| Linux(例外) | Gentoo / Void | OpenRC / runit | 极简派发行版 |
| Linux(例外) | Devuan / antiX | SysVinit | 反 systemd 分支,回归传统 init |
| Linux(容器) | 极简镜像 / scratch | 无 init | 由 Docker / Podman 运行时直接管理进程 |
| Apple | macOS / iOS / iPadOS | launchd | 自 Mac OS X 10.4 起统一,无备选 |
Apple 系收敛,Linux 系多元:launchd 是苹果的唯一标准;systemd 只是 Linux 的主流而非全员。选命令前先确认:systemctl(systemd)、rc-service(OpenRC)、service(SysVinit)、launchctl / brew services(macOS)。
systemd 与 launchd 概念对照
| systemd / systemctl | launchd / launchctl | 用途 |
|---|---|---|
systemctl start foo | brew services start foo(写 plist 后 launchctl bootstrap) | 启动服务 |
systemctl enable foo | plist 中 RunAtLoad=true(开机自启) | 开机自启 |
systemctl status foo | brew services list / launchctl list | 查看状态 |
单元文件 /etc/systemd/system/foo.service | plist ~/Library/LaunchAgents/*.plist | 服务定义 |
journalctl -u foo | launchd / 系统日志 | 日志 |
brew services 只是 launchd 的封装(写 homebrew.mxcl.<name>.plist 到 LaunchAgents 再用 launchctl 注册);而 systemctl 是 systemd 的 D-Bus 客户端。二者都是"遥控器",一个遥控 launchd,一个遥控 systemd。
2. 行为图(系统"做什么")
2.1 用例图 — systemctl 交互全景
管理员(root)是主要使用角色;普通用户可用 --user 管理自己的用户服务;后台的 systemd 则是这些操作最终作用的被控制对象。
用例演示
systemctl list-units --type=service --state=running # 列出所有运行中的服务 systemctl status nginx # 查看 nginx 详细状态+最近日志 systemctl daemon-reload # 单元文件改动后重载配置 systemctl set-property nginx.service MemoryMax=2G # 运行时调整资源上限
2.2 活动图 — 服务生命周期主流程
以"启动一个服务 → 观察 → 停止"为主线,展示 systemctl 与 systemd 的职责划分。
用例演示
systemctl start redis.service # 启动 systemctl status redis.service # 观察 active (running) systemctl stop redis.service # 优雅停止(SIGTERM) # 若进程未在 TimeoutStopSec 内退出,systemd 会升级为 SIGKILL
2.3 状态机图 — unit 生命周期
单元在 systemd 眼中的生命周期,对应 systemctl status 里 Active: 一行的取值。
ACTIVE 状态速查
| 状态 | 含义 |
|---|---|
| active | 已启动/绑定/挂载(视单元类型而定) |
| inactive | 已停止/解绑 |
| failed | 启动失败或运行中崩溃(退出码非零、超时、重启次数超限) |
| activating | 从 inactive 走向 active 的过程中 |
| deactivating | 从 active 走向 inactive 的过程中 |
| reloading | active 且正在重载配置 |
2.4 时序图 — systemctl start 内部调用
一次 systemctl start nginx.service,在 systemctl、D-Bus、systemd 与服务进程之间如何流转。
用例演示
# 观察事务中实际入队了哪些 job systemctl start --show-transaction nginx.service # 观察管理器日志(另一终端) journalctl -u nginx.service -f
2.5 活动图 — enable / start / mask 对比
把三者放一起对比,理解它们对"开机自启"和"立即运行"两个维度的影响。
用例演示
systemctl enable nginx # 创建自启符号链接 systemctl disable nginx # 移除自启符号链接(不影响当前运行) systemctl mask nginx # 链接到 /dev/null,任何 start/enable 都失败 systemctl unmask nginx # 解除屏蔽 systemctl is-enabled nginx # 查看自启状态(enabled/disabled/masked/static...)
WantedBy=multi-user.target,表示 enable 时在对应 target 的 .wants/ 目录建符号链接;WantedBy vs RequiredBy 分别对应软依赖(失败不影响 target)与硬依赖。
3. 结构图(系统"由什么组成")
3.1 部署图 — systemd 生态
systemctl 只是 systemd 生态众多管理工具中的一个,它们围绕 D-Bus 总线协作。
用例演示
systemctl list-machines # 列出本机与本地容器 systemctl --host=user@host status # SSH 远程管理 systemctl -M container status # 管理容器内服务 systemctl --user status # 管理当前用户服务
3.2 组件图 — systemctl 内部
把 systemctl 进程拆开看:它如何解析你的命令、如何与 systemd 通信、如何读写单元文件。
用例演示
systemctl status /home # 路径自动转换为 home.mount 单元 systemctl status /dev/sda # 设备路径 → dev-sda.device systemctl stop "sshd@*.service" # 通配符匹配所有 sshd@.service 实例 systemctl edit nginx.service # 打开编辑器编辑 drop-in,退出后自动 daemon-reload
.service(如 systemctl start sshd ≡ sshd.service);glob 匹配:单元命令支持 fnmatch 通配符;编辑调用:systemctl edit 通过 $SYSTEMD_EDITOR / $EDITOR / $VISUAL 选择编辑器(默认 fallback:editor→nano→vim→vi)。
3.3 包图 — 命令分组
systemctl 的全部命令可归为七大类,便于记忆与检索。
归类速记
| 分组 | 代表命令 | 作用 |
|---|---|---|
| Unit Commands | list-units / status / start / stop / set-property / kill | 单元的运行时管理 |
| Unit File Commands | list-unit-files / enable / mask / edit / set-default | 单元文件的安装与自启 |
| Job Commands | list-jobs / cancel | 任务队列管理 |
| Environment Commands | show-environment / set-environment | 管理器环境变量块 |
| Manager State Commands | daemon-reload / daemon-reexec / log-level | 管理器自身状态 |
| System Commands | is-system-running / poweroff / reboot / suspend | 整机电源与运行级别 |
| Machine Commands | list-machines | 容器与机器 |
3.4 类图 — 对象模型
理解 systemctl / systemd 背后的核心抽象:Manager、Unit、Job、UnitFile 及其关系。
用例演示
systemctl show nginx.service -p MainPID -p ActiveState # 读属性(脚本友好) systemctl show nginx.service --value -p ExecStart # 只输出值 systemctl list-dependencies nginx.service # 递归列出依赖 systemctl list-dependencies --reverse nginx.service # 谁依赖它
4. 配置文件语法规范
单元文件(unit file)是 systemd 的"声明式配置",写对了才能跑稳。规范分三层:文件结构、值格式、每段的指令语义。本节是实战的基础,所有 service / timer / socket 的排查都从这里开始。
4.1 单元文件结构
单元文件由若干段(section)组成,段内是键=值对。段名写在方括号里且大小写敏感,# 或 ; 开头是注释,空行忽略,键=值 可用反斜杠续行。
结构演示
# /etc/systemd/system/myapp.service [Unit] Description=My Application Server # [Unit] 通用段:描述、依赖、排序 After=network-online.target Wants=network-online.target [Service] # [Service] 服务特有段:执行、类型、重启 Type=simple ExecStart=/usr/local/bin/myapp --port 8080 Restart=on-failure User=www-data [Install] # [Install] 安装段:enable 时如何被拉起 WantedBy=multi-user.target
enable 使用;[Service] / [Timer] / [Socket] 等是各类型特有的段。`--full` 编辑主文件;普通 systemctl edit 只追加 drop-in。
4.2 值格式与占位符
先掌握值格式,再看指令才不会读错配置。
| 类型 | 格式 | 示例 |
|---|---|---|
| 时间(duration) | 数字+单位,可组合;单位 us/ms/s/min/h/d;infinity 永不超时 | 30s、1min 30s、2h、500ms、infinity |
| 大小(size) | 数字+单位,可带小数;K/M/G/T(以 1024 计,也可 KB/MB 表示 1000 计) | 10M、1.5G、512K |
| 布尔 | yes/no/on/off/true/false/1/0 | PrivateTmp=yes |
| 信号/退出码 | 数字或 SIGxxx / 常量名 | Restart=on-failure、SuccessExitStatus=SIGUSR1 |
说明符(specifier)— 模板单元的核心
在单元文件值里,%X 会被替换为运行期信息,常用于模板单元 foo@.service(用 systemctl start foo@bar 实例化,实例名即 bar):
| 说明符 | 含义 |
|---|---|
%n | 完整单元名(如 foo@bar.service) |
%N | 未转义前的完整单元名 |
%p | 前缀名(去掉 @实例 和 .service,即 foo) |
%P | 未转义的前缀名 |
%i | 实例名(模板单元中就是 @ 后那段,即 bar) |
%j | 实例名的非转义形式 |
%t | 运行时目录(/run 或 $XDG_RUNTIME_DIR) |
%h | 用户家目录 |
%u | 运行用户 |
%H | 主机名 |
%% | 转义出一个字面 % |
# getty@tty1.service 的 [Service] ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear %I $TERM # %I 实例名 tty1
@(如 getty@.service),本身不可运行,须实例化为 getty@tty1.service 等;实例名用于区分多个同名服务,配合 %i 展开。
4.3 [Unit] 段 — 描述、依赖与排序
这是最容易写错的部分。依赖决定"要不要拉起来",排序决定"谁先谁后",两者是正交的。
| 指令 | 类别 | 说明 |
|---|---|---|
Description= | 描述 | 一行说明,显示在 systemctl status 的标题里 |
Documentation= | 描述 | 文档 URL 或 man: 页面(status 里可跳转) |
After= / Before= | 排序 | 只保证先后顺序,不自动拉入依赖 |
Wants= | 软依赖 | 尽量启动;目标启动失败不影响本单元 |
Requires= | 硬依赖 | 必须一起启动;依赖失败则本单元启动失败 |
Requisite= | 硬依赖 | 依赖未激活则不启动本单元(但不主动拉起) |
BindsTo= | 强绑定 | 依赖停止/重启,本单元也随之停止/重启 |
Conflicts= | 互斥 | 与本单元互斥,启动我即停它 |
PartOf= | 从属 | 父单元停止/重启时带动本单元 |
OnFailure= / OnSuccess= | 回调 | 失败/成功时触发另一个单元(如报警、清理) |
StartLimitIntervalSec=StartLimitBurst= | 限速 | 单位时间内允许启动次数,超限则拒绝(配合 StartLimitAction=) |
RefuseManualStart= | 保护 | yes 时禁止手动 start/stop |
RequiresMountsFor= | 挂载依赖 | 自动为路径对应的挂载点建依赖与排序 |
Requires=/Wants= 与 After= 成对使用。只写 Requires= 不写 After=:会拉起但可能并行(不保证先就绪);只写 After= 不写依赖:保证顺序但不会自动拉起。
4.4 [Service] 段 — 命令与类型
4.4.1 执行命令
| 指令 | 说明 |
|---|---|
ExecStart= | 启动命令(必要;Type=oneshot 可省略) |
ExecStartPre= / ExecStartPost= | 启动前/后的钩子命令 |
ExecCondition= | 条件命令,非零退出则跳过启动(不算失败) |
ExecStop= | 停止命令(默认发 SIGTERM 给主进程) |
ExecReload= | 重载命令(systemctl reload 触发) |
ExecStart 前缀修饰符(放在命令最前面):
| 前缀 | 含义 |
|---|---|
- | 该命令失败/不存在也不计入失败(如 ExecStart=-/usr/bin/optional.sh) |
+ | 以 root 全特权执行,无视 User=/CapabilityBoundingSet= |
! | 提升到(受限的)root 权限执行 |
@ | 把可执行文件路径作为 argv[0] 传入(脚本解释器场景) |
: | 环境变量不展开、前缀不解析(字面执行) |
变量展开:$FOO 只展开一次(传给子进程仍保留字面量);${FOO} 在传给子进程前先替换为值。用 ${FOO} 更符合预期。
4.4.2 Type — systemd 如何判定"启动完成"
| Type | 完成判定 | 适用场景 |
|---|---|---|
simple | 主进程一 fork 出就算 active | 最常见;进程不通知就绪 |
exec | ExecStart 的 exec() 成功即 active | 比 simple 更严谨(exec 失败即失败) |
forking | 主进程 fork 出子进程并退出后 active | 传统 daemonize 的守护进程(配合 PIDFile=) |
oneshot | 命令执行完即 active,随后变 inactive | 一次性任务(脚本、初始化),配 RemainAfterExit=yes 保持 active |
dbus | 服务在 BusName= 上注册后才 active | D-Bus 服务 |
notify | 服务通过 sd_notify(READY=1) 上报就绪 | 支持 sd_notify 的应用,最可靠 |
idle | 等所有任务排队完成后再启动(输出不混行) | 交互/串口服务 |
# forking 经典写法(老式守护进程) [Service] Type=forking PIDFile=/run/daemon.pid ExecStart=/usr/sbin/daemon -d ExecReload=/bin/kill -HUP $MAINPID # notify 推荐写法(现代服务,自身支持 sd_notify) [Service] Type=notify NotifyAccess=all ExecStart=/usr/local/bin/server
4.5 [Service] 段 — 重启策略、身份与沙箱
4.5.1 退出与重启
| 指令 | 说明 |
|---|---|
Restart= | 重启策略,见下表 |
RestartSec= | 重启前等待时间(如 RestartSec=3),建议配退避 |
TimeoutStartSec= / TimeoutStopSec= | 启动/停止超时(默认 90s);停止超时会 SIGKILL |
TimeoutSec= | 同时设置上述两者 |
SuccessExitStatus= | 额外视为成功的退出码/信号 |
RemainAfterExit= | oneshot 执行完仍保持 active |
WatchdogSec= | 启用硬件看门狗,服务须周期性 sd_notify(WATCHDOG=1) |
| Restart= 值 | 何时重启 |
|---|---|
no | 永不自动重启(默认) |
on-success | 干净退出(码 0 或 SuccessExitStatus)时 |
on-failure | 非零退出码、信号杀死、超时、watchdog 触发时(最常用) |
on-abnormal | 被信号、超时、watchdog 终止时(不含非零退出码) |
on-abort | 非干净信号导致异常退出时 |
on-watchdog | watchdog 超时未喂狗时 |
always | 任何退出都重启(包括正常退出) |
4.5.2 身份与工作环境
| 指令 | 说明 |
|---|---|
User= / Group= | 以指定用户/组运行(默认 root) |
SupplementaryGroups= | 附加组 |
Environment= | 单行设置环境变量(可写多行) |
EnvironmentFile= | 从文件读 KEY=VALUE;路径前加 - 表示文件缺失不报错 |
WorkingDirectory= | 工作目录(~ 相对 User 家目录) |
UMask= / Nice= | 默认 umask / 调度优先级 |
StandardOutput= / StandardError= | stdout/stderr 去向(默认进 journal,可 journal/file:/null) |
4.5.3 资源限制与沙箱
| 指令 | 说明 |
|---|---|
LimitNOFILE= / LimitNPROC= 等 | rlimit 资源上限(infinity 不设限),常见坑:服务句柄不够 |
CPUWeight= / MemoryMax= | cgroup 资源控制(Weight 相对权重,Max 硬上限) |
PrivateTmp=yes | 私有 /tmp(每个实例独立,安全) |
PrivateDevices= / PrivateNetwork= | 隔离 /dev、网络命名空间 |
ProtectSystem=full|strict | 根目录只读;strict 连 /etc /usr 也只读 |
ProtectHome=yes | /home /root /run/user 不可读 |
ReadOnlyPaths= / ReadWritePaths= | 指定目录只读/读写 |
NoNewPrivileges=yes | 禁止通过 setuid 提权 |
SystemCallFilter= | 系统调用白/黑名单(seccomp) |
[Service] User=www-data EnvironmentFile=-/etc/myapp.env # 缺失也不报错 LimitNOFILE=65535 PrivateTmp=yes ProtectSystem=full ProtectHome=yes NoNewPrivileges=yes Restart=on-failure RestartSec=3 TimeoutStopSec=30
4.6 [Install] 段 — 开机自启
只在 systemctl enable 时读取,决定"开机时被谁拉起",与运行无关。
| 指令 | 说明 |
|---|---|
WantedBy=multi-user.target | enable 时在 multi-user.target.wants/ 建软链接(软依赖,最常见) |
RequiredBy= | 建到 .requires/(硬依赖) |
Also= | enable 本单元时一并 enable 其他单元(如配套 timer) |
Alias= | 为本单元建立别名符号链接 |
DefaultInstance= | 模板单元无显式实例时的默认实例名 |
[Install] WantedBy=multi-user.target # 开机进入多用户模式时自动启动 Also=myapp.timer # enable myapp.service 时顺带 enable 定时器
4.7 其他单元类型段
[Timer] — 定时器(cron 替代)
| 指令 | 说明 |
|---|---|
OnCalendar=*-*-* 03:00:00 | 日历式定时(每周一 Mon *-*-* 09:00:00、每小时 *:00:00) |
OnBootSec=5min | 开机后 N 时间触发 |
OnUnitActiveSec=1h | 目标单元上次激活后 N 时间触发(循环) |
Persistent=yes | 关机期间错过的触发,开机后补执行 |
AccuracySec=1min | 允许的执行误差(省电合并唤醒) |
RandomizedDelaySec= | 随机延迟避免惊群 |
Unit= | 到点激活的目标单元(默认同名 .service) |
[Socket] — 套接字(按需启动)
| 指令 | 说明 |
|---|---|
ListenStream= | TCP 端口或 UNIX 套接字路径 |
ListenDatagram= | UDP |
Accept=yes | 每连接实例化一个服务实例(否则首次连接即拉起服务) |
Service= | 被激活的服务(默认同名 .service) |
SocketMode= | UNIX 套接字权限 |
[Path]、[Mount]、[Slice]
| 段 | 关键指令 | 说明 |
|---|---|---|
[Path] | PathExists= / PathChanged= / DirectoryNotEmpty= | 文件/目录出现或变化时触发服务 |
[Mount] | What= / Where= / Type= / Options= | 声明挂载点(文件名即 Where 转义后的路径.mount) |
[Slice] | CPUWeight= / MemoryMax= | 资源分组,可在 service.slice 上聚合配额 |
4.8 drop-in 覆盖与优先级
不要直接改厂商自带的 /usr/lib/systemd/system/*.service。用 drop-in 追加覆盖:
# 方法一:systemctl edit(自动创建并打开编辑器,保存后自动 daemon-reload) systemctl edit myapp.service # 方法二:手工创建 sudo mkdir -p /etc/systemd/system/myapp.service.d sudo tee /etc/systemd/system/myapp.service.d/override.conf <<'EOF' [Service] Environment=APP_ENV=production RestartSec=5 EOF sudo systemctl daemon-reload
叠加规则(栈式):同一键的取值按目录优先级取最高者,目录优先级 /etc > /run > /usr/lib;同一目录内按文件名排序,后者覆盖前者。要清空某个在低优先级文件里设置的键,赋空值即可:
# override.conf —— 清掉上游设置的 User [Service] User=
systemctl daemon-reload 重载管理器,否则运行的是旧配置;改完用 systemctl cat myapp.service 确认生效后的合并结果;用 systemd-analyze verify /etc/systemd/system/myapp.service 做语法/依赖校验,能在启动前发现 80% 的笔误。
5. 实战速查手册
5.1 查询与状态
| 命令 | 说明 |
|---|---|
systemctl / systemctl list-units | 列出内存中已加载的单元(默认只显 active/失败) |
systemctl list-units --all | 包含未激活单元 |
systemctl list-unit-files | 列出磁盘上所有单元文件及 enable 状态 |
systemctl --type=service --state=failed | 只列失败的服务 |
systemctl status <unit> | 单元详情 + 最近日志(-n 控制行数) |
systemctl status PID | 按 PID 找它属于哪个单元 |
systemctl show <unit> -p <prop> | 读取机器可解析属性 |
systemctl cat <unit> | 打印单元文件内容(fragment + drop-ins) |
systemctl is-active <unit> | 仅判断是否 active(0=是) |
systemctl is-failed <unit> | 仅判断是否 failed(0=是) |
systemctl is-enabled <unit> | 仅判断自启状态 |
systemctl is-system-running | 系统运行状态(running/degraded/...) |
systemctl list-dependencies <unit> | 递归列出依赖树 |
systemctl list-jobs | 当前进行中的 job |
systemctl list-timers | 定时器下次触发时间 |
systemctl list-sockets | 套接字单元监听状态 |
5.2 服务生命周期
| 命令 | 说明 |
|---|---|
systemctl start <unit> | 启动(激活) |
systemctl stop <unit> | 停止(SIGTERM→超时 SIGKILL) |
systemctl restart <unit> | 停止后重新启动 |
systemctl try-restart <unit> | 仅在运行中才重启 |
systemctl reload <unit> | 仅重载服务自身配置(不重启进程) |
systemctl reload-or-restart <unit> | 支持 reload 则 reload,否则 restart |
systemctl kill <unit> -s SIGKILL | 向单元进程发信号(--kill-whom=main/all) |
systemctl reset-failed <unit> | 清除 failed 状态并重置重启计数/速率限制 |
systemctl freeze <unit> / thaw | 用 cgroup freezer 挂起/恢复进程 |
systemctl clean <unit> --what=all | 清除 State/Cache/Logs 等目录数据(需先 stop) |
systemctl isolate <target> | 切换运行级别,停止其余所有单元(危险) |
5.3 开机自启管理
| 命令 | 说明 |
|---|---|
systemctl enable <unit> | 设置开机自启(建符号链接) |
systemctl enable --now <unit> | 自启 + 立即启动 |
systemctl disable <unit> | 取消自启(可加 --now 一并停止) |
systemctl reenable <unit> | disable 后再 enable,重置链接到默认 |
systemctl mask <unit> | 彻底屏蔽(链接到 /dev/null) |
systemctl unmask <unit> | 解除屏蔽 |
systemctl preset <unit> | 按 preset 策略重置自启状态 |
systemctl get-default | 查看默认启动 target |
systemctl set-default multi-user.target | 设置默认启动 target(图形→命令行) |
systemctl edit <unit> | 编辑 drop-in(--full 改主文件,--runtime 只对本次开机) |
systemctl revert <unit> | 撤销 edit / set-property / mask 的改动 |
5.4 系统电源管理
| 命令 | 说明 |
|---|---|
systemctl poweroff | 关机断电 |
systemctl reboot | 重启 |
systemctl halt | 停机但不断电 |
systemctl kexec | 用 kexec 快速重启内核 |
systemctl suspend | 挂起(睡眠) |
systemctl hibernate | 休眠到磁盘 |
systemctl hybrid-sleep | 混合挂起+休眠 |
systemctl rescue | 进入救援模式(单用户) |
systemctl emergency | 进入紧急模式(只挂载根文件系统) |
systemctl reboot --when=21:00 | 定时重启(--when=cancel 取消) |
systemctl poweroff -f | 强制关机(跳过服务关闭,数据可能丢失) |
5.5 环境与属性
| 命令 | 说明 |
|---|---|
systemctl show-environment | 查看管理器环境变量块 |
systemctl set-environment VAR=val | 设置管理器环境变量 |
systemctl unset-environment VAR | 删除管理器环境变量 |
systemctl set-property foo.service CPUWeight=200 MemoryMax=2G | 运行时调整资源控制并写盘持久化 |
systemctl set-property --runtime ... | 同上但仅本次开机有效 |
systemctl daemon-reload | 单元文件改动后重载全部配置与依赖树 |
systemctl daemon-reexec | 重执行 systemd 进程(升级用) |
systemctl log-level debug | 调整 systemd 日志级别(排障用) |
5.6 定时任务与套接字
systemd 的 cron 替代是 timer 单元;按需启动的守护进程用 socket 单元。
创建一个定时任务
# /etc/systemd/system/backup.service [Unit] Description=Daily backup job [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh # /etc/systemd/system/backup.timer [Unit] Description=Run backup daily [Timer] OnCalendar=*-*-* 03:00:00 # 每天凌晨 3 点 Persistent=true # 错过(关机期间)后开机补跑 [Install] WantedBy=timers.target systemctl daemon-reload systemctl enable --now backup.timer systemctl list-timers backup.timer
| 命令 | 说明 |
|---|---|
systemctl list-timers | 查看所有定时器及下次触发 |
systemctl start <name>.timer | 启用某个定时器 |
systemctl list-sockets | 查看套接字单元(如 ssh.socket) |
5.7 日志查看
systemctl 本身不读日志,配合 journalctl 使用:
journalctl -u nginx.service # 该单元全部日志 journalctl -u nginx.service -f # 实时跟踪 journalctl -u nginx.service --since "1 hour ago" journalctl -b -p err # 本次开机以来的错误级日志 journalctl --since today # 今天所有日志 journalctl -f # 实时看全部日志
5.8 新建服务实战
例:把 Go/Python 写的 Web 后端托管为系统服务
sudo tee /etc/systemd/system/myapp.service <<'EOF' [Unit] Description=My Application Server After=network-online.target Wants=network-online.target [Service] Type=notify # 或 simple User=www-data WorkingDirectory=/srv/myapp ExecStart=/usr/local/bin/myapp-server --config /etc/myapp.toml ExecReload=/bin/kill -HUP $MAINPID Restart=on-failure # 崩溃自动拉起 RestartSec=3 LimitNOFILE=65535 EnvironmentFile=-/etc/myapp.env [Install] WantedBy=multi-user.target EOF sudo systemctl daemon-reload sudo systemctl enable --now myapp.service systemctl status myapp.service
改配置的标准流程
systemctl edit myapp.service # 追加 drop-in(不污染原文件) # 或直接改 /etc/systemd/system/myapp.service systemctl daemon-reload # 关键!改完必须重载 systemctl restart myapp.service
5.9 故障排查套路
# 1. 服务起不来 → 看状态与日志 systemctl status myapp.service journalctl -u myapp.service -e # -e 跳到末尾 # 2. 查看系统是否 degraded(有单元失败) systemctl is-system-running systemctl --state=failed # 列出所有失败单元 systemctl list-unit-files --state=enabled # 3. 查看启动耗时,找最慢的服务 systemd-analyze blame systemd-analyze critical-chain # 4. 单元文件语法错误 / 依赖环 systemd-analyze verify /etc/systemd/system/myapp.service systemctl list-jobs --after --before # 看 job 互相等待 # 5. 改完单元文件没生效? systemctl daemon-reload # 十有八九忘了这步 systemctl status myapp.service -n 50 # 看最近 50 行日志
Active: 行是 failed 还是 inactive;再看 Loaded: 行是不是 not-found / masked / error(bad-setting);最后看日志里有没有 Failed to parse、Cannot open、Permission denied。改单元文件后必须 daemon-reload。
4.10 退出码(LSB)
| 值 | systemd 中的含义 |
|---|---|
0 | 单元处于 active / enabled |
1 | 单元 not failed(is-failed 用) |
3 | 单元 not active(is-active 用) |
4 | 不存在该单元 |
非 0 | 操作失败 |