尧图精选

Linux运行级别详解:从SysV init到systemd target的运维实践

🕒 发布时间:2026/9/28 9:09:15 📁 来源:尧图网络
说到 Linux 运行级别runlevel很多人的第一反应是那句面试题常客“Linux 系统有 7 个运行级别。”背答案当然简单但真到运维现场比如误把默认级别改成 0 导致服务器开机就关机或者在 CentOS 7 上打开/etc/inittab发现里面只剩一行注释很多人就懵了。这篇文章我想用实际运维的视角把 runlevel 从原理到配置、从 SysV 到 systemd 完整过一遍适合刚入行的运维、准备 Linux 面试的开发者以及每天跟服务器打交道的系统管理员。读完你不仅知道 7 个级别分别是什么还能安全地改默认级别遇到系统起不来时知道怎么救回来。1. 7个运行级别到底是什么一张表讲清每个级别的真实用途1.1 从0到6每个级别对应的系统状态先上最核心的表格这是整个概念的地基运行级别系统状态典型用途0关机halt/poweroff执行关机流程1单用户模式single user维护、修复、重置 root 密码2多用户模式无 NFS部分发行版带网络Debian/Ubuntu 常用作图形桌面级别3完整多用户文本模式服务器标准运行级别4未使用/保留自定义管理员可自定义服务集5图形化多用户模式X11桌面系统默认级别6重启reboot执行重启流程这里有两个地方最容易出错。第一有些人以为 2 就是“多用户无网络”这个说法只在早期 System V 文档里成立实际很多发行版在 2 级别一样会启动网络服务。比如 Ubuntu/Debian 默认就在 runlevel 2 跑图形桌面网络自然是可用的。第二级别 4 不是“损坏”或者“不可用”它只是没有预置的服务集合给管理员做自定义用的。但正因为没有固定的启动脚本自定义起来维护成本高所以我很少见到有人认真用 4大多数发行版里它就是个空壳。运行级别 0 和 6 最特殊它们不是一个“运行中的系统状态”而是两个系统在退出时执行的动作序列。把 0 或 6 设成默认级别等于让系统一开机就执行关机或重启这种事故我在后面会专门说。1.2 为什么默认是3或5而不是其他级别了解了每个级别对应的状态自然会产生两个问题为什么服务器默认是 3桌面默认是 5级别 2 和级别 4 为什么没人用先解释服务集合的差异。运行级别本质上是一组“要启动的服务”的代号。级别 3 的服务集对应的是 SSH、网络、cron、日志等生产环境需要的服务级别 5 在级别 3 基础上增加了图形登录管理器比如 gdm、sddm、lightdm和 X Window 系统。服务器不装图形界面一方面是省内存和 CPU另一方面是减少攻击面所以默认 3 是完全合理的。桌面环境面向普通用户没有图形登录界面没法用所以默认 5。继续解释为什么不是 1 或 4级别 1 只有最基本的文件系统挂载和少量维护工具连网络和 SSH 都不一定启动没法支撑正常业务级别 4 没有预置服务集意味着你每次装软件包、配服务都要额外处理一套自定义脚本风险大于收益。至于级别 2各发行版定义不统一RHEL/CentOS 把它当作“多用户无 NFS”Ubuntu/Debian 则让它等价于完整多用户跨发行版用 2 容易踩到行为不一致的坑。所以选择默认级别时如果是 Linux 服务器我建议就用 3只有明确要跑图形桌面才用 5。很多编译安装 Linux 发行版时还可以用参数指定默认运行级别比如--with-default-runlevel3不过线上环境一般不会重新编译系统知道这个概念就行。2. 查看与切换别把runlevel、init和who -r搞混2.1 三条命令的区别与正确用法很多新手分不清runlevel、init和who -r到底谁是谁。我用一个最简化的说法帮你记住runlevel是查看工具init是切换工具who -r是带登录会话信息的查看工具。# 查看当前运行级别以及上一次运行级别 $ runlevel N 5输出结果里第一个字符是“上一次的运行级别”第二个是“当前运行级别”。如果你开机后从来没手动切换过上一次会显示为N意思是“没有None”。所以N 5的含义是这个系统从开机起就是 5没有发生过级别切换。who -r的功能类似但输出更啰嗦一点会显示最后一次运行级别变化的时间在排查“系统到底什么时候被切过级别”时很有用$ who -r run-level 5 2025-06-20 09:30切换运行级别则用init后面跟数字。例如从图形界面切到文本模式$ init 3在 SysV 时代telinit是init的替身两者可以互用。很多老教程会写telinit q那是让 init 重读 /etc/inittab 配置这个习惯在排查“改了 inittab 不生效”时依然有价值。这里有个容易出事的细节init 0是关机init 6是重启它们和runlevel 0、runlevel 6完全是两回事。runlevel后面跟数字没有任何作用它只是查询命令。我看到过有新手在键盘上敲出runlevel 0然后盯着屏幕问为什么没关机幸好没关否则还真不知道该怎么解释。2.2 切换运行级别的底层机制init到底做了什么搞清楚命令以后咱们再看一层原理当你敲下init 3系统里到底发生了什么SysV init 是整个系统的 1 号进程它维护当前运行级别状态。收到切换请求后init 会分析新旧级别的差异按顺序先停止那些“新级别里不需要的服务”再启动“新级别里新增的服务”。这个顺序不是随便来的而是由/etc/rc.d/rc3.d或/etc/rc3.d目录下的脚本决定的。目录里的脚本都以K或S开头K代表退出时杀掉killS代表进入时启动start后面的数字表示执行顺序。我用一个生活化的类比运行级别就像公司的一张值班表。新值班表下发后init 先通知表中删除的岗位收拾东西离开K 脚本再让新增岗位的人到位S 脚本顺序由编号决定比如 K01 先执行S99 最后执行。如果新旧表里都有某个服务那它就不动这是为了减少无意义的服务重启。知道这个机制后很多问题就迎刃而解。比如在级别 3 切到级别 5 时如果发现 X 服务没起来可以去检查/etc/rc.d/rc5.d目录下有没有对应的S*脚本如果某个服务永远起不来看看它的启动脚本是否在对应级别目录里有软链接。还有一个经验切换运行级别并不会把“当前本来就运行着的服务”全部停掉再重新拉起只会处理需要变化的服务所以短时间切换对业务的冲击比很多人想象的小但如果某些脚本的依赖顺序写得不好依然可能引起连锁问题。3. 开机默认级别的配置从/etc/inittab到grub的完整链路3.1 传统SysV init的配置方法在 CentOS 6 及更早年代默认运行级别写死在/etc/inittab里。文件里有一行是这个样子的id:3:initdefault:id表示这是设置 init 默认级别的行中间的3就是开机要进入的运行级别initdefault说明它是默认值。修改方法很直接把 3 改成你想要的数字保存然后执行$ init q或者telinit q让 init 重读配置。如果只是改了文件而不执行这条命令当前运行级别不会变化有时重启后倒是会生效但这种“不确定”的状态在运维里最可怕所以还是主动 reload 一下比较好。需要特别提醒的是改/etc/inittab之前一定先备份。别笑这个动作很基础但很重要尤其是当你手头还有一堆rc3.d、rc5.d软链接要处理时万一改错数字导致系统进不去备份能救命。另外有些发行版的 inittab 里还包含了si::sysinit:/etc/rc.d/rc.sysinit、ca::ctrlaltdel:/sbin/shutdown -t3 -r now这类行初学者不要乱动只关注initdefault行就够了。3.2 通过内核参数临时指定运行级别有时候你并不想永久改默认级别只是需要临时进入某个级别去修东西或者系统已经因为配置错误起不来了。这时最可靠的手段是 GRUB 引导时加内核参数。开机看到 GRUB 菜单时按下e进入编辑模式找到以linux或kernel开头的那一行在行尾追加一个数字。比如linux /boot/vmlinuz-... root/dev/mapper/... 3保存并启动系统就会临时以运行级别 3 启动。如果追加的是1或single就会进入单用户模式。这个方法最大的好处是“一次有效”重启后自动恢复原来的默认级别不用事后恢复配置。在 systemd 主导的新系统上对应的内核参数变成了systemd.unitmulti-user.target或者systemd.unitrescue.target。道理是一样的只是单位名称换成了 target。这里要给一个非常实战的建议在云服务器上做这类操作前优先使用云控制台提供的 VNC/远程终端别依赖 SSH。因为单用户模式下网络很可能没有起来你 SSH 一断就真的进不去了而 VNC 相当于坐在物理机前面容错率高很多。3.3 配置默认级别的坑与建议我把这些年见到的默认级别配置事故总结成几条每一条都有真实案例的影子绝对不要把默认级别改成 0 或 6。这个错误我见过不止一次有人为了“测试关机流程”把initdefault改成 0结果服务器一开机就执行关机陷入无限开关机循环。改成 6 就是无限重启循环。遇到这种情况不要慌用 3.2 节的内核参数方法临时进单用户模式改回来即可。改默认级别前先想清楚自己和业务之间的距离。比如远程 SSH 连接的服务器你从 5 切到 3图形服务被停掉SSH 不一定受影响但如果网络服务因为级别变化被重启断开时间可能比想象中长。远程操作时尽量选业务低峰期或者提前确认相关脚本行为。容器、云镜像里可能没有传统 inittab。现在很多容器镜像和云主机初始化模板已经把 init 替换成了 systemd 或自定义 init你打开/etc/inittab看到的可能只是一行注释“This file is no longer used.”。这时候就不要强行改 inittab而是用systemctl set-default类命令或者直接改 GRUB 配置。改完一定要验证不要改完就睡大觉。执行init q后先用runlevel确认当前值再用who -r看切换时间记录在变更记录里。这样出了问题你能快速定位是自己改的还是别人改的。4. systemd时代runlevel还有意义吗4.1 target与runlevel的映射关系CentOS 7、Ubuntu 16.04 之后的系统全面转向 systemd很多教材还在讲/etc/inittab但实际系统里已经找不到 initdefault 行了。这不是 runlevel 概念被抛弃而是被重新包装成了“target”。systemd 官方提供了一套完整的映射关系我整理成了表格传统运行级别systemd target说明0poweroff.target关机1rescue.target单用户/救援模式2multi-user.target多用户文本模式3multi-user.target多用户文本模式4multi-user.target多用户文本模式5graphical.target图形化多用户6reboot.target重启注意看2、3、4 在 systemd 里全部映射到同一个multi-user.target。第一次看到这个表的人觉得奇怪那 2、3、4 的区别去哪了其实在 systemd 的设计哲学里运行级别编号是 System V 时代对“是否启动网络”等差异的硬编码而 systemd 把这些差异拆解成由各个服务自己声明的依赖关系。比如网络服务可以通过Wantsnetwork-online.target来表达依赖不再需要为“带网络的多用户模式”单独分配一个数字编号。这种设计更灵活但也意味着你不能再指望“切到 2 就不启动网络”这种老技巧在新系统上不成立。4.2 systemctl命令替代init命令的对应表理解了映射关系日常命令其实很简单。我列一个常用对照表新手可以直接抄传统操作等价 systemd 命令init 3systemctl isolate multi-user.targetinit 5systemctl isolate graphical.targetinit 0systemctl poweroffinit 6systemctl rebootinit 1systemctl rescueinit qsystemctl daemon-reload修改默认级别systemctl set-default multi-user.target查看默认级别systemctl get-default重点说下isolate这是切换 target 的标准方式。它会把当前 target 里不需要的 unit 全部停止再启动新 target 需要的 unit逻辑上和 SysV init 切换运行级别很像。但要注意不要在远程服务器上无脑执行systemctl isolate poweroff.target这种命令我就见过有人一边开着 SSH 一边练习结果屏幕一黑自己把自己锁在外面。systemctl rescue也有同样的风险它会停掉网络服务远程连接当场失效。4.3 旧脚本在systemd下的兼容性很多老运维刚迁移到 systemd 时最关心的是我以前写的/etc/init.d/xxx start脚本还能用吗还能用但已经开始被“边缘化”了。systemd 默认会读取/etc/init.d里的 SysV 脚本用 systemd-sysv-generator 为它们生成对应的 unit让你可以用systemctl start xxx来管理。但 SysV 脚本没有完整的依赖声明systemd 对它们的管理比较“粗放”远不如原生 unit 精确。另一个常见兼容点是/etc/rc.local。如果你习惯把自定义命令写在rc.local里在 systemd 系统上需要先确认rc-local.service存在并且是启用状态。我遇到过 CentOS 7 最小化安装后rc.local没有执行权限导致开机脚本静默失效的案例排查了半天才发现是/etc/rc.d/rc.local少了x权限。这类问题在旧系统上不会出现因为 init 会直接执行 rc.local 脚本这是很多老手踩的第一个 systemd 坑。还有chkconfig命令在 CentOS 7 上虽然还留着但官方建议用systemctl enable/disable。如果你管理的是 CentOS 6 和 CentOS 7 混编的机器群最好让自己习惯“看到 runlevel 首先翻译成 target”的思维不然同一套操作在两套系统上容易分叉。5. 实际运维中我踩过的运行级别相关的坑5.1 误设默认级别为0或6的灾难现场有一次我和同事排查一台测试服务器现象是“开机后不到一分钟就自动重启”无限循环。一开始怀疑硬件、怀疑内核 panic查了一圈都没结果。后来我让他把 GRUB 菜单停在编辑界面在 kernel 行加了一个1参数进到单用户模式后打开/etc/inittab一看initdefault那行赫然写着id:6:initdefault:。原来是前一天有人为了练习init命令把配置文件给改了和命令行里敲init 6完全不是一回事。救回来的过程其实不复杂以单用户模式启动后文件系统通常是只读挂载的所以第一步要重新挂载成可写mount -o remount,rw /然后把6改成原来的3或5保存退出重启。这里有个细节如果文件系统是 LVM 或加密卷单用户模式下可能需要手动激活卷组比如执行vgchange -ay否则会看到设备不存在。那次经历之后我养成了一个习惯但凡改/etc/inittab先在文件头部加注释说明原本的值和修改时间比如# default was 3, changed by xxx at 2025-06-20。看似多写一行字关键时候能省很多事。5.2 救援模式与单用户模式的区别很多人把“单用户模式”和“救援模式”混着叫实际上它们不完全一样。传统 SysV 里级别 1 是单用户模式挂载的文件系统有限网络服务不启动而有些发行版还提供“救援模式rescue”和“紧急模式emergency”差别在于启动到哪一步救援模式会尝试挂载所有本地文件系统并启动必要的服务紧急模式只挂载根文件系统几乎不启动任何额外服务。在 systemd 下rescue.target对应的就是传统级别 1emergency.target则更“穷”。实际应用场景区分也很明显忘记 root 密码通常用单用户模式或救援模式重置根文件系统损坏需要修复用紧急模式要恢复网络环境并挂载所有磁盘用救援模式更合适。通过 GRUB 进入时可以加systemd.unitrescue.target或systemd.unitemergency.target而不是只记single这个参数。另外强调一遍这些模式基本都没有网络云服务器在控制台 VNC 里操作才是稳妥方案否则你根本没有输入密码的机会因为连接已经断了。5.3 规范使用运行级别避免影响业务最后聊一下日常规范。运行级别不是给你“试玩”的玩具尤其在线上环境。以下几条是我个人在多次“玩脱”后总结出来的纪律第一切换前先评估网络影响。在 SysV 系统上从级别 5 切到级别 3 不一定会动网络但从级别 3 切到 5 也不一定不动关键是看/etc/rc.d/rc*.d目录下和 network 相关的脚本。你可以提前查ls -l /etc/rc.d/rc3.d/*network /etc/rc.d/rc5.d/*network看到K开头就表示从该级别退出时会停网络S开头则表示进入时会启动网络。如果你远程 SSH 操作又发现切换会重启网络就要考虑是不是换一种不依赖网络服务的切换方式或者干脆在维护窗口执行。第二不要在业务高峰期验证新配置。我见过有人在数据库主库上执行init 3只是为了“看看会不会断网”结果网络真的断了整个应用层瞬间雪崩。运行级别切换不是普通命令请把它当成变更流程来走申请窗口、备份配置、准备回滚方案、执行后验证。第三升级到 systemd 后尽量用 target 而不是继续用数字习惯。虽然init 3在很多新系统上还能用但那只是为了兼容新脚本里写systemctl isolate multi-user.target可读性更好别人看代码也更容易理解。把运行级别的知识当作“底层原理”理解把 target 当作“当前产品”使用这两者并不矛盾。我自己的体会是运行级别这个概念在 Linux 里已经存在了几十年就算 systemd 把它包装成了 target理解它依然能帮你快速看懂服务启动的依赖关系也能在旧系统和新系统之间来回切换时游刃有余。新手不用急着背命令先在自己的虚拟机里试试从默认级别切到 3再切回 5看看服务变化再改一次默认级别并重启验证。跑通一遍之后那些知识点才真正是你的。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →