4. 常用启动参数详解(中):init、systemd.unit、single、emergency
系统初始化阶段,是内核交棒给用户空间的关键一步。说白了,就是内核启动完,得有人来拉起所有服务、挂载文件系统、配置网络。谁来做这件事?就是 init 进程。这一章我们聊聊跟初始化相关的几个核心参数,都是我平时排查启动故障时最常用的。
4.1 init 参数:指定你的 1 号进程
内核启动的最后一步,会执行 /sbin/init 作为第一个用户态进程(PID 1)。但你可以通过 init= 参数强行指定别的程序。
语法: init=/path/to/program
默认值: /sbin/init(通常是 systemd 的软链接)
我遇到过几次系统因为 /sbin/init 损坏而无法启动的情况。这时候用 init=/bin/bash 直接进一个 shell,就能修复文件系统或者重装软件包。
实用场景:
- 救援模式:
init=/bin/bash或init=/bin/sh - 临时替换 init 系统:比如从 systemd 切到 sysvinit 做测试
- 容器场景:指定自定义的初始化程序
注意: 用 init=/bin/bash 启动后,很多服务不会自动运行。你需要手动挂载 /proc、/sys、/dev,否则很多命令会报错。我曾经吃过这个亏,进去后 mount 都跑不了,折腾了半天才发现没挂 /proc。
4.2 systemd.unit:直接指定启动目标
如果你的系统用的是 systemd(现在绝大多数发行版都是),systemd.unit= 参数可以让你直接指定启动到哪个 target。这比进系统后再 systemctl isolate 要快得多。
| 参数值 | 对应目标 | 说明 |
|---|---|---|
systemd.unit=multi-user.target |
多用户文本模式 | 不启动图形界面,适合服务器 |
systemd.unit=graphical.target |
图形界面模式 | 启动桌面环境 |
systemd.unit=rescue.target |
单用户救援模式 | 基础文件系统挂载,root shell |
systemd.unit=emergency.target |
紧急模式 | 最精简环境,只挂载根文件系统 |
我个人习惯在调试启动问题时,直接在 GRUB 命令行里加上 systemd.unit=rescue.target。这样既能拿到一个可用的 shell,又比 emergency 模式多了一些基础服务(比如网络)。
4.3 single:传统单用户模式
single 参数是 sysvinit 时代的遗产,现在在 systemd 系统上,它会被映射成 rescue.target。用法很简单,直接在内核参数行末尾加上 single 或 1(数字 1 也是同样的效果)。
等价关系:
single→systemd.unit=rescue.target1→systemd.unit=rescue.targets→systemd.unit=rescue.target
嗯,这里要注意:single 模式会提示你输入 root 密码。如果你忘了 root 密码,那就得用 init=/bin/bash 或者 rd.break(针对 dracut 的 initramfs)来绕过了。
4.4 emergency:最后的救命稻草
emergency 参数对应 systemd 的 emergency.target。这是比 rescue 更精简的模式——只挂载根文件系统(只读),不启动任何服务,连网络都没有。你得到的就是一个孤零零的 root shell。
什么时候用 emergency?
- 根文件系统损坏,需要 fsck
- 关键系统服务导致启动死循环
- 需要在不加载任何额外模块的情况下修复系统
我曾经有一次遇到 /etc/fstab 配置错误,导致系统在挂载分区时卡死。用 emergency 进去后,根文件系统是只读的,得先 mount -o remount,rw / 才能修改 fstab。这个细节很多人不知道,进去后直接 vi /etc/fstab 发现保存不了,就懵了。
4.5 各初始化模式的对比
| 模式 | 内核参数 | 根文件系统 | 网络 | 多用户 | 适用场景 |
|---|---|---|---|---|---|
| 正常启动 | (无) | 读写 | ✓ | ✓ | 日常使用 |
| 救援模式 | single / 1 |
读写 | ✗ | ✗ | 修复配置、重置密码 |
| 紧急模式 | emergency |
只读 | ✗ | ✗ | 修复根文件系统、抢救数据 |
| 自定义 init | init=/bin/bash |
取决于脚本 | ✗ | ✗ | 极端修复、init 损坏 |
4.6 实战:用 systemd.unit 跳过故障服务
说个真实案例。有一次我维护的服务器,某个自定义服务在启动时总是 segfault,导致 systemd 不断尝试重启,整个启动过程被拖慢了 5 分钟。怎么快速进系统?
- 重启,在 GRUB 菜单按
e编辑启动项 - 在
linux开头的行末尾加上systemd.unit=multi-user.target - 按
Ctrl+X启动 - 进系统后,用
systemctl disable 故障服务禁用它 - 再正常重启,问题解决
你看,一个参数就绕过了故障点,不用进救援模式那么麻烦。
4.7 知识体系图:初始化参数决策流程
下面这张图总结了不同场景下该选哪个初始化参数。我建议你把它截图保存,或者记在笔记本上——线上出问题时,没时间翻文档。
4.8 避坑指南
最后分享几个我踩过的坑,你遇到了能少走弯路。
- init=/bin/bash 后忘记 remount: 进去后第一件事就是
mount -o remount,rw /,否则所有修改都写不进去。 - single 模式需要 root 密码: 如果你忘了密码,用
rd.break或者init=/bin/bash绕过。 - emergency 模式下没有 /dev: 有些 initramfs 在 emergency 模式下不会自动创建设备节点。如果要用
dd或fdisk,先手动mount -t devtmpfs none /dev。 - systemd.unit= 参数拼写: 是
systemd.unit,不是systemd-unit,也不是systemd_unit。我见过有人因为这个下划线折腾了半小时。
这些初始化参数,说白了就是给你一把钥匙,让你在系统出问题时还能开门进去修。平时多练练,真到线上故障的时候,你就能从容应对了。