news 2026/3/4 4:48:17

优先级怎么设?聊聊开机启动顺序那些事

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
优先级怎么设?聊聊开机启动顺序那些事

优先级怎么设?聊聊开机启动顺序那些事

你有没有遇到过这样的情况:系统一开机,某个服务就卡住不动,等半天才进入桌面;或者两个脚本抢着访问同一个文件,结果一个失败、一个异常;又或者明明配置好了自动启动,重启后却什么都没发生?这些问题背后,往往不是脚本写错了,而是启动顺序没理清,优先级没设对

今天不讲虚的,我们就用一个真实可运行的镜像——“测试开机启动脚本”——来把 Ubuntu 系统里最让人头疼又最容易被忽略的环节:开机启动顺序与优先级设置,掰开揉碎讲清楚。全文没有一句空话,所有操作都在真实环境验证过,代码可复制、步骤可回溯、问题有解法。

你不需要是系统管理员,只要会敲几行命令、能看懂注释,就能真正掌握“什么时候启动、谁先谁后、为什么这样设”的底层逻辑。


1. 启动顺序不是玄学,而是有章可循的流程

很多人以为开机启动就是“把脚本丢进某个目录就完事”,其实 Ubuntu(特别是使用 SysV init 的老版本或兼容模式)的启动过程是一套严格分阶段执行的机制。理解这个流程,是设对优先级的前提。

1.1 Ubuntu SysV init 启动的四个关键阶段

系统从加电到登录界面,大致经历以下阶段:

  • 内核加载与基础设备初始化:硬件识别、驱动加载、/proc /sys 挂载
  • init 进程启动(PID 1):读取/etc/inittab或默认运行级别(通常是runlevel 23
  • 运行级别脚本执行:按/etc/rc?.d/目录下符号链接的字母顺序,依次调用/etc/init.d/中的真实脚本
  • 用户登录准备:启动 getty、显示登录界面或桌面环境

其中,第三阶段才是我们能干预的“启动脚本执行层”,而优先级,就体现在/etc/rc?.d/下那些以Sxx开头的链接名里。

1.2 优先级数字到底代表什么?

看这个常见命令:

sudo update-rc.d run.sh defaults 96

这里的96就是优先级值。它不是越大越好,也不是越小越快,而是决定脚本在当前运行级别(如rc2.d)中被调用的先后顺序

  • 所有Sxx链接按xx数值从小到大排序执行(S01S99
  • S01类脚本最早执行(如S01procps,负责挂载 proc 文件系统)
  • S99类脚本最晚执行(如S99rc.local,留给用户最后兜底)
  • 同一数值下,按字母顺序(a-z)执行;若冲突,系统会提示警告

关键提醒:优先级只影响同一运行级别内的执行顺序,不跨级别。比如rc2.drc3.d是两套独立列表。Ubuntu 桌面版默认进入runlevel 2,服务器版常用runlevel 3

1.3 什么情况下必须调优先级?

别盲目改数字。真正需要调整优先级的场景,只有三类:

  • 依赖网络的服务:比如你的脚本要 curl 外部 API,就必须确保在S10networking(通常为 10)之后运行
  • 依赖文件系统挂载的服务:比如脚本要读/home/ubuntu/trx/config.json,就得比S15mountall(挂载用户分区)更晚
  • 避免资源争抢:比如两个脚本都要写同一个日志文件,可让一个设为S80,另一个设为S85,错开执行时间

记住了:优先级的本质,是表达“我需要等谁做完,才能开始”


2. 实战:用“测试开机启动脚本”镜像完成一次完整部署

我们不再纸上谈兵。下面全程基于镜像“测试开机启动脚本”环境操作,所有路径、权限、命令均来自真实验证。假设你的目标是:让/home/ubuntu/trx/bin/mywork这个程序,在系统联网完成后、桌面启动前,以 root 权限自动运行。

2.1 第一步:编写带标准头的启动脚本

注意,这不是普通 shell 脚本,而是符合 LSB(Linux Standard Base)规范的 init 脚本。头部注释不是摆设,update-rc.d会解析它来生成依赖关系。

# 创建并编辑脚本 cd /home/ubuntu nano run.sh

粘贴以下内容(请逐字复制,尤其注意空格和换行):

#!/bin/sh ### BEGIN INIT INFO # Provides: run.sh # Required-Start: $local_fs $remote_fs $network $syslog # Required-Stop: $local_fs $remote_fs $network $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts mywork daemon # Description: runs /home/ubuntu/trx/bin/mywork with root privileges ### END INIT INFO case "$1" in start) echo "Starting mywork..." cd /home/ubuntu/trx # 使用 sudo -S 配合 echo 输入密码(仅用于测试环境,生产请改用 visudo 配置免密) echo "123456" | sudo -S ./bin/mywork > /var/log/mywork.log 2>&1 & ;; stop) echo "Stopping mywork..." pkill -f "mywork" ;; restart) $0 stop sleep 2 $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 ;; esac exit 0

为什么这样写?

  • Required-Start: $network告诉系统:必须等网络服务启动完再执行我
  • Default-Start: 2 3 4 5表示在运行级别 2~5 都启用(覆盖桌面和服务器模式)
  • start/stop/restart分支让脚本能被service run.sh start正常调用,方便调试
  • 日志重定向> /var/log/mywork.log是排障第一手资料,千万别省

2.2 第二步:赋予执行权限并移入系统目录

chmod +x /home/ubuntu/run.sh sudo cp /home/ubuntu/run.sh /etc/init.d/ sudo chmod 755 /etc/init.d/run.sh

注意:/etc/init.d/下的脚本必须是root:root所有者且权限为755,否则update-rc.d会拒绝注册。

2.3 第三步:用 update-rc.d 注册,并设置合理优先级

现在最关键:设多少?

  • 查看当前网络服务的优先级:

    ls -l /etc/rc2.d/ | grep network # 输出类似:S10networking -> ../init.d/networking
  • 我们的脚本需要在网络之后,但不能太靠后(避免被rc.local或桌面服务抢占资源)。稳妥起见,设为90

    sudo update-rc.d run.sh defaults 90

    这条命令做了三件事:

    • /etc/rc0.d//etc/rc6.d/中创建对应K10run.sh(关机)和S90run.sh(启动)链接
    • 根据Default-Start自动选择rc2.drc3.d等目录
    • 解析Required-Start,确保依赖检查通过

    如果看到update-rc.d: error: ... missing LSB information,说明脚本头部注释格式错误,请回头检查### BEGIN INIT INFO块是否完整、缩进是否正确。

2.4 第四步:立即测试,不等重启

别急着reboot。先手动触发一次,确认脚本能跑通:

sudo service run.sh start # 检查进程 ps aux | grep mywork # 查看日志 sudo tail -20 /var/log/mywork.log

如果进程存在、日志有输出,说明脚本本身和权限都没问题。此时再执行:

sudo reboot

重启后,等待约 30 秒,执行:

ps aux | grep mywork # 应该能看到正在运行的 mywork 进程

成功!你的程序已真正融入系统启动流程。


3. 三种常用方式对比:选对方法,少踩 80% 的坑

虽然update-rc.d是最规范的方式,但实际中还有其他路径。我们用一张表说清它们的适用边界、风险点和优先级控制能力:

方式是否支持优先级设置依赖管理能力适用场景风险提示
/etc/init.d/+update-rc.d完全支持(Sxx数字)自动解析Required-Start生产环境、需精确控制依赖的服务脚本必须符合 LSB 规范,头部注释缺一不可
/etc/rc.local❌ 无优先级(固定为S99❌ 无显式依赖声明快速验证、简单命令、兜底任务Ubuntu 20.04+ 默认禁用,需手动启用;exit 0必须在末尾,否则后续脚本不执行
桌面自启动(~/.config/autostart/❌ 不适用(GUI 层)❌ 仅等 X11 启动用户级图形程序(如托盘工具)仅对当前用户生效,root 权限脚本无法直接运行

为什么 rc.local 经常“失效”?

  • Ubuntu 18.04+ 默认将rc-local.service设为disabled
  • 即使启用,它也只在multi-user.target末尾执行,早于graphical.target
  • 若你的脚本依赖DISPLAY环境变量(比如要弹窗),在这里必然失败

所以结论很明确:只要不是纯用户级、纯图形界面的小工具,就别碰rc.local和桌面启动。老老实实用init.d + update-rc.d,稳、准、可维护。


4. 排查指南:当启动失败时,这五步帮你快速定位

再严谨的配置也可能出错。以下是真实环境中高频问题的排查路径,按顺序执行,90% 的问题能在 5 分钟内解决:

4.1 第一步:确认脚本是否被加载

# 查看 rc2.d 中是否有 S90run.sh 链接 ls -l /etc/rc2.d/ | grep run.sh # 应输出:S90run.sh -> ../init.d/run.sh

如果没看到,说明update-rc.d未成功注册,回到第 2.3 步检查。

4.2 第二步:检查脚本语法与权限

# 测试脚本能否被 sh 解析(排除语法错误) sudo sh -n /etc/init.d/run.sh # 检查权限和所有者 ls -l /etc/init.d/run.sh # 应为:-rwxr-xr-x 1 root root ...

4.3 第三步:手动模拟启动流程

# 用 init 脚本标准方式启动(等同于开机时调用) sudo /etc/init.d/run.sh start # 观察终端输出,比日志更直接

常见报错:

  • sudo: no tty presentsudoers未配置requiretty,或密码输入方式错误
  • Permission deniedmywork二进制文件缺少执行权限:chmod +x /home/ubuntu/trx/bin/mywork

4.4 第四步:查看系统启动日志

# 过滤所有与 run.sh 相关的日志 sudo journalctl -b | grep -i "run.sh\|mywork" # 或查看传统 syslog sudo cat /var/log/syslog | grep -i "run.sh"

重点关注Failed to startPermission deniedNo such file类错误。

4.5 第五步:验证依赖服务是否就绪

你的脚本声明了依赖$network,那就确认 networking 服务确实启动成功了:

systemctl status networking # 或查看其 rc2.d 链接 ls -l /etc/rc2.d/ | grep networking

如果networking本身启动失败,你的脚本永远不会被执行——这就是依赖管理的价值。


5. 进阶建议:让启动更健壮、更安全、更易维护

做到“能用”只是起点。在真实项目中,还需考虑这些工程化细节:

5.1 密码明文?绝不允许!

示例脚本中echo "123456"是为了演示,生产环境必须删除。正确做法是:

  • 编辑/etc/sudoers(用sudo visudo安全打开)
  • 添加一行:ubuntu ALL=(ALL) NOPASSWD: /home/ubuntu/trx/bin/mywork
  • 脚本中改为:sudo /home/ubuntu/trx/bin/mywork > /var/log/mywork.log 2>&1 &

这样既免密,又最小化授权范围,符合最小权限原则。

5.2 加入健康检查与自动恢复

start分支末尾添加:

# 检查进程是否存活,5秒后重试一次 if ! pgrep -f "mywork" > /dev/null; then echo "mywork failed to start, retrying..." >> /var/log/mywork.log sleep 5 sudo /home/ubuntu/trx/bin/mywork > /var/log/mywork.log 2>&1 & fi

5.3 日志轮转,避免磁盘占满

创建/etc/logrotate.d/mywork

/var/log/mywork.log { daily missingok rotate 30 compress delaycompress notifempty create 644 root root }

6. 总结:优先级不是数字游戏,而是系统思维的体现

我们从一个看似简单的“开机启动”问题出发,一路拆解到启动流程、优先级原理、脚本规范、实操部署、故障排查和工程优化。你会发现:

  • 设优先级,本质是在绘制一张服务依赖图:谁是基石,谁是上层建筑,谁必须等谁
  • update-rc.d不是命令,而是一套契约:你承诺遵守 LSB 规范,系统才承诺按你期望的顺序执行
  • reboot成功,不等于部署完成:日志、进程监控、异常恢复,才是生产级的标配

下次再看到S90xxx,别再只把它当成一个数字。它是系统启动交响乐中的一个音符,而你,正握着指挥棒。

--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/3 11:22:05

OFA视觉蕴含模型5分钟上手教程:零基础搭建图文匹配系统

OFA视觉蕴含模型5分钟上手教程:零基础搭建图文匹配系统 1. 为什么你需要这个模型——不是所有“图文匹配”都叫视觉蕴含 你有没有遇到过这些场景: 电商运营上传了1000张商品图,但文案团队只写了800条描述,剩下200张图配什么文字…

作者头像 李华
网站建设 2026/3/4 2:46:54

Open-AutoGLM敏感操作处理机制,安全接管实测分享

Open-AutoGLM敏感操作处理机制,安全接管实测分享 在手机AI Agent真正走向日常使用前,一个绕不开的问题是:它会不会“越界”?比如未经确认就输入支付密码、自动提交身份证信息、或在未授权情况下访问通讯录?Open-AutoG…

作者头像 李华
网站建设 2026/2/7 11:41:33

AcousticSense AI入门必看:CCMusic-Database语料结构与16类平衡性说明

AcousticSense AI入门必看:CCMusic-Database语料结构与16类平衡性说明 1. 什么是AcousticSense AI:不只是音频分类,而是“看见”音乐的听觉工作站 你有没有想过,音乐不只是耳朵在听,眼睛也能“看懂”?Aco…

作者头像 李华
网站建设 2026/3/4 2:00:31

Clawdbot一文详解:Qwen3:32B模型在Clawdbot中启用LLM-as-a-Judge自动评估模块

Clawdbot一文详解:Qwen3:32B模型在Clawdbot中启用LLM-as-a-Judge自动评估模块 1. Clawdbot是什么:一个让AI代理管理变简单的平台 Clawdbot不是另一个需要从零搭建的复杂系统,而是一个开箱即用的AI代理网关与管理平台。它不强迫你写一堆胶水…

作者头像 李华
网站建设 2026/3/3 5:38:53

Qwen-Image-Layered踩坑记录:这些错误千万别再犯

Qwen-Image-Layered踩坑记录:这些错误千万别再犯 最近在尝试将Qwen-Image-Layered镜像用于图像可编辑性增强任务时,连续踩了五个“看似简单、实则致命”的坑。从服务根本起不来,到图层输出全黑,再到RGBA通道错位导致编辑失效——…

作者头像 李华