🐧 第05章 · 系统启动与引导
Systemd 启动流程 systemctl enable
系统启动与引导¶
服务器开机后到底发生了什么、为什么有的服务开机自启有的没有、为什么启动卡在某一秒?这一章梳理从 BIOS/UEFI 到 systemd 的完整引导流程,并教你用 systemd-analyze 定位启动慢点、管理多目标(target)。
开机流程:从固件到 systemd¶
一台 Ubuntu 24.04 服务器(BIOS/UEFI + GRUB + systemd)的启动链条:
BIOS/UEFI 固件
→ 读取 GRUB 引导程序(如 /boot/grub)
→ GRUB 加载内核(vmlinuz)与 initramfs
→ 内核解压,接管硬件
→ 启动 init(第一个进程),systemd 的 PID=1
→ systemd 并行拉起各服务
→ 达到默认 target,登录提示符出现
| 阶段 | 谁来干 | 出问题表现 |
|---|---|---|
| 固件自检 | BIOS/UEFI | 卡 Logo、黑屏 |
| 引导程序 | GRUB | Grub 菜单、initrd not found |
| 内核启动 | vmlinuz + initramfs | 内核 panic、找不到根盘 |
| 服务拉起 | systemd | 某服务报 failed、卡在 [ OK ] 某步 |
易错 内核与 initramfs 放在
/boot(本机/dev/sda16,913M)。initramfs里含有加载根文件系统所需的驱动(如 ext4、virtio),如果把/boot写满或删了内核版本,重启就会进 rescue 模式 —— 对/boot的操作必须谨慎。
systemd 的核心概念:unit 与 target¶
Systemd 用 unit 统一管理所有"开机要干的事"。常见 unit 类型:
.service—— 服务(如nginx.service);.target—— 目标/启动级别(如multi-user.target);.socket、.timer、.path—— 套接字激活、定时器、路径触发。
systemctl list-units --type=service --state=running # 正在运行的 service
systemctl list-unit-files --type=service | grep enabled # 开机自启的 service
易错
systemctl list-units默认只显示"已加载/活动"的 unit,看不到已禁用的;要看全部自启设置(含 disabled/static)必须用list-unit-files。
开机自启:default target 与 enable¶
systemd 开机会启动到"默认 target"。Ubuntu 桌面版默认 graphical.target(GUI),服务器版默认 multi-user.target(纯终端)。
systemctl get-default # 查看默认 target
systemctl set-default multi-user.target # 设为纯命令行(服务器常见)
systemctl isolate multi-user.target # 立即切换到该 target
第 4 章说过 systemctl enable 设置开机自启——它的本质是建立符号链接,把 unit 链接进某个 target 的 .wants/ 目录:
# enable 背后做了什么(以多用户 target 为例)
ls /etc/systemd/system/multi-user.target.wants/ | grep -i nginx
# 会看到 nginx.service -> /lib/systemd/system/nginx.service 的软链接
enable / disable 就是增删这些链接。mask 则更彻底(链接到 /dev/null)。
定位启动慢点:systemd-analyze¶
服务能不能快速起来、卡在哪一步,用 systemd-analyze 分析:
systemd-analyze time # 内核与用户空间各花了多少
systemd-analyze blame # 按启动耗时排序,看谁拖慢了
systemd-analyze critical-chain # 关键链:谁阻塞了启动
systemd-analyze blame | head # 只看最慢的几项
易错
systemd-analyze读的是上一次启动的数据(存于 journal 里),刚重启后立刻看数字可能是 0。blame结果的单位是ms(毫秒),xxx.ms即 0.xxx 秒。
启动日志与失败排查¶
服务开机启动失败,看 journal 的 boot 级日志:
journalctl -b # 本次开机以来的日志
journalctl -b -p err # 只看错误级别
journalctl -b -u bangdream # 开机启动 bangdream 这一段
journalctl -b -u nginx -e # 时间从早到晚,-e 跳到尾部
journalctl --list-boots # 列出所有历史开机记录
journalctl -b -1 -u mysql # 看上一次开机的 mysql 日志(-1)
提示 服务启动了但立刻 failed,先看
journalctl -u <服务> -e的报错,再systemctl reset-failed <服务>清除失败状态(否则status一直显示 failed 影响判断),最后systemctl start重试。
救援与紧急模式¶
系统开机进不去(fstab 写错、关键服务挂了),进 rescue / emergency 模式修复:
systemctl rescue # 进入救援模式(单用户,少服务)
systemctl emergency # 进入紧急模式(最小环境,几乎不含服务)
在 GRUB 菜单按 e 编辑内核行,在 ro quiet splash 后追加 systemd.unit=rescue.target 或 systemd.unit=emergency.target 也能强制进入。此时挂载根分区读写,修复 /etc/fstab 等即可。
易错
emergency模式几乎不加载任何服务,连fsck和手动命令都可能受限。能进rescue就先用 rescue;emergency是最后手段。修复完exec /sbin/init或systemctl reboot重启。
案例:服务没有开机自启,重启后 Nginx 不见了¶
systemctl is-enabled nginx # 确认是否为 enabled
systemctl enable --now nginx # 设为自启并立即拉起
# 验证
systemctl is-active nginx && reboot -n # 可选:重启后确认
易错 排查"重启后服务没起来",先
systemctl status看是不是enable漏了,再看journalctl -b -u <服务>是不是启动时报错。很多"服务没自启"其实是启动时报错失败,不是没 enable。
案例:启动卡顿排查(本机示例)¶
假设本机开机偏慢,用 blame 定位:
systemd-analyze blame | head -10
# 常见大头:networkmanager 几十秒 或 某个挂载等待、Redis 初始化等待
# 针对网络等待可考虑把不需要立刻联网的服务改为 不依赖 network-online.target
易错点¶
/boot写满或删内核:直接进不了系统。- 改 fstab 不
mount -a验证:重启卡 rescue。 list-units看不出"没自启"的服务:用list-unit-files。blame读的是上一次启动数据:刚重启完数字为 0。
相关命令¶
systemctl、systemd-analyze、journalctl、systemctl-get-default、systemctl-set-default、systemctl rescue、lsblk、grub-editenv。