跳转至

10 - 服务管理与进程控制(systemd)

前提条件

  • 已完成第一阶段所有内容(基础部署、apt 源、SSH 安全加固、fail2ban 等)
  • 以 root 身份登录,或 ops 用户执行 sudo -i 切换至 root 环境
  • 系统运行在 Debian 12 Bookworm,SSH 端口已改为 2222
  • 虚拟机环境:VMware Workstation Pro

全局参数

主机名 linuxdc,IP 192.168.1.100/24,SSH 端口 2222,运维用户 ops

详细步骤

1. systemd 核心概念速览

单元类型 说明 典型示例
service 最常见的服务单元 ssh.servicenginx.service
target 服务组,类似运行级别 multi-user.target(相当于 runlevel 3)
timer 定时任务,替代传统 cron unattended-upgrades.timer
socket 按需激活服务 docker.socket
mount 挂载点管理 /etc/systemd/system/mnt-data.mount

2. 查看系统和服务状态

systemctl status                                         # 当前 target 和整体状态
systemctl get-default                                    # 默认运行级别(通常 multi-user.target)
systemctl list-units --type=service --state=running      # 列出所有运行中的服务
systemctl list-unit-files --type=service | grep enabled  # 列出所有已启用的服务

3. 服务基本操作

# 以 ssh 为例(以下命令均以 root 身份执行)
systemctl status ssh

systemctl start ssh        # 启动
systemctl stop ssh         # 停止
systemctl restart ssh      # 重启(中断现有连接)
systemctl reload ssh       # 平滑重载配置(不中断已有连接)

systemctl enable ssh       # 设置开机自启(创建符号链接)
systemctl disable ssh      # 取消开机自启

# 屏蔽服务(防止被意外启动,优先级高于 enable)
systemctl mask avahi-daemon
systemctl unmask avahi-daemon

注意

在虚拟机内操作时,systemctl stop ssh 会断开当前 SSH 连接。建议通过 VMware 控制台执行,或立即跟上 systemctl start ssh

4. 日志查看与实时跟踪(journalctl)

journalctl -u ssh -n 200                # ssh 最近 200 行日志
journalctl -u ssh -f                    # 实时跟踪(Ctrl+C 退出)
journalctl -u ssh --since "today"       # 今天的所有 ssh 日志
journalctl -b -p warning..emerg         # 本次启动的警告及以上级别日志
journalctl --disk-usage                 # 查看日志磁盘占用
journalctl -b -1 -p err                 # 上次启动的错误日志

日志级别参考:emerg(0) > alert(1) > crit(2) > err(3) > warning(4) > notice(5) > info(6) > debug(7)

5. 创建自定义 systemd 服务

示例:创建一个后台持续运行的日志脚本服务。

创建脚本:

mkdir -p /opt/testservice
vim /opt/testservice/hello.sh

脚本内容:

#!/bin/bash
while true; do
    echo "$(date '+%Y-%m-%d %H:%M:%S') - Hello from systemd service"
    sleep 60
done

赋予执行权限:

chmod +x /opt/testservice/hello.sh

创建服务单元文件:

vim /etc/systemd/system/hello.service

内容:

[Unit]
Description=Simple Hello World Service
After=network.target

[Service]
Type=simple
ExecStart=/opt/testservice/hello.sh
Restart=always
RestartSec=5
User=ops
StandardOutput=append:/var/log/hello.log
StandardError=append:/var/log/hello.log

[Install]
WantedBy=multi-user.target

加载、启动、验证:

systemctl daemon-reload
systemctl enable hello
systemctl start hello
systemctl status hello
tail -f /var/log/hello.log

检查点

systemctl status hello 显示 active (running)tail -f /var/log/hello.log 每 60 秒追加一行带时间戳的输出。

6. 日志清理与维护

journalctl --vacuum-time=30d      # 删除 30 天前的日志
journalctl --vacuum-size=500M     # 将日志总大小压缩至 500 MB 以内
systemctl reset-failed            # 清除所有 failed 状态单元
systemctl reset-failed hello      # 清除指定服务的 failed 状态

实践任务

  1. 查看当前系统所有运行中的服务,找出内存占用最高的前 5 个(提示:systemd-cgtop
  2. 临时停止 ssh 服务,再启动,确认 2222 端口恢复监听(ss -tuln | grep 2222
  3. 创建上述 hello.service 示例服务,启用开机自启,验证日志是否正常写入
  4. journalctl -u hello -f 实时观察服务输出

自测问题

1. systemctl enablesystemctl start 的区别是什么?

systemctl start立即启动服务,效果仅限当前运行时,重启后若未 enable 则不会自动启动。systemctl enable设置开机自启,在 /etc/systemd/system/ 下对应的 .wants/ 目录中创建符号链接,下次启动时 systemd 会自动拉起该服务,但不影响当前运行状态。生产环境通常组合使用:systemctl enable --now ssh(同时设置自启并立即启动)。

2. 如何让服务在网络完全就绪后再启动?

在单元文件的 [Unit] 段中添加:

After=network-online.target
Wants=network-online.target

network.target 仅表示网络配置已应用,不代表网络实际连通;network-online.target 会等待 systemd-networkd-wait-online 确认网络接口真正在线后才触发依赖服务,适合需要在启动时访问外网的服务(如 VPN 客户端、动态 DNS 更新脚本)。

3. journalctl -b -p err 显示的是什么内容?

显示本次系统启动以来,优先级为 err(3)及以上(即 err、crit、alert、emerg)的所有日志条目。这是排查启动问题和服务崩溃的常用命令。-b -1 可查看上次启动的日志,适合排查崩溃重启后的问题根因。

4. 如果一个服务配置了 Restart=always,如何临时停止而不删除文件?

直接 systemctl stop 后,systemd 会检测到服务退出并按 RestartSec 间隔再次拉起。要真正临时停止,需使用 mask:

systemctl mask hello       # 屏蔽服务(阻止任何方式启动)
systemctl stop hello       # 停止当前运行实例
# 恢复时
systemctl unmask hello
systemctl start hello

或先 disable 再 stop(下次重启后不会自启,但当前仍不会被 systemd 自动拉起):

systemctl disable hello
systemctl stop hello

总结

systemd 是 Debian 现代运维的核心,掌握服务状态查看、启动控制、日志追踪和自定义单元是后续所有服务类章节的基础。生产环境中,优先使用 systemctl + journalctl 排查问题,而不是旧的 service 命令或直接翻阅 /var/log 下的文本日志。