关于linux启动流程一直好像有点模糊,通过查阅官网和博客资料,实际验证总结如下:
一、 启动流程
Linux的init经历了两次重大演进,传统的sysvinit已经淡出历史舞台,新的updtart和systemd各有特点,但是越来越多的发行版采纳了systemd,因此重点优先说明systemd、upstart的方式。
1.1. 演变过程:
Sysvinit:Linux最早的启动方式是sysvinit,但因为init是串行启动,时间长且脚本复杂,所以基本被抛弃。
Upstart: ubuntu(6.10-15.0)期间是比较不稳定的时期,6.10开始使用upstart的event方式控制,所以6.10-9.10之间使用/etc/event.d目录的配置文件。而9.10-15.0配置文件改为/etc/init/*.conf。执行脚本init.d目录在前几个版本统一放在etc/rc.d目录下,后面的版本又调整到了/etc目录下。
Systemd:自ubuntu15.04版本之后正式引入并默认将init系统配置为systemd方式。(官方原文:Since Ubuntu 15.04, init and upstart have been replaced by Systemd)。systemd并发的性能进一步提升、功能也更强大,但也导致其过于复杂,且和内核耦合较大,因此2019年12月 Debian对此发起了一次投票, 据投票结果,对systemd的处理方式为:"Systemd but we support exploring alternatives(选择 systemd 但同时探索替代方案)
注:
1、查看ubuntu及linux内核版本号:cat /proc/version
2、rc=system runlevel compatibility
3、查看系统采用的哪种方式键入:stat /proc/1/exe:
输出:File: /proc/1/exe -> lib/systemd/systemd。
或者查看init文件属性:ls -l init
lrwxrwxrwx 1 root root 20 Jan 1 1970 init -> /lib/systemd/systemd
1.2. Systemd方式
启动流程:
1、内核arch/arm/kernel/head*.S 文件包含了内核入口ENTRY(stext)和跳转到start_kernel)代码。
2、start_kernel--》kernel_thread--》init()--》do_initcalls(初始化驱动,很多驱动中都有类似module_init(usb_init)的代码,通过该宏定义逐层解释存放到.initcall.int节中)。
3、内核初始化结束后启动init进程,然后切换到用户态执行/sbin/init。(具体过程:内核中的init函数是用户态init(kernel_init)进程的入口,它在执行execve("/sbin/init",argv_init, envp_init)时改变成为一个普通的用户进程。然后开始执行第三方的初始化程序/sbin/init,这个init是软连接,指向 /lib/systemd/systemd。)
4、systemd软件(/sbin/init),首先解析graphical.targe(default.target),根据配置文件的区块、字段,如before、after,决定启动顺序,具体字段的含义参见附录。如下是graphical.targe的配置文件:
注:
所有配置文件存放的目录可以在以下任一目录之中
/etc/systemd/system
/etc/systemd/system/
/usr/lib/systemd/system/
/lib/systemd/system/
通过解析配置文件,获得启动队列,启动服务的逻辑顺序如下图:
工具使用:
Systemd相对来说功能比较强大,提供了很多工具供使用者分析、调试用。
1、查看版本:systemctl --version
2、分析启动时间:systemd-analyze blame
可以列出所有正在运行的单元,按从初始化开始到当前所花的时间排序,通过这种方式你就知道哪些服务在引导过程中要花较长时间来启动。
3、查看graphical.targe包含的服务:systemctl list-dependencies graphical.target
● ├─accounts-daemon.service
● ├─mystartcql.service
● ├─ureadahead.service
● └─multi-user.target
● ├─irqbalance.service
● ├─mystartcql.service
● ├─networking.service
● │ │ ├─apparmor.service
● │ │ ├─brltty.service
● │ │ ├─console-setup.service
● │ │ ├─dev-hugepages.mount
3、# 查看内核日志(不显示应用日志)
$ sudo journalctl -k
日志的配置文件是/etc/systemd/journald.conf
4、systemctl start cqltest.service 验证服务能否正常启动;如果不能执行,
systemd-analyze verify cqltest.service 分析service不能执行的而原因;如果没有错误,执行systemctl status cqltest.service或者 systemctl list-unit-files(列出所有可用的Unit),查看服务状态是否使能可用。
其他指令
systemctl list-units 列出所有正在运行的Unit
systemctl --failed 列出所有失败单元
systemctl mask httpd.service 禁用服务
systemctl unmask httpd.service
systemctl kill httpd 杀死服务
systemd-analyze critical-chain:分析启动时的关键链
systemd-analyze blame 分析启动时各个进程花费的时间
5、查找执行文件是脚本:#! /bin/sh
root@imx6dlsabresd:/sbin# grep -r /bin/sh
routef:#! /bin/sh
mount-copybind:#!/bin/sh
populate-extfs.sh:#!/bin/sh
Binary file sulogin.util-linux matches
routel:#!/bin/sh
mount-copybind~:#!/bin/sh
ifcfg:#! /bin/sh
cql.sh:#!/bin/sh -e
rtpr:#! /bin/sh
6、service需要重启才会生效。
1.3. Upstart方式
启动流程:
1、和systemd方式一致。
2、加载系统内核,启动init进程,在/etc 下有init和init.d两个文件夹,init文件夹内都是配置文件,init.d文件夹下都是可执行文件。
3、启动init进程,第一个运行的应用程序也是/sbin/init,init模式下该程序会读取/etc/inittab文件,但是在upstart下,没有这个文件,取而代之的是 /etc/init/rc-sysinit.conf,主要作用就是设定Linux运行等级
4、首先执行/etc/rcS.d/ 目录下的启动脚本,然后是/etc/rc*.d/ 目录。这里的/etc/rc*.d文件夹的脚本文件的链接目标为:/etc/init.d文件夹下的相应脚本(* 为运行的级别,0-6级别。如果您的运行级别为5,则执行 rc5.d )。 rcX.d里各服务的执行顺序根据文件名的序号决定。
5、根据 /etc/rcS.d/文件夹中对应的脚本,启动 Xwindow 服务器 xorg,Xwindow 为 Linux 下的图形用户界面系统。启动登录界面,等待用户登录。
查看当前运行等级:输入runlevel 即可。
查看启动方式:/boot/grub/grub.conf。
1.4. 增加开机启动项:
方法一、为了兼容性,systemd、upstart都支持在etc\rc.local中添加shell指令的方式增加启动,启动顺序在system service之后。
方法二、针对system启动方式:在etc/systemd/system目录中添加如下cqltest.service,文件内容如下:
[Unit]
Description=cqltest
After=basic.target
StartLimitIntervalSec=0
[Service]
Type=forking
ExecStart=/sbin/cql.sh
User=root
Restart=on-failure
RestartSec=1
[Install]
WantedBy=multi-user.target
备注:文件执行权限644,文件的各个字段都要小心谨慎。配置文件的编写需要很多的学习,必须参考 systemd 附带的 man 等文档进行深入学习
方法三、针对upstart启动方式:添加一个开机启动脚本,Root权限下执行
mv starter.sh /etc/init.d/
update-rc.d starter.sh defaults 90
打印输出:
My start.sh
Hello etc/rc.local
卸载启动脚本:
cd /etc/init.d
update-rc.d -f starter.sh remove
注:关于update-rc.d指令的解释:
自动将starter.sh的链接添加到所有etc/rcX.d目录中,使用man update-rc.d可详细了解