在 Linux 系统中,如果希望系统在启动或重启时自动执行指定命令或脚本,可以通过多种方式实现,包括系统级(systemd、rc.local)、用户级(crontab)、以及容器级(Docker ENTRYPOINT/CMD)。以下内容覆盖通用 Linux 与 Docker 内部的最佳实践方案。⚙️


🧭 一、总体思路与执行机制

系统启动过程本质上是一个由内核 → systemd → 服务启动 → 用户环境的分层启动链。
我们只要将脚本“挂”在其中任意阶段,就能实现在开机执行。

graph TD
A[开机启动] --> B[加载内核]
B --> C[启动systemd]
C --> D[执行系统服务]
D --> E[执行用户级启动任务]
E --> F[脚本或命令自动运行✅]

核心思路: 把脚本注册为“系统启动任务”或“容器启动入口点”。


🧩 二、方法一:使用 systemd 创建开机自启服务(推荐✅)

这是现代 Linux(Ubuntu、Debian、CentOS 7+)最稳健、可管理的方式。

1️⃣ 创建脚本

先编写你需要开机执行的脚本:

sudo vim /usr/local/bin/startup.sh

写入内容示例:

#!/bin/bash
echo "$(date) : System started successfully" >> /var/log/startup.log
/usr/bin/python3 /opt/app/start.py &

解释:

  • #!/bin/bash 表示使用 Bash 解释器执行。

  • & 表示后台执行,防止阻塞系统启动流程。

  • /var/log/startup.log 用于记录执行时间和日志。

保存后赋权:

sudo chmod +x /usr/local/bin/startup.sh

2️⃣ 创建 systemd 服务文件

sudo vim /etc/systemd/system/startup.service

写入以下内容:

[Unit]
Description=Custom Startup Script
After=network.target

[Service]
ExecStart=/usr/local/bin/startup.sh
Type=simple
RemainAfterExit=true

[Install]
WantedBy=multi-user.target

解释:

  • After=network.target 保证脚本在网络启动后执行。

  • RemainAfterExit=true 表示即便脚本执行完也保持为“已启动”状态。

  • WantedBy=multi-user.target 意味着系统进入正常运行级别时执行。

3️⃣ 启用与测试

sudo systemctl daemon-reload
sudo systemctl enable startup.service
sudo systemctl start startup.service

执行完后重启验证:

sudo reboot

优势: 可靠、可控、带日志管理;
劣势: 配置稍繁琐,但企业级推荐使用。


⚙️ 三、方法二:使用 rc.local(传统兼容方案)

适用于轻量或旧系统环境(如嵌入式、轻量容器)。

sudo vim /etc/rc.local

添加以下内容:

#!/bin/bash
/usr/local/bin/startup.sh &
exit 0

赋权:

sudo chmod +x /etc/rc.local

解释:
系统在进入多用户模式时自动执行 /etc/rc.local
此文件兼容旧系统,执行时机较晚(网络、服务均已启动)。

注意: 某些新版本系统需手动启用 rc-local 服务:

sudo systemctl enable rc-local.service

🕒 四、方法三:使用 crontab @reboot 关键字(简洁方案)

用户级启动任务可用:

crontab -e

添加行:

@reboot /usr/local/bin/startup.sh

解释:
@reboot 表示系统每次启动后执行。
适合个人脚本、小型项目,但无日志管理能力。


🐳 五、方法四:Docker 容器启动时执行脚本(容器内)

在 Docker 场景中,容器并不遵循完整的 Linux 启动流程,而是通过 ENTRYPOINTCMD 执行。

方式一:在 Dockerfile 中定义启动脚本

FROM ubuntu:22.04
COPY startup.sh /usr/local/bin/startup.sh
RUN chmod +x /usr/local/bin/startup.sh
ENTRYPOINT ["/usr/local/bin/startup.sh"]

解释:
容器启动即执行 startup.sh,可在脚本末尾调用主进程,例如:

#!/bin/bash
echo "Container start at $(date)" >> /var/log/container.log
exec nginx -g "daemon off;"

exec 保证容器主进程为 nginx,不会被脚本替代。

方式二:docker-compose.yml 中挂载脚本

command: bash -c "/usr/local/bin/startup.sh && tail -f /dev/null"

🧠 六、各方式比较表

方式 场景 优点 缺点
systemd 服务 企业/生产环境 稳定、日志可控、依赖清晰 配置稍复杂
rc.local 兼容性强 简单直接 可能默认禁用
crontab @reboot 用户任务 简洁方便 无日志、不可依赖网络状态
Docker ENTRYPOINT 容器场景 一次性执行、轻量 不支持 systemd 服务

🔧 七、执行顺序原理图

graph TD
A[系统启动] --> B[systemd初始化]
B --> C[加载网络服务]
C --> D[执行rc.local]
D --> E[执行用户crontab@reboot]
E --> F[执行Docker ENTRYPOINT]
F --> G[完成脚本任务✅]

✅ 八、总结

  • 推荐标准化方式: systemd 服务。

  • 轻量容器场景: 直接在 Dockerfile 中设置 ENTRYPOINT。

  • 快速测试或个人任务: 使用 crontab 的 @reboot 关键字。

🌟 一句话总结:
Linux 启动执行脚本的本质是“注册执行点”,选对触发层级,脚本即可稳定执行。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐