>

适合读者:会基本 Linux 命令(cd、ls、cat),第一次接触 systemd。
> 全文命令默认需要 root 权限(前面加 sudo),为简洁起见不再逐条重复。
> 本文在 Ubuntu 22.04 / Debian 12 上验证,RHEL 9 / CentOS Stream / Rocky / Alma 以及树莓派 OS 上完全通用。


一、什么是 systemd?为什么现代 Linux 都离不开它?

1.1 一句话版本

systemd 是现代 Linux 的"总管家":开机时它是第一个运行的程序(PID 1,“init 系统”),负责启动并管理其余一切——后台服务(service)、定时任务(timer)、日志(journal)、网络、DNS、时间同步、用户会话……你日常听到的"开机自启"“服务管理”“查系统日志”,基本都是它的事。

1.2 它是怎么成为主流的?

老系统的 init 是 SysVinit:一堆 /etc/init.d/ 下的 shell 脚本加 runlevel,串行启动,慢且难维护。systemd 在 2010 年前后陆续取代它,如今主流发行版早已"全员换装":

发行版systemd 成为默认
Ubuntu15.04 起
Debian8(jessie)起
RHEL / CentOS7 起(RHEL 8/9、CentOS Stream、Rocky、Alma 同理)
openSUSE13.2 起
Arch自始即然
树莓派 OS(Raspberry Pi OS)自始即然(Debian 血统)

换句话说:只要你的系统是近 10 年发布的,开机跑的就是 systemd。 学它不是可选项,是必修课。

1.3 systemd 管什么?

管理对象对应组件 / 单元你日常的操作
后台服务*.service 单元systemctl start/stop/status
定时任务*.timer 单元(配合 service)systemctl list-timers
日志journald → /var/log/journal/journalctl -u xxx -f
DNS 解析systemd-resolved一般不用碰
时间同步systemd-timesyncd一般不用碰
网络配置systemd-networkd轻量服务器 / 嵌入式常用
登录会话systemd-logindloginctl
开机阶段*.target 单元(如 multi-user.target)systemctl get-default

1.4 核心概念:单元(Unit)

systemd 把"一切可以被管理的东西"抽象成单元(unit),每个单元由一个 INI 风格的单元文件描述。常见类型:

后缀名称用途
.service服务单元后台常驻进程 / 一次性任务
.timer定时器单元按时间触发另一个单元(cron 的替代)
.socket套接字单元有连接进来才拉起服务(socket 激活)
.target目标单元一组单元的集合 / 开机阶段(multi-user.target = 多用户模式)
.mount / .automount挂载单元管理挂载点
.path路径单元文件变化时触发
.slice / .scope资源单元CPU / 内存等资源限制

单元文件放哪里?(查找优先级从高到低)

  • /etc/systemd/system/ —— 你自己写的,系统更新不会动。本文所有自定义文件都写在这里。
  • /usr/lib/systemd/system/(部分发行版为 /lib/systemd/system/)—— 软件包安装时带过来的。
  • /run/systemd/system/ —— 运行时临时生成,重启即失。
>

经验法则:软件包自带的单元在 /usr/lib/...,自己写的放 /etc/systemd/system/。同名时 /etc 下的会覆盖系统自带的(这也是"改官方服务行为"的正规做法:systemctl edit xxx 会帮你生成 override)。


二、service 服务单元:逐行拆解

2.1 写第一个自定义服务

假设你有个小服务 myapp,可执行文件在 /opt/myapp/myapp(示例路径,按你的实际程序改)。

先建一个非 root 的运行用户(好习惯,下文 User= 会用到):

sudo useradd -r -s /usr/sbin/nologin myapp   # 建一个不能登录的系统用户
sudo mkdir -p /opt/myapp

然后写单元文件:

sudo vim /etc/systemd/system/myapp.service

文件内容(先贴全量,下面逐段、逐行讲):

# /etc/systemd/system/myapp.service
# systemd 服务单元文件:INI 风格,分三段 [Unit] [Service] [Install]

# ============ [Unit] 元信息段:这个单元"是什么" ============
[Unit]
Description=myapp 示例服务                     # 一句话描述,status/list 里会显示
Documentation=https://example.com/myapp        # 文档链接(可选,纯展示)
After=network.target                           # 启动顺序:排在这个 target 之后
Wants=network.target                           # 弱依赖:需要网络,但缺了我也能启动

# ============ [Service] 运行段:进程"怎么跑" ============
[Service]
Type=simple                                    # 进程模型:simple = systemd 直接拉起的进程
User=myapp                                     # 以 myapp 用户身份运行(别用 root)
Group=myapp                                    # 运行用户组
WorkingDirectory=/opt/myapp                    # 启动前先 cd 到这个目录
Environment=APP_ENV=production APP_PORT=8080   # 环境变量(空格分隔的 KEY=VALUE)
ExecStart=/opt/myapp/myapp --config /opt/myapp/config.yaml
#ExecStop=/opt/myapp/myapp --stop              # 可选:自定义停止命令;不写则默认发 SIGTERM
Restart=on-failure                             # 异常退出(非 0 退出码/被信号杀死)时自动重启
RestartSec=5                                   # 两次重启之间等 5 秒
StandardOutput=journal                         # stdout 进 journal(默认值,可不写)
StandardError=journal                          # stderr 同理

# ============ [Install] 安装段:开机自启"装在哪" ============
[Install]
WantedBy=multi-user.target                     # enable 时挂到多用户模式 target

2.2 逐行拆解

[Unit] 段 —— “它是什么”

字段含义说明
Description=单元描述给人看的,systemctl status / list-units 里显示
Documentation=文档 URL可选,纯展示
After=启动顺序表示"我在这个 target 之后启动"。注意:只保证先后顺序,不产生依赖、也不等它真正完成
Wants=弱依赖拉起目标;目标挂了我不受牵连
Requires=强依赖拉起目标;目标挂了我也跟着停
BindsTo=绑定依赖比 Requires 更狠:目标停了,我立刻被停
>

新手建议:After=network.target + Wants=network.target 是最常见的组合;真要"等网络可用",见第七节坑 #10。

[Service] 段 —— “它怎么跑”

字段含义
Type=进程模型,见下表
ExecStart=启动命令,必须是绝对路径,可带参数;这是单元的核心
ExecStop=停止命令(可选);不写则默认发 SIGTERM,10 秒后 SIGKILL
ExecReload=systemctl reload 时执行的命令(可选)
User= / Group=以哪个用户/组运行;省略就是 root(不推荐)
WorkingDirectory=启动前 cd 到的目录
Environment=环境变量,多个用空格分隔
EnvironmentFile=从文件读环境变量;写成 -EnvironmentFile=/path 表示文件不存在也不报错
Restart=no(默认)/ always / on-success / on-failure / on-abnormal
RestartSec=重启间隔(秒)
StandardOutput= / StandardError=输出去向:journal(默认)/ syslog / file:/path / null / inherit

Type= 常见取值:

取值含义典型场景
simple(默认)systemd fork 出进程,主进程就是 ExecStart 那个绝大多数常驻服务
exec同 simple,但 fork 失败会报 failed想严格检测"进程到底起没起"
forking程序自己 fork 成守护进程老式 xxx -D 启动的程序
oneshot跑一次就结束备份、清理、升级脚本(配合 timer 用)
notify程序通过 sd_notify 告知"我准备好了"支持 systemd 通知协议的程序
idle同 simple,但等别的任务启动完再启动想让开机其他服务先走
>

拿不准就用 simple(常驻)或 oneshot(跑一次就完),覆盖 90% 场景。

[Install] 段 —— “开机自启装在哪”

字段含义
WantedBy=systemctl enable 时,把本单元的软链建到该 target 的 .wants/ 目录下,从而实现开机自启
>

没有 [Install] 段的单元无法被 enable(很多 socket 激活单元、静态单元就是这样,它们由别的单元顺带拉起)。

2.3 让改动生效并启动

sudo systemctl daemon-reload   # 重新读取所有单元文件(每次改完单元文件都要跑!)
sudo systemctl start myapp     # 现在立即启动
systemctl status myapp         # 看一眼状态

三、systemctl 常用命令速查表

3.1 命令速查

命令作用例子
systemctl start <unit>立即启动(不改变开机自启状态)systemctl start myapp
systemctl stop <unit>立即停止systemctl stop myapp
systemctl restart <unit>重启(stop + start;没在跑也会先启动)systemctl restart nginx
systemctl reload <unit>重载配置、不断连接(需单元支持 ExecReload=)systemctl reload nginx
systemctl status <unit>状态:在跑吗、PID、是否 enable、最近 10 行日志systemctl status myapp
systemctl enable <unit>设置开机自启(建软链,不启动当前进程)systemctl enable myapp
systemctl disable <unit>取消开机自启(不影响正在运行的进程)systemctl disable myapp
systemctl is-enabled <unit>查是否已 enable:enabled / disabled / static / maskedsystemctl is-enabled myapp
systemctl is-active <unit>查是否正在运行:active / inactive / failedsystemctl is-active myapp
systemctl daemon-reload重读单元文件(改完 .service/.timer 必跑)—
systemctl list-units列出运行中的单元(默认只显示 active 的)systemctl list-units --type=timer
systemctl list-unit-files列出磁盘上所有单元文件及 enabled/disabled 状态systemctl list-unit-files --state=enabled
systemctl enable --now <unit>enable + start 一步到位systemctl enable --now myapp
systemctl mask <unit>彻底封禁(任何方式都起不来,比 disable 狠)systemctl mask getty@tty1
systemctl unmask <unit>解除 masksystemctl unmask getty@tty1
systemctl reset-failed清除 failed 状态,让单元可以再次 startsystemctl reset-failed myapp
journalctl -u <unit> -f实时跟踪该单元日志journalctl -u myapp -f

3.2 重点:enable 和 start 是两回事!

这是新手最常搞混的点,务必分清:

startenable
作用此刻把进程拉起来把单元注册进开机自启列表(在 target 的 .wants/ 目录建软链)
影响范围只影响本次开机(重启后失效,除非 enable 了)影响下次及以后每次开机
立即生效?是否(不启动任何进程)
文件层面无(纯运行时操作)创建/删除 /etc/systemd/system/multi-user.target.wants/myapp.service 软链

由此推出三条常用组合:

  • 装完服务,想"现在就跑 + 以后开机也跑" → systemctl enable --now myapp
  • 只想临时跑一次 → systemctl start myapp
  • 只取消开机自启、服务继续跑 → systemctl disable myapp(重启后不再启动)

3.3 读懂 status 输出

● myapp.service - myapp 示例服务
     Loaded: loaded (/etc/systemd/system/myapp.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2025-01-06 09:00:01 CST; 2h 5min ago
   Main PID: 1234 (myapp)
     Memory: 8.2M
        CPU: 432ms
     CGroup: /system.slice/myapp.service
             └─1234 /opt/myapp/myapp --config /opt/myapp/config.yaml

Jan 06 09:00:01 srv systemd[1]: Started myapp 示例服务.
Jan 06 09:00:01 srv myapp[1234]: listening on :8080
  • Loaded: loaded (路径; enabled; ...) —— 单元文件在哪、是否已 enable;
  • Active: active (running) since ... —— 正在运行、从何时开始;若为 failed,往下找日志;
  • 末尾几行 = 该单元最近的日志(完整日志用 journalctl -u myapp)。

四、timer 定时单元:让任务"定时自动跑"

4.1 timer vs cron

维度cronsystemd timer
配置位置/etc/crontab、crontab -e/etc/systemd/system/*.timer
日志默认丢进 syslog,难追溯自动进 journal,journalctl -u 一查一个准
错过任务错过就错过(部分发行版靠 anacron 补救)Persistent=true:错过后开机补跑一次
随机延迟没有RandomizedDelaySec= 原生支持,多机错峰
查看下次执行时间只能自己推算systemctl list-timers 直接显示
依赖管理无和普通单元一样支持 After/Requires
>

cron 依然可用,两者不冲突;但新系统上写新任务,推荐 timer。

4.2 例子:每天凌晨 3:00 跑备份脚本

timer 由一对文件组成:*.timer 定义"什么时候“,同名的 *.service 定义”干什么"。

/etc/systemd/system/backup.service(干什么):

[Unit]
Description=每日数据备份(由 backup.timer 触发)

[Service]
Type=oneshot                       # 跑一次就结束——备份类任务的标准选择
User=backup
ExecStart=/opt/backup/backup.sh    # 绝对路径
WorkingDirectory=/opt/backup

/etc/systemd/system/backup.timer(什么时候):

[Unit]
Description=每天凌晨 3:00 触发备份

[Timer]
OnCalendar=*-*-* 03:00:00     # 每天 03:00:00(本地时区)触发
Persistent=true                # 到点时机器没开/没运行?下次开机补跑一次
RandomizedDelaySec=300         # 在计划时间上随机延迟 0~300 秒,避免多机同一秒抢资源
#OnBootSec=10min               # (可选)开机后 10 分钟触发一次,不管时钟几点
#OnUnitActiveSec=1h            # (可选)距上次激活 1 小时后再次触发

[Install]
WantedBy=timers.target          # 启用时挂到 timers.target

4.3 timer 字段逐行拆解

字段含义备注
OnCalendar=按墙上时钟(日历时间)触发语法见下表;默认本地时区,需要 UTC 可写 OnCalendar=UTC ...
OnBootSec=按开机后经过的时间触发例 OnBootSec=10min = 开机 10 分钟后
OnUnitActiveSec=按上次激活后经过的时间触发循环任务常用,例 OnUnitActiveSec=1h = 每隔 1 小时
Persistent=true 时:错过的那次任务,下次开机补跑一次仅对 OnCalendar 有意义;防止"到点关机 = 任务丢失"
RandomizedDelaySec=触发前加 0N 秒随机延迟备份/同步类任务推荐,天然错峰
AccuracySec=触发精度窗口(默认 1 秒),systemd 在窗口内挑时机一般不用动

一个 timer 可以同时写多个 OnXxx= 字段:满足其中任意一个就触发。

4.4 OnCalendar 时间表达式表

语法(比 crontab 更自由):[周] [月]-[日] [时]:[分]:[秒],任意位置可用 *。

表达式含义
*-*-* 03:00:00每天 03:00
Mon *-*-* 02:30:00每周一 02:30
Mon,Wed,Fri *-*-* 09:00:00每周一、三、五 09:00
*-*-1 00:00:00每月 1 号 00:00
*-*-1,15 00:00:00每月 1 号和 15 号
*-*-06 03:00:00每月 6 号 03:00
Jan-01 00:00:00每年 1 月 1 日 00:00
*-*-* 00:00:00;12:00:00每天 00:00 和 12:00(分号分隔多个时间)
UTC *-*-* 00:00:00UTC 时区的午夜
>

记忆法:*-*-* 就是"每月每天";周几写在最前面,不写就是"每天"。
> 注意:周几和日期同时限定时满足其一即触发(cron 语义),一般别这么写,容易踩坑。

4.5 启用与查看

sudo systemctl daemon-reload                # 新单元文件,先 reload
sudo systemctl enable backup.timer          # 开机自启(重启后自动开始计时)
sudo systemctl start backup.timer           # 让当前开机的计时立刻生效(不重启也要跑就加这条)
systemctl list-timers                       # 列出所有 timer 及上次/下次触发时间
systemctl status backup.timer               # 看这个 timer 的状态

list-timers 输出示例(假设今天是 1 月 5 日周日 08:30):

NEXT                          LEFT          LAST                         PASSED      UNIT            ACTIVATES
Mon 2025-01-06 03:00:00 CST   18h           Sun 2025-01-05 03:00:04 CST  5h ago      backup.timer    backup.service
>

两个细节:

>
  • timer 只负责"按点按铃",真正干活的是同名 service——timer 名字决定它触发哪个 service(backup.timer → backup.service),不需要显式写 Wants=。
  • >
  • 手动测试:sudo systemctl start backup.service。oneshot 服务跑完即止,不用等明天 3 点就能验证脚本——这正是 Type=oneshot 的妙处。

五、journalctl:systemd 的日志中枢

5.1 journal 是什么

  • systemd 自带日志守护 journald:所有服务(stdout/stderr 重定向到 journal 的)、内核消息、登录事件,全部汇总进 journal。
  • 二进制存储,位置:/var/log/journal/(持久,重启保留);/run/log/journal/(内存,重启即失)。
  • 查询工具就是 journalctl。

5.2 常用命令速查

命令作用
journalctl看全部日志(进入分页器,q 退出)
journalctl -u myapp只看 myapp 这个单元的日志
journalctl -u myapp -f实时跟踪 myapp 日志(Ctrl+C 退出),效果类似 tail -f
journalctl -u myapp --since "2 hours ago"最近 2 小时的日志
journalctl -u myapp --since today --until "12:00"今天 0 点 ~ 12 点
journalctl -u myapp -p err只看 err 级别及以上(err / crit / alert / emerg)
journalctl -n 50只看最后 50 行
journalctl --no-pager不进分页器、直接全量打印(方便接 \| grep 管道)
journalctl -b只看本次开机以来的日志
journalctl -b -1看上一次开机的日志(排查"重启后才挂的"利器)
journalctl --disk-usagejournal 一共占了多少磁盘
journalctl --vacuum-time=7d只保留最近 7 天的日志
journalctl --vacuum-size=200M把 journal 总量压到 200M 以内
journalctl -g "关键词"全文搜索(二进制层 grep,很快)
journalctl -t mytag按 syslog 标识过滤,非 systemd 启动的程序也适用

时间参数很好认,直接写人话:"yesterday"、"2025-01-06"、"2025-01-06 03:00" 都可以。

5.3 和 tail /var/log/xxx.log 的区别

维度journalctltail /var/log/xxx.log
来源所有进 journal 的东西(服务、内核、登录)集中一处只有该程序自己写进文件的那部分
按服务过滤-u 单元名,精确得先知道它把日志写到哪个文件
按时间过滤--since / --until 内置文件无统一时间戳格式时只能肉眼扫
按级别过滤-p err没有
跨重启持久化在 /var/log/journal看程序自己是否轮转/保留
实时跟踪-ftail -f
对程序的要求什么都不用做,往 stdout/stderr 打就行程序必须主动写文件
存储格式二进制(可压缩、可限额)纯文本
>

实践建议:systemd 时代的主流写法是程序只往 stdout/stderr 打日志,全部交给 journal 统一收;传统 /var/log/*.log 依然并存,老程序照查不误。


六、完整实战:备份脚本 → 开机可重启、定时自动跑、日志可查

目标:把 /opt/backup/backup.sh(把 /data 备份到 /backup)做成——

  • 可以 systemctl start 手动跑;
  • 每天凌晨 3:00 自动跑,错过就开机补跑;
  • 日志随时 journalctl -u backup 查。

Step 0:写备份脚本

sudo mkdir -p /opt/backup /backup
sudo tee /opt/backup/backup.sh > /dev/null <<'EOF'
#!/usr/bin/env bash
# 每天备份 /data 到 /backup,只保留最近 7 份
set -euo pipefail

SRC=/data
DEST=/backup
DATE=$(date +%F_%H%M)
TAR="${DEST}/data_${DATE}.tar.gz"

echo "[backup] 开始备份 ${SRC} -> ${TAR}"
tar -czf "$TAR" -C "$(dirname "$SRC")" "$(basename "$SRC")"
echo "[backup] 完成:${TAR}($(du -h "$TAR" | cut -f1))"

# 只保留最近 7 份(没有旧文件时不报错)
if ls -1t "${DEST}"/data_*.tar.gz >/dev/null 2>&1; then
  ls -1t "${DEST}"/data_*.tar.gz | tail -n +8 | xargs -r rm -f
  echo "[backup] 已清理旧备份"
fi
EOF
>

用 vim 手动建文件完全可以,上面的 tee + heredoc 只是为了方便整段复制粘贴。注意脚本往 stdout 打日志——这正是 journal 能收到的原因。

Step 1:赋执行权限 + 建运行用户(新手第一大坑!)

sudo chmod +x /opt/backup/backup.sh                # 必须可执行,否则 ExecStart 报 Permission denied
sudo useradd -r -s /usr/sbin/nologin backup        # 专用运行用户
sudo chown -R backup:backup /opt/backup /backup    # 目录归它,读写才不报权限错误
sudo chmod 750 /opt/backup

Step 2:写 service 单元

sudo tee /etc/systemd/system/backup.service > /dev/null <<'EOF'
[Unit]
Description=每日数据备份

[Service]
Type=oneshot                    # 一次性任务:跑完即止
User=backup
WorkingDirectory=/opt/backup
ExecStart=/opt/backup/backup.sh # 绝对路径!
EOF

Step 3:写 timer 单元

sudo tee /etc/systemd/system/backup.timer > /dev/null <<'EOF'
[Unit]
Description=每天 03:00 触发数据备份

[Timer]
OnCalendar=*-*-* 03:00:00   # 每天凌晨 3 点
Persistent=true              # 错过补跑
RandomizedDelaySec=120       # 最多随机延迟 2 分钟,错峰

[Install]
WantedBy=timers.target
EOF

Step 4:加载并启用

sudo systemctl daemon-reload          # 改过单元文件,必须 reload
sudo systemctl enable backup.timer    # 开机自启(重启后自动开始计时)
sudo systemctl start backup.timer     # 当前开机立即生效(不等重启)

Step 5:验证

# 5.1 手动跑一次(验证脚本 + 权限 + 路径)
sudo systemctl start backup
systemctl status backup
# oneshot 跑完显示 "Active: inactive (dead)" 属正常,重点看日志和退出码

# 5.2 看这次跑的日志
journalctl -u backup --no-pager | tail -20
# 应看到:[backup] 开始备份 ... [backup] 完成 ... [backup] 已清理旧备份

# 5.3 看定时器排期
systemctl list-timers backup.timer
# NEXT 应显示明天的 03:00:xx(含最多 120 秒随机延迟)

# 5.4 实时跟踪(另开一个终端,再执行一次 systemctl start backup)
journalctl -u backup -f

Step 6:日常运维动作

场景命令
改了 backup.sh,想马上跑一次systemctl start backup
改了 .service / .timer 文件systemctl daemon-reload && systemctl restart backup.timer
临时停用定时器(不卸载)systemctl stop backup.timer(彻底停用用 disable)
改备份时间改 OnCalendar= → daemon-reload → systemctl restart backup.timer
查最近一次跑没跑成功systemctl status backup;journalctl -u backup --since "3 hours ago"

✅ 到此,你的备份任务已经做到:开机自启计时、定时自动跑、错过可补跑、失败可查日志。


七、常见坑与避坑表

#坑症状原因解决
1改了单元文件没 daemon-reload改了 Restart=、User= 等不生效systemd 还在用内存里的旧配置改完必跑 systemctl daemon-reload(养成肌肉记忆)
2ExecStart 路径错/拼错start 立刻 failed,journal 里 No such file or directoryExecStart 必须是存在的绝对路径,解释器也要绝对路径先 ls -l /path/to/binary 核对;用 journalctl -u xx 看具体报错
3脚本没 chmod +xfailed,journal 里 Permission deniedExecStart 直接执行该文件,需要 x 权限chmod +x 脚本;或写成 ExecStart=/bin/bash /path/script.sh(不依赖 x 位)
4enable 了但服务没在跑is-enabled 显示 enabled,is-active 却是 inactiveenable 只管开机,不会启动当前正在运行的系统里的服务systemctl start;或一开始就用 enable --now
5服务"秒退"status 显示 inactive (dead),日志只有一行Type=simple 的进程正常退出就结束了;oneshot 更是如此常驻服务:看 journal 查进程为何退出;一次性任务:本来就该配 timer
6权限不足(User= 非 root)写文件 Permission denied、目录不可读以服务用户身份跑,但目录/文件还归 root 所有用对 User=,并 chown 好相关目录;别在服务里读写 /root 下的东西
7日志刷得太快journal 占满磁盘 / 日志被丢弃并提示 Rate limit hit循环里疯狂 print;journald 有频率限制(默认约 30 秒 1 万条)降低日志级别;journalctl --vacuum-time=7d 定期清;确需高频再调 journald 的 RateLimit 配置
8timer 到点没跑list-timers 正常,但任务没执行机器到点时关机了,且没开补跑加 Persistent=true(开机补跑);并确认 timer 已 enable + start
9oneshot 的 status 看不太懂Active: inactive (dead),以为是挂了oneshot 跑完就是 dead,这是正常看退出码和 journal;想让它显示"保持 active",加 RemainAfterExit=yes
10写了 After=network.target 启动时还是没网服务启动瞬间 DNS 解析失败、连接被拒After= 只保证顺序,不等网络真正就绪(network.target 只是顺序锚点)脚本里做重试;或 Wants=network-online.target + After=network-online.target 等真正就绪
11单元被 mask 过怎么都起不来systemctl mask 比 disable 狠,软链指向 /dev/nullsystemctl unmask xxx
12RHEL 系 SELinux 拦路日志 Permission denied,ls -lZ 看到上下文警告SELinux 上下文不匹配临时 setenforce 0 验证;长期用 chcon / restorecon 或自定义策略

三条黄金排查习惯

  • systemctl status <unit> —— 先看第一屏(Loaded / Active / 最近日志);
  • journalctl -u <unit> --no-pager | tail -50 —— 看完整报错;
  • 任何单元文件改动后,systemctl daemon-reload —— 无脑执行。

八、systemd 生态速览(一句话版)

组件一句话作用
systemd(PID 1)总控:服务、目标、开机流程都归它管
systemd-journald日志中枢:收集所有单元/内核日志存进 journal,journalctl 查询
systemd-resolvedDNS 解析器:提供本地 stub 127.0.0.53,统一管理 /etc/resolv.conf(Ubuntu 18.04 起默认启用)
systemd-timesyncd轻量 NTP 客户端:用 SNTP 同步系统时间(RHEL 系默认 chronyd,功能等价)
systemd-networkd网络配置守护:用 /etc/systemd/network/*.network 管理网卡/路由/DHCP,轻量机器上 NetworkManager 的替代品
systemd-logind管理用户登录会话,loginctl 查会话、做电源操作
systemd-hostnamed主机名/时区/部署环境,hostnamectl 改主机名
systemd-oomd内存不足时按策略杀进程,防止整机卡死
>

新手记忆:日常 99% 只用 systemctl + journalctl;resolved / networkd / timesyncd 知道"系统里这些服务是干嘛的"即可,真要配置再查对应 man 页(man systemd-resolved 等)。


写在最后:把今天的知识串一遍

  • systemd = 现代 Linux 的总管家,一切皆单元(.service / .timer / .target …);
  • 写服务:/etc/systemd/system/xxx.service 三段式——[Unit] 是什么、[Service] 怎么跑、[Install] 挂哪个 target;
  • 命令口诀:start 管现在,enable 管开机,status 看状态,journalctl 查日志,改文件必 daemon-reload;
  • 定时任务:xxx.timer(OnCalendar 定时间、Persistent 防错过)+ 同名 xxx.service(Type=oneshot 干活);
  • 日志:journalctl -u xxx -f 实时跟踪,--since / -p 精确定位,比翻 /var/log 爽得多;
  • 排错三板斧:status → journalctl → daemon-reload。

(完)

— 感谢阅读 —

一起交流

分享你的思考,让讨论更进一步。