Ubuntu开机脚本不会配?这个测试镜像手把手教你
你是不是也遇到过这样的问题:服务器重启后,自己写的程序没跟着起来,得手动登录、cd到目录、再敲一遍启动命令?每次都要重复操作,既浪费时间又容易出错。更糟的是,万一半夜服务挂了,没人及时处理,业务就断了。
别急——其实只要一个简单的开机启动脚本,就能让程序在系统一启动时就自动运行。但很多新手卡在第一步:脚本怎么写?放哪?怎么注册成服务?为什么写了却没生效?
这篇博客不讲抽象概念,不堆术语,就用「测试开机启动脚本」这个轻量镜像,带你从零开始,一行一行敲、一步一验证,真正把开机自启这件事搞明白。不需要你懂 init.d、systemd 的底层原理,只需要你会复制粘贴、会敲几条命令,15分钟内就能让自己的脚本稳稳跑在开机第一秒。
1. 先搞清楚:我们到底要解决什么问题
1.1 开机自启 ≠ 简单丢个.sh文件就完事
很多人以为,把启动命令写进/etc/rc.local或者扔个start.sh在桌面,再加个chmod +x就能开机运行——结果重启后发现:
- 脚本根本没执行;
- 执行了但报“找不到命令”或“权限被拒绝”;
- 程序启动了,但立刻退出,日志里只有一行
nohup: ignoring input; - 多个服务之间启动顺序错乱,依赖的服务还没起来,上游就先启动失败。
这些问题的根源,不是脚本写得不对,而是缺少系统级的生命周期管理。Linux 不是 Windows,它不会“看到脚本就执行”,而是通过一套服务管理机制(比如 SysV init 或 systemd)来统一调度、校验依赖、记录状态。
1.2 这个镜像帮你绕过所有坑
「测试开机启动脚本」镜像不是一堆现成代码的打包,而是一个可交互、可验证、带反馈的实操环境:
- 预装了完整 Ubuntu 22.04 系统(兼容主流云服务器和本地虚拟机);
- 内置一个已配置好的
test服务示例(含启动/停止/重启逻辑); - 所有路径、权限、依赖项都提前调通,你只需关注“怎么做”,不用纠结“为什么不行”;
- 每步操作后都有明确验证方式(比如
sudo service test status返回active (running)才算成功); - 支持两种主流方式:传统
update-rc.d(适合老项目/兼容性要求高场景)和现代systemctl(推荐新部署)。
换句话说:你不用再百度“ubuntu 开机启动脚本 权限错误”,也不用反复重启试错。镜像就是你的沙盒实验室。
2. 动手实操:用镜像一步步配好你的第一个开机脚本
2.1 启动镜像并进入终端
如果你还没拉取镜像,执行这条命令(已适配国内源加速):
docker run -it --rm --privileged -p 2222:22 csdn/mirror-test-startup:latest提示:镜像已预装
openssh-server和vim,支持 SSH 连接(默认用户ubuntu,密码ubuntu),也支持直接docker exec -it <容器ID> /bin/bash进入。
进入后,先确认当前用户有sudo权限:
whoami && sudo -n true && echo " sudo 权限正常"如果提示sudo: a password is required,输入密码ubuntu即可。
2.2 查看预置的测试服务脚本
镜像中已准备好完整的test服务脚本,位置在/etc/init.d/test。我们先用cat快速浏览结构:
sudo cat /etc/init.d/test你会看到类似这样的开头(关键部分已加注释):
#!/bin/bash ### BEGIN INIT INFO # Provides: test # 服务名,必须和文件名一致 # Required-Start: $local_fs $network # 启动前必须就绪的系统资源 # Required-Stop: $local_fs # 停止前必须保持的资源 # Default-Start: 2 3 4 5 # 在哪些运行级别启动(2~5 是多用户图形/网络模式) # Default-Stop: 0 1 6 # 在哪些级别停止(0关机、1单用户、6重启) # Short-Description: test service # 简短描述,显示在 service list 中 # Description: A demo service for startup script testing ### END INIT INFO注意:### BEGIN INIT INFO和### END INIT INFO之间的注释块不是可选的。它是update-rc.d工具识别服务依赖和启动顺序的唯一依据。少一个#或格式错位,注册就会失败。
再往下看,是实际的启动逻辑:
# 定义要管理的子服务目录(模拟多个微服务) files=(file opt merchant) deploy=/home/ubuntu/deploy/ start() { echo "Starting test services..." for var in "${files[@]}"; do cd "$deploy$var" || { echo "❌ Failed to enter $deploy$var"; exit 1; } # 检查是否存在 start.sh 并执行 if [ -x "start.sh" ]; then ./start.sh & else echo " No executable start.sh in $deploy$var" fi done }关键点:
- 使用
"${files[@]}"而不是$files,避免空格路径出错; cd ... || exit 1保证任一目录失败就中断,不静默跳过;./start.sh &后台运行,但不加nohup—— 因为 init.d 脚本本身由系统守护进程管理,无需自行守护。
2.3 验证脚本语法与权限
在注册前,先手动执行一次,确保脚本能跑通:
sudo /etc/init.d/test start sleep 2 sudo /etc/init.d/test status你应该看到类似输出:
● test.service - LSB: test service Loaded: loaded (/etc/init.d/test; generated) Active: active (running) since ...如果报错command not found,大概率是start.sh缺少执行权限。镜像中已修复,但你自己写时务必检查:
sudo chmod +x /home/ubuntu/deploy/file/start.sh2.4 注册为开机服务(两种方式任选)
方式一:使用update-rc.d(SysV init 兼容方式)
这是最经典、兼容性最强的方式,适用于 Ubuntu 16.04~22.04(即使 systemd 主导,仍完全支持):
sudo update-rc.d test defaults 95defaults表示按Default-Start/Stop注释里的级别启用;95是启动优先级(0~99),数字越大越晚启动。这里设为 95,确保网络、磁盘等基础服务已就绪。
验证是否注册成功:
sudo ls -l /etc/rc*.d/*test*应看到类似:
/etc/rc0.d/K05test /etc/rc1.d/K05test /etc/rc2.d/S95test /etc/rc3.d/S95test ...其中S表示 Start,K表示 Kill,数字代表顺序。
方式二:使用systemctl(推荐新项目)
虽然镜像默认用 SysV,但我们也提供.service文件模板(位于/opt/templates/test.service),可一键启用:
sudo cp /opt/templates/test.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable test.service验证:
systemctl is-enabled test.service # 应返回 "enabled" systemctl status test.service # 查看当前状态两种方式可共存,但建议新项目统一用systemctl—— 它支持依赖声明、日志聚合、自动重启策略等高级功能。
3. 自己写一个:从零创建属于你的开机脚本
3.1 明确需求:你想开机自动运行什么?
别急着写代码。先问自己三个问题:
- 它是什么程序?(Python 脚本?Java jar?Node.js 服务?)
- 它需要什么前置条件?(网络连通?某个目录存在?数据库已启动?)
- 它是否需要持续运行?(还是只执行一次就退出?)
举个真实例子:你写了一个 Python 监控脚本monitor.py,需要每 5 秒检查一次磁盘空间,并把结果写入/var/log/disk.log。它依赖网络(发告警邮件)和磁盘写入权限。
那么你的脚本核心需求就是:
开机后自动启动;
确保/var/log可写;
如果崩溃,自动重启;
日志集中管理,方便排查。
3.2 模板化编写:抄作业也能抄明白
镜像中提供了通用模板/opt/templates/custom-startup.sh,你只需改 4 处:
#!/bin/bash ### BEGIN INIT INFO # Provides: mymonitor # Required-Start: $local_fs $network # Required-Stop: $local_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Disk monitor service # Description: Monitors disk usage and logs to /var/log/disk.log ### END INIT INFO # 👇 修改1:你的程序路径 APP_PATH="/home/ubuntu/monitor.py" # 👇 修改2:你的工作目录(Python 导入路径可能依赖) WORK_DIR="/home/ubuntu" # 👇 修改3:你的日志路径 LOG_FILE="/var/log/disk.log" # 👇 修改4:启动命令(根据语言调整) START_CMD="python3 $APP_PATH >> $LOG_FILE 2>&1 &" start() { echo "Starting mymonitor..." mkdir -p "$(dirname $LOG_FILE)" chown ubuntu:ubuntu "$LOG_FILE" cd "$WORK_DIR" # 检查是否已在运行 if pgrep -f "$APP_PATH" > /dev/null; then echo " mymonitor already running" return 0 fi eval "$START_CMD" echo " mymonitor started with PID $!" } stop() { echo "Stopping mymonitor..." pkill -f "$APP_PATH" || true echo " mymonitor stopped" } case "$1" in start) start ;; stop) stop ;; restart) stop; sleep 1; start ;; *) echo "Usage: $0 {start|stop|restart}"; exit 1 ;; esac抄完记得:
- 保存为
/etc/init.d/mymonitor; sudo chmod +x /etc/init.d/mymonitor;sudo update-rc.d mymonitor defaults;sudo service mymonitor start测试。
3.3 高级技巧:让脚本更健壮
- 防止重复启动:用
pgrep -f检查进程是否存在(比pidfile更可靠); - 日志自动轮转:配合
logrotate,避免日志撑爆磁盘; - 失败自动恢复:在
systemd中加Restart=always和RestartSec=10; - 环境变量隔离:
systemd服务中用Environment="PATH=/usr/local/bin:/usr/bin"避免command not found。
镜像中/opt/guide/advanced-tips.md有详细说明,可随时查阅。
4. 排查常见问题:脚本写了,为啥不生效?
4.1 最常踩的 3 个坑
| 现象 | 原因 | 快速验证命令 | 解决方案 |
|---|---|---|---|
sudo service xxx start报unrecognized service | 脚本没放在/etc/init.d/,或文件名与Provides:不一致 | ls /etc/init.d/xxx;grep "Provides:" /etc/init.d/xxx | 确保路径正确、名称匹配、有执行权限 |
服务显示active (exited)但进程不存在 | 脚本执行完就退出(比如忘了加&或nohup) | sudo journalctl -u xxx.service -n 20 | 改用&后台运行,或用systemd的Type=simple |
| 重启后服务没启动 | update-rc.d未生效,或systemctl enable漏掉 | sudo ls /etc/rc2.d/ | grep xxx;systemctl is-enabled xxx.service | 重新执行注册命令,确认输出enabled |
4.2 一条命令定位所有问题
镜像内置诊断脚本/opt/bin/diagnose-startup.sh,运行它:
sudo /opt/bin/diagnose-startup.sh mymonitor它会自动检查:
脚本是否存在且可执行;Provides名称是否匹配;
依赖服务($network等)是否就绪;
是否已注册到 rcN.d 目录;
当前运行状态与 PID 是否一致。
输出结果清晰标红/绿,直指病灶。
5. 总结:开机脚本的本质,是让机器听懂你的意图
写一个开机脚本,技术上只是几行 bash 和一次update-rc.d。但背后体现的,是一种工程思维:
- 明确边界:知道程序需要什么、不能假设什么;
- 尊重约定:init.d 的注释块、systemd 的 unit 文件,不是形式主义,而是系统沟通的语言;
- 验证闭环:不以“写完”为终点,而以“重启后稳定运行 24 小时”为验收标准。
这个「测试开机启动脚本」镜像,就是帮你把这种思维落地的最小可行环境。它不教你怎么成为 Linux 内核专家,但能让你今天下午就配好生产环境的第一个自启服务。
现在,关掉这篇博客,打开终端,敲下第一行sudo vim /etc/init.d/myapp—— 你的自动化运维之旅,就从这一行开始。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。