Linux 运维与安全专家 07 · 服务管理与 systemd

第 7 章 · 服务管理与 systemd

阶段 B预计 5–6 小时Ubuntu/Rocky 一致

「服务器常用服务怎么管理」的完整答案:启动/停止/重启/开机自启、查服务日志、手写服务配置、定时任务。Ubuntu 和 Rocky 都用 systemd,本章命令两系统完全通用,学一遍顶两遍。

7.1systemd 是什么:进程 1 与「服务的操作系统」

7.2systemctl 全家桶(背熟 = 服务管理通关)

终端 · 日常操作
sudo systemctl start nginx       # 启动(本次生效)
sudo systemctl stop nginx        # 停止
sudo systemctl restart nginx     # 重启(改配置后常用)
sudo systemctl reload nginx      # 热重载配置(不中断连接,Nginx 推荐)
sudo systemctl enable nginx      # 开机自启(永久)
sudo systemctl disable nginx     # 取消开机自启
sudo systemctl enable --now nginx   # 自启 + 立即启动(二合一)
systemctl status nginx           # 状态 + 最近日志 + 是否自启
systemctl is-active nginx        # active/inactive(脚本判断用)
systemctl is-enabled nginx       # enabled/disabled
systemctl list-units --type=service --state=running   # 所有运行中的服务
systemctl list-unit-files | grep nginx   # 服务文件与自启状态
sudo systemctl daemon-reload    # 新增/修改 unit 后必须执行!
enable 与 start 的区别(新手必懂) start = 现在启动;enable = 开机启动(创建软链接)。两者独立:可以「只启动不自启」(临时跑一下)或「自启但现在没跑」(下次开机才起来)。服务器上装完服务标准操作:enable --now。

7.3journalctl:服务日志统一入口

systemd 把服务输出统一收进 journal 日志(二进制,比散文件更好查):

终端 · journalctl 实战
journalctl -u nginx              # 某服务全部日志
journalctl -u nginx -f           # 实时跟踪(-f follow,排障最爱)
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -p err       # 只看错误级别(-p 级别过滤)
journalctl -b                    # 本次开机以来的日志(-b -1 上次开机)
journalctl --disk-usage          # 日志占多少空间
journalctl --vacuum-time=7d      # 清理 7 天前日志
sudo journalctl -xeu nginx       # 故障经典组合:-x 附说明 -e 跳到末尾

传统文本日志仍在:/var/log/(syslog、nginx 自己的 access/error log),两者共存。规律:systemd 收服务启动错误,/var/log 收服务业务日志,排障时都看。

7.4手写 unit:把任意程序变成受管服务

你从 GitHub 下了一个程序,想让它开机自启、崩溃自动重启、日志统一管理 —— 写一个 unit 文件即可。示例(app 服务):

/etc/systemd/system/app.service
[Unit]
Description=My App Service          # 描述
After=network.target postgresql.service   # 在哪些目标/服务之后启动
Wants=network.target                # 需要的目标(弱依赖)

[Service]
Type=simple                        # simple/forking/oneshot,见下
User=webapp                        # 以哪个用户运行(绝不跑 root!)
Group=webapp
WorkingDirectory=/opt/app
ExecStart=/opt/app/bin/app-server --config /etc/app.conf   # 启动命令
Restart=on-failure                 # 崩溃自动重启(always/on-failure)
RestartSec=3                       # 重启等待秒数
Environment=NODE_ENV=production    # 环境变量
LimitNOFILE=65535                  # 文件句柄上限(高并发应用)

[Install]
WantedBy=multi-user.target         # 开机自启挂到多用户目标
终端 · 启用新服务
sudo systemctl daemon-reload            # 让 systemd 认识新文件(必做)
sudo systemctl enable --now app
systemctl status app
journalctl -u app -f                    # 看它是否正常跑起来

Type 三选一:simple(前台进程,最常见);forking(启动后 fork 到后台,用 PIDFile 指明);oneshot(执行一次就结束,适合初始化脚本)。判断:看程序是前台阻塞式运行(simple)还是自动 daemonize(forking)。

7.5开机自启原理(enable 干了什么)

systemctl enable app 的本质:在 /etc/systemd/system/multi-user.target.wants/ 下创建指向 unit 文件的软链接。删除该链接即 disable。你完全可以手动管理这个目录,但命令更稳。

7.6定时任务:cron / systemd timer / at 怎么选

工具适用示例
cron日常周期任务(每天/每周/每月),最常用crontab -e 编辑:0 3 * * * /opt/backup.sh
systemd timer需要精确控制、依赖管理、错过补跑的周期任务写 .timer 文件,更「systemd 化」,进阶用
at一次性定时(几点几分跑一次)echo "sh /opt/x.sh" | at 14:30
终端 · cron 五分钟上手
crontab -e                    # 编辑当前用户任务(首次选编辑器,推荐 nano)
crontab -l                    # 查看
crontab -r                    # 清空(慎用)
# 格式:分 时 日 月 周  命令
#   0 3 * * *   每天 3:00 执行备份
#   */10 * * * *   每 10 分钟
#   0 2 * * 1   每周一 2:00
# 日志:grep CRON /var/log/syslog(Rocky: /var/log/cron)
cron 三条坑 ① cron 环境变量极少(没有你 .bashrc 里的 PATH),命令写绝对路径或开头 PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin;② 输出重定向到日志文件(>> /var/log/mytask.log 2>&1),否则静默失败找不到原因;③ 脚本先手动执行成功再挂 cron。

7.7服务排障五步(万能套路)

  1. 看状态:systemctl status 服务 —— active/failed、最近几行日志、主进程 PID。
  2. 看日志:journalctl -u 服务 -n 50 --no-pager,找 error/denied/not found 关键词。
  3. 手动跑:sudo 服务启动命令 在前台执行,错误会直接打在屏幕(很多服务支持 nginx -t 之类测试命令先验配置)。
  4. 查权限与端口:配置文件权限、端口占用 ss -tlnp | grep 端口(第 8 章)。
  5. 改配置→daemon-reload→restart:改 unit 或配置文件后规范顺序:daemon-reload(改 unit 时)→ restart → 再看 status 与日志确认。
「Failed to start」常见真凶 端口被占(换端口或停掉旧服务)、配置文件语法错(先跑 命令 -t 测试)、权限不足(User= 没有写日志目录权限)、依赖服务没起来(看 After= 与 systemctl status 依赖)、SELinux 拦截(Rocky,ausearch -m avc 查,第 9 章)。

7.8老命令兼容:service / chkconfig / /etc/init.d

老教程里的 service nginx start、chkconfig nginx on 在 systemd 时代只是兼容层(会转成 systemctl)。看到老命令别慌:service 服务 start 等价 systemctl start 服务。直接学 systemctl 即可,老命令认识就好。

本章自测题

  1. start 和 enable 的区别?装机后标准动作是什么?
  2. 改完 unit 文件后必须执行什么命令?
  3. 实时看 nginx 服务日志用什么?看错误级别日志呢?
  4. 写一个 app.service 的关键字段:以用户 webapp 运行、崩溃自动重启、开机自启,写出完整文件与启用命令。
  5. Type=simple 和 forking 分别适合什么程序?
  6. cron 格式「每天凌晨 3 点备份」「每 10 分钟检查」怎么写?cron 常见三个坑是什么?
  7. 服务 failed 后你的排查顺序是什么?
参考答案
1. start 现在启动;enable 开机自启(建软链接);标准动作 systemctl enable --now 服务。
2. systemctl daemon-reload。
3. journalctl -u nginx -f;journalctl -u nginx -p err。
4. [Service] 里 User=webapp、Restart=on-failure、ExecStart=/opt/app/bin/app;[Install] WantedBy=multi-user.target;然后 daemon-reload + enable --now。
5. simple 前台常驻程序;forking 自己转后台的守护型程序(配 PIDFile)。
6. 0 3 * * * /opt/backup.sh;*/10 * * * * /opt/check.sh。坑:环境变量少(用绝对路径)、输出要重定向留痕、先手动验证脚本。
7. status → journalctl 日志 → 前台手动跑/配置测试 → 查端口权限 → 修配置后 daemon-reload+restart。