在我们实现如何创建开机自启程序前,先简单了解下linux的启动过程。
linux启动过程
Linux 系统的启动,从计算机开机通电自检开始,一直到登陆系统,需要经历多个过程。
CentOS/RHEL6
- 服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘);
- 读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 Boot Loader(启动引导程序,最为常见的是 GRUB)。
- 依据 Boot Loader 的设置加载内核,内核会再进行一遍系统检测。系统一般会采用内核检测硬件的信息,而不一定采用 Bios 的自检信息。内核在检测硬件的同时,还会通过加载动态模块的形式加载硬件的驱动。
- 内核启动系统的第一个进程,也就是 /sbin/init。
- 由 /sbin/init 进程调用 /etc/init/rcS.conf 配置文件,通过这个配置文件调用 /etc/rc.d/rc.sysinit 配置文件。而 /etc/rc.d/rc.sysinit 配置文件是用来进行系统初始化的,主要用于配置计算机的初始环境。
- 还是通过 /etc/init/rcS.conf 配置文件调用 /etc/inittab 配置文件。通过 /etc/inittab 配置文件来确定系统的默认运行级别。
- 确定默认运行级别后,调用 /etc/init/rc.conf 配置文件。
- 通过 /etc/init/rc.conf 配置文件调用并执行 /etc/rc.d/rc 脚本,并传入运行级别参数。
- /etc/rc.d/rc 确定传入的运行级别,然后运行相应的运行级别目录 /etc/rc[0-6].d/ 中的脚本。
- /etc/rc[0-6].d/ 目录中的脚本依据设定好的优先级依次启动和关闭。
- 最后执行 /etc/rc.d/rc.local 中的程序。
- 如果是字符界面启动,就可以看到登录界面了。如果是图形界面启动,就会调用相应的 X Window 接口。
CentOS/RHEL7
服务器加电,加载 BIOS 信息,BIOS 进行系统检测。依照 BIOS 设定,找到第一个可以启动的设备(一般是硬盘);
读取第一个启动设备的 MBR (主引导记录),加载 MBR 中的 OSLoader(启动引导程序GRUB2)。
OSLoader 加载其相关配置 , 并显示相关的配置 菜单来引导用户选择相关操作(/etc/grub.d,/etc/default/grub,/boot/grub2/grub.cfg)
在用户选择后 ( 或 timeout 后 ),GRUB2 将加载 内核及 initramfs 至内存中 .initramfs 属于一个 img 的虚拟磁盘。
initramfs 包含了动态的内核模块 , 初始化脚本及非常多的硬件驱动等 , 在 RHEL7 中 initramfs 自身即包含了一个完整的可用系统。(/etc/dracut.conf)
GRUB2 将控制系统切换到 kernel, 通过对 GRUB2 的控制可以添加各种 kernel 的选项 . 并将 这些选项同时传递至内存中 , 影响 kernel 及 initramfs 的运行 . (/etc/grub.d,/etc/default/grub,/boot/grub2/gr ub.cfg)
kernel 在启动后将初始化所有的硬件 , 通过 initramfs 找到硬件相关的驱动程序 , 而后从 initramfs 中执行 PID 1 的 /sbin/init 命令 ( 最高 进程 ). 在 RHEL 中 init 属 于 /lib/systemd/systemd 的软连接 , 以及一个 udev 进程来自动建立已经存在的硬件的设备。(/etc/fstab)
由 initramfs 建立的内存的根分区 /sysroot( 物理 ‘/‘ 分区 ) 在成功挂载之后,将切 换到此根分区上 , 并将 systemd 重新执行安装至真实的根分区中。
systemd 开始查找所有的服务 , 开始执行 ( 停止 ) 相关的服务 , 以符合该服务的配置并解决相关的依赖问题。(/etc/systemd/system/default.target)
Systemd引入了并行启动的概念,它会为每个需要启动的守护进程建立一个套接字,这些套接字对于使用它们的进程来说是抽象的,这样它们可以允许不同守护进程之间进行交互。Systemd会创建新进程并为每个进程分配一个控制组(cgroup)。处于不同控制组的进程之间可以通过内核来互相通信。
从 7.x 版本开始,引入了 systemd 来管理服务,/etc/rc.local 是为向前兼容而保留。
开机自启
我们现在大多都在使用CentOS/RHEL7中,实现开机启动程序主要有两种方法:
在/etc/rc.local脚本文件中编写启动程序的脚本
把要启动的程序配置成自定义的systemd服务(推荐)
通过rc.local实现开机自启程序
/etc/rc.local是/etc/rc.d/rc.local的软链接
1 | [root@slions_pc1 home]# ll /etc/rc.local |
rc.local配置文件解读
1 | [root@slions_pc1 home]# cat /etc/rc.local |
rc.local本质上是一个shell脚本文件,可以把启动时需要执行的命令写在里面,启动时将按顺序执行。
rc.local编写注意
- rc.local脚本在操作系统启动时只执行一次
- 环境变量的问题
- 在rc.local脚本中执行程序时是没有环境变量的,如果执行的程序需要环境变量,可以在脚本中设置环境变量
- 命令需写绝对路径
- 不要让rc.local挂起
- rc.local是一个脚本,是按顺序执行的,执行完一个程序后才会执行下一个程序,如果某程序不是后台程序,就应该加&让程序运行在后台,否则rc.local会挂起。
- 切记chmod+x/etc/rc.d/rc.local赋予执行权限
通过system实现开机自启程序
systemd可管理的服务
操作系统使用systemd后,所有用户进程都是systemd的后代进程。
1 | [root@slions_pc1 ~]# pstree -p |
虽然从进程树关系来看,所有进程都直接或间接地受到systemd的管理,但是,并非所有systemd的子进程都受Systemd Unit管理单元的管理。只有那些由systemd方式启动的服务进程(比如systemctl命令启动)才受到Systemd Unit管理单元的监控和管理。为了简化描述,后面均直接以『systemd管理』来描述受systemd unit管理单元的管理。
比如,用户可以通过下面两种方式启动Nginx服务进程:
1 | nginx # (1) |
但systemd只能监控、管理第(2)种方式启动的nginx服务。比如第一种方式启动的nginx,无法使用systemctl stop nginx来停止。
systemd管理服务的命令
systemctl
是 Systemd 的主命令,用于管理系统。
1 | 启动、停止服务: |
因为篇幅问题,下篇继续介绍如何编写systemd service