星标「Linux大陆」,一起进步!
1. init是什么?
init是Linux系统中的“天字一号”进程:
它的进程号(PID)恒为1,是所有其他进程的父进程。其启动流程如:
init进程的核心功能包括:
2. init的分类
嵌入式Linux系统中,init的分类,从简单到复杂,三种主流方案:BusyBox init、SysVinit和systemd。Buildroot等构建系统也明确将这三类列为可选的初始化系统。
当前系统init类型的指令:
cat /proc/1/comm
2.1 BusyBox init——轻量级选手
BusyBox init是专门为资源受限的嵌入式环境设计的最轻量级解决方案。它是Buildroot的默认init方案,对于大多数嵌入式系统而言已经足够使用。
比如,Buildroot_2019.02:
2.2 SysVinit——经典传统派
SysVinit源自AT&T在1983年发布的System V Unix系统,曾是绝大多数桌面Linux发行版采用的init方案。
2.3 systemd——现代全能型选手
systemd由Lennart Poettering主导开发,是当前Linux桌面和服务器领域最主流的init系统,已被Ubuntu、Fedora、Debian等主流发行版全面采用。
3. 各init开机自启动应用的区别
三种init方案在开机自启动应用的方式上有显著差异:
3.1 SysVinit
SysVinit的启动脚本命名规则为Sxxname(S表示Start,xx为两位数字编号,数字越小越先启动),启动过程中会按编号顺序逐个执行脚本,例如:
init进程启动之后,会对/etc/inittab文件的解释及执行。/etc/inittab文件里有什么内容如:
可以看到里面用到了两个脚本文件:
其中,可以看出/etc/init.d/rcS是在系统开机之后执行的脚本;/etc/init.d/rcK是在系统关机时执行的脚本。
下面看看/etc/init.d/rcS里面的内容:
这个rcS脚本会循环调用/etc/init.d文件夹下的以S+数字开头的脚本文件。即:
SysVinit这种机制简单直观,但随着服务数量的增长,串行启动的效率瓶颈越来越明显。
3.2 BusyBox init
BusyBox init与SysVinit程序自启动的方式大同小异。可以把 BusyBox init 看作 SysVinit 的精简子集,它们之间最核心的区别在于 SysVinit 拥有运行级别的概念,而 BusyBox init 则巧妙地绕过了它,但又能“模拟”出近乎一致的效果。
配置文件:/etc/inittab 或 /etc/init.d/rcS。通过 rcS 脚本挂载,适合一次性启动,不自动守护。通过 inittab 守护进程,自动重启保活。
自启动方式:直接编辑 inittab 或创建 S* 脚本。
3.3 systemd
systemd则截然不同:
我们只需编写一个简单的.service文件描述服务的启动命令、运行条件和其他依赖关系,然后执行systemctl enable即可设置开机自启动。启动时,systemd会解析所有Unit文件间的依赖关系,并行启动不冲突的服务,大大缩短了启动时间。自定义服务必须放在 /etc/systemd/system/ 下。
开机自启动自定义服务的例子:
1. 将程序安装到合适的位置
systemd 服务通常使用绝对路径来指定可执行文件。建议将二进制文件放在 /usr/local/bin/ 或 /opt/ 下,例如自定义一个hello程序:
sudo cp ~/hello /usr/local/bin/
同时确保文件具有可执行权限:
sudo chmod +x /usr/local/bin/hello
2. 创建 systemd 服务单元文件
在 /etc/systemd/system/ 目录下创建 hello.service:
sudo vim /etc/systemd/system/hello.service
写入以下内容:
[Unit]Description=Hello Systemd Demo ServiceAfter=network.target[Service]Type=simpleExecStart=/usr/local/bin/helloRestart=alwaysRestartSec=5sUser=nobodyGroup=nogroupStandardOutput=journalStandardError=journal[Install]WantedBy=multi-user.target
关键参数解释:
Type=simple:服务主进程就是 ExecStart 启动的进程。Restart=always:无论程序因何退出(包括正常退出),都自动重启。因为我们循环中用了 sleep(10),理论上不会退出,加上 always 可以兜底。User=nobody / Group=nogroup:使用低权限用户运行,降低安全风险。StandardOutput=journal:将程序的标准输出重定向到 systemd 日志(journalctl)。WantedBy=multi-user.target:将服务挂钩到多用户目标,实现开机自启。
注意:如果你的程序需要写文件或访问某些目录,nobody 用户可能没有权限,可以根据实际需求修改为其他普通用户(如 www-data 或你自己的用户名)。
3. 启动服务并设置开机自启
# 1. 重新加载 systemd 配置,让 systemd 识别新的服务文件sudo systemctl daemon-reload# 2. 立即启动服务(验证是否能正常运行)sudo systemctl start hello.service# 3. 查看服务状态和最近的日志sudo systemctl status hello.service
此时能看到下面的输出,且 Active 状态为 active (running),日志中已经出现了 hello systemd:
# 4. 设置开机自动启动sudo systemctl enable hello.service
执行 enable 后,systemd 会在 /etc/systemd/system/multi-user.target.wants/ 目录下创建一个指向 hello.service 的符号链接:
下次系统启动时,就会自动运行该服务。
4. 验证开机自启
重启系统:
sudo reboot
重新登录后,检查服务状态:
systemctl status hello.service
常用指令:
| |
|---|
sudo systemctl start hello | |
sudo systemctl stop hello | |
sudo systemctl restart hello | |
sudo systemctl enable hello | |
sudo systemctl disable hello | |
systemctl status hello | |
journalctl -u hello -b | |
journalctl -u hello -f | |
4. 当前主流的init方案
在桌面和服务器领域,systemd已毫无疑问地成为绝对主流。
在嵌入式Linux领域,情况则更为多元:Yocto Project虽然默认仍使用SysVinit,但已全面支持systemd切换;Buildroot默认选择BusyBox init,因为它在资源受限的嵌入式系统中最轻量、最高效。
选型建议:
此外,还有一些小众但值得关注的init方案:
4. 小结
init进程虽小(PID=1),却是整个Linux系统的“第一推动力”。从极致精简的BusyBox init,到经典稳健的SysVinit,再到功能强大的systemd,每一种方案都有其适合的应用场景。
在嵌入式系统开发中,正确选择init方案并掌握其开机自启动配置方法,是确保产品稳定可靠的关键一步。