AxionserveSign in / RegisterEnglish/中文/cn繁体/tw

第 4 课 · 服务管理:systemd 单元、开机自启、日志

Linux 基础 · L1 · 第 4 / 6 节 · 约 3 分钟

现代 Linux 的服务都由 systemd 统一管理:启动顺序、崩溃拉起、开机自启、日志归集——学会 systemctl 与 journalctl 两个命令,你就掌握了服务器上所有服务的「生老病死」。

服务生命周期管理示意

概念三分钟:unit、service、target

systemd 管理的一切对象叫 unit(单元),配置文件在 /etc/systemd/system/(自己写的)与 /lib/systemd/system/(软件包带的)。最常用的 unit 类型是 .service(服务);.timer(定时任务,cron 的现代替代)与 .target(运行级别组)了解即可。服务的状态机:inactive(停)→ active/running(跑)→ failed(挂了)。

systemctl:五个动词覆盖日常

systemctl status nginx      # 状态总览:在不在跑、PID、最近日志、开机自启否
systemctl start nginx       # 启动
systemctl stop nginx        # 停止
systemctl restart nginx     # 重启(reload 是不断连接重读配置,支持的服务优先用 reload)
systemctl enable --now nginx  # 开机自启 + 立即启动(--now 一步到位)
systemctl disable nginx     # 取消自启(list-unit-files --type=service 看全部自启清单)

journalctl:日志的时间机器

systemd 把服务日志统一收进 journal——按服务、按时间、按优先级检索:

journalctl -u nginx --since "1 hour ago" | tail -50   # 某服务最近一小时
journalctl -u nginx -f                                 # 实时追踪(等效 tail -f)
journalctl -p err -b                                   # 本次开机的所有错误级日志
journalctl --disk-usage                                # journal 占用(可配置上限防吃盘)

传统日志文件(/var/log/syslog、应用自己的日志)仍在——journal 是补充不是替代,两边都学会查。

写一个最小 service:把你的脚本变成服务

# /etc/systemd/system/mybot.service —— 让一个脚本开机自启+崩溃自动拉起
[Unit]
Description=My background bot
After=network-online.target          # 等网络就绪再启动

[Service]
ExecStart=/usr/local/bin/mybot.sh    # 启动命令(绝对路径)
Restart=on-failure                   # 异常退出自动拉起
RestartSec=5
User=mybot                           # 专用低权限用户运行(别用 root)

[Install]
WantedBy=multi-user.target

# 生效三步:
systemctl daemon-reload              # 重载 unit 定义(改过文件就要跑)
systemctl enable --now mybot
systemctl status mybot && journalctl -u mybot -n 20

这个模板覆盖了托管脚本的八成需求;User= 一行是安全习惯:服务用专用低权限用户跑,被攻破时的损失面小一个量级。

服务起不来:四步定位

# ① 状态里的退出码与最后几行日志(八成的答案直接写在这)
systemctl status mybot -l | tail -15
# ② 手动前台跑一次启动命令(错误直接打到脸上)
sudo -u mybot /usr/local/bin/mybot.sh
# ③ 检查 unit 语法与路径(相对路径/权限/依赖顺序是三大常见错)
systemd-analyze verify /etc/systemd/system/mybot.service
# ④ 端口冲突类:目标端口被谁占了
ss -tlnp | grep :端口号

与 cron 的分工

定时任务两条路线:传统 cron(crontab -e,一行一任务,简单直接)与 systemd timer(unit 化,有日志、有依赖管理、错过可补跑)。经验口径:简单定时用 cron 不丢人,需要日志归集与失败重试的用 timer——两者的任务都要进你的运维文档,「机器上到底跑了什么定时任务」必须可回答。

依赖顺序:After 与 Wants 的语义差

unit 文件里的依赖有两个容易混淆的关键字:After/Before 只管顺序(网络就绪后再启动我),Requires/Wants 管绑定(它挂了/停了怎么办)。常用组合是 After=network-online.target + Wants=network-online.target——既等网络又声明需要它;Requires 比 Wants 强(被依赖方故障会连带停你),日常服务用 Wants 足够,滥用 Requires 会把小故障放大成连锁停机。改完 unit 文件必须 systemctl daemon-reload 再操作服务——忘了这一步,systemd 还在用旧定义,「我明明改了怎么不生效」的第一嫌疑人。

服务加固:unit 里的安全选项

systemd 自带一层服务沙箱能力,写进 [Service] 段即可,成本几乎为零:User=/Group=(低权限身份运行,前一课讲过);NoNewPrivileges=true(进程及其子进程永远不能获得新特权——挡掉一类提权路径);ProtectSystem=strict + ReadWritePaths=(文件系统只读,只开放它必须写的目录);PrivateTmp=true(私有 /tmp,与其他服务隔离);Restart=on-failure + RestartSec=5(崩溃拉起但别无限快循环)。逐项加、每加一项 systemctl restart 验证服务仍正常——加固与可用性的平衡就是这样一小步一小步试出来的;这套选项的完整文档在 man systemd.exec,值得通读一遍目录。

本节小结

  • systemctl 五动词(status/start/stop/restart/enable)管理服务生命周期,reload 优于 restart;
  • journalctl -u 服务名是查日志的第一入口,-f 实时追、-p err 看错误级;
  • 自建 service 三要素:After 依赖、Restart 拉起、User 低权限——起不来按四步定位。