2、SysV Init运行级别:0-6运行级别的定义与切换机制

聊到SysV Init,运行级别是个绕不开的话题。我刚开始接触Linux系统管理那会儿,觉得这玩意儿挺玄乎的——不就是个数字嘛,0到6七个数字,能玩出什么花来?后来在生产环境里栽过跟头,才明白这七个数字背后藏着大学问。

2.1 运行级别到底是什么?

说白了,运行级别就是Linux系统的一组预设状态。每个状态决定了系统启动后跑哪些服务、不跑哪些服务。你想想看,一台服务器在单用户模式下修故障,跟它在多用户模式下对外提供服务,需要的服务集合肯定不一样。

SysV Init用0到6这七个数字来定义这些状态。嗯,这里要注意——虽然数字是0到6,但实际可用的运行级别其实更多,只是约定俗成用这七个。我见过有些老系统还自定义了8、9级别,不过那是极少数情况。

2.2 0-6运行级别的标准定义

咱们先看一张表,把每个级别的含义搞清楚:

运行级别 名称 功能描述 典型用途
0 关机 停止所有服务,关闭系统 安全关机
1 单用户模式 仅root用户,无网络,最小化服务 系统修复、密码重置
2 多用户模式(无NFS) 多用户文本界面,无网络文件系统 Debian系默认多用户级别
3 完整多用户模式 多用户文本界面,带网络服务 服务器标准运行级别
4 未使用/自定义 保留给用户自定义 特殊场景定制
5 图形化多用户模式 多用户文本界面 + 图形界面 桌面系统默认级别
6 重启 停止所有服务,重启系统 安全重启

这张表看着简单,但实际用起来坑不少。我记得有一次,同事在RHEL 6上把默认运行级别改成了0,结果服务器一开机就关机……嗯,这种低级错误其实挺常见的。

2.3 运行级别的切换机制

运行级别切换,核心靠的是init进程。当你在终端敲下init 3或者telinit 3时,init进程会做三件事:

  1. 读取/etc/inittab:找到目标运行级别对应的配置
  2. 终止旧服务:停止当前级别特有的服务
  3. 启动新服务:启动目标级别需要的服务

具体怎么操作?看个例子:

# 查看当前运行级别
runlevel

# 切换到运行级别3(文本多用户模式)
init 3

# 或者用telinit,效果一样
telinit 3

# 查看切换后的状态
runlevel

输出结果一般是这样的:

N 5    # 之前是5,现在还是5(没切换)
5 3    # 之前是5,现在切换到了3

这里有个细节——runlevel命令显示的是上一个当前的运行级别。第一个字母是N,表示没有上一个级别(刚开机)。

2.4 服务启动与停止的脚本机制

运行级别切换时,服务怎么启停?这就要说到/etc/rc.d/目录下的脚本了。每个运行级别对应一个子目录:

/etc/rc.d/rc0.d/   # 关机级别
/etc/rc.d/rc1.d/   # 单用户级别
/etc/rc.d/rc2.d/   # 多用户级别
/etc/rc.d/rc3.d/   # 完整多用户
/etc/rc.d/rc4.d/   # 自定义
/etc/rc.d/rc5.d/   # 图形化
/etc/rc.d/rc6.d/   # 重启

每个目录里都是符号链接,指向/etc/init.d/下的实际脚本。链接的命名规则很有意思:

  • S开头:启动服务(Start),后面跟两位数字决定顺序
  • K开头:停止服务(Kill),同样跟两位数字

举个例子:

# 在rc3.d目录下
S10network    # 启动网络服务,顺序10
S55sshd       # 启动SSH服务,顺序55
K90network    # 停止网络服务,顺序90

数字越小,执行越早。我个人习惯把核心服务(比如网络、磁盘)放在前面,应用服务放后面。这样依赖关系不容易出问题。

2.5 切换时的实际流程

当执行init 3时,init进程会:

  1. 对比当前级别和目标级别的服务列表
  2. 找出需要停止的服务(当前级别有,目标级别没有)
  3. 找出需要启动的服务(目标级别有,当前级别没有)
  4. 先执行K开头的脚本(停止服务)
  5. 再执行S开头的脚本(启动服务)

这个顺序很重要。我曾经遇到过一个问题:切换运行级别时,某个服务没停干净,新服务启动就报端口冲突。后来排查发现,是K脚本的执行顺序没处理好。

避坑指南:切换运行级别时,千万别在服务启动/停止的半中间强制重启。我曾经手贱,在init 3执行到一半时按了Ctrl+C,结果系统服务状态全乱了,最后只能进单用户模式手动修复。

2.6 默认运行级别的设置

系统启动时默认进入哪个级别?这由/etc/inittab文件控制:

# 在/etc/inittab中设置默认运行级别
id:3:initdefault:    # 默认进入运行级别3

对于RHEL/CentOS 6及更早版本,直接改这个文件就行。但要注意——有些发行版(比如Debian/Ubuntu)的/etc/inittab可能不存在,它们用/etc/init/rc-sysinit.conf或者/etc/default/rcS来控制。

小技巧:如果你不确定当前系统用哪种方式,可以执行grep initdefault /etc/inittab。没输出的话,八成是用了Upstart或者Systemd。

2.7 实际项目中的经验

我在维护一个老旧的RHEL 5集群时,遇到过这么个场景:某台服务器需要临时切换到单用户模式修磁盘,但修完后忘了切回来,结果跑了三天单用户模式,业务全挂了。从那以后,我养成了一个习惯——每次切换运行级别后,都用runlevel确认一下当前状态。

还有一次,我在做系统安全加固时,把默认运行级别从5改成了3(去掉图形界面)。结果第二天同事说服务器起不来——原来他依赖图形界面做监控。嗯,这种沟通问题其实比技术问题更难搞。

2.8 运行级别的现代替代方案

说实话,SysV Init的运行级别机制在Systemd时代已经不太常用了。Systemd用target替代了运行级别,但概念上是一脉相承的:

SysV运行级别 Systemd Target
0 poweroff.target
1 rescue.target
2 multi-user.target
3 multi-user.target
4 multi-user.target
5 graphical.target
6 reboot.target

但别以为SysV Init就过时了。很多嵌入式系统、老旧服务器、以及某些定制化Linux发行版,依然在用这套机制。我建议你至少把0、1、3、5、6这五个级别的含义记牢——面试经常考,实际工作中也经常用。

核心总结:运行级别是SysV Init的灵魂。0关机、1单用户、3文本多用户、5图形多用户、6重启——这五个必须烂熟于心。切换时注意服务启停顺序,别在半中间打断。默认级别设置要谨慎,改错了系统可能起不来。