CentOS 7系统详细开机启动流程和关机流程
名称
bootup - 系统启动流程
描述
在系统启动过程中要涉及多个不同的组件。按下开机按钮后,首先BIOS/UEFI做最基本的硬件自检与初始化, 然后加载预设/手动选择的磁盘/网络上的引导加载器(例如GRUB2),引导加载器进一步从磁盘/网络上加载操作系统内核(例如Linux)。 对于Linux来说,内核将会(可选的)解压一个initrd(initial RAM disk)镜像(可以用dracut类的工具生成), 并执行由"rdinit="内核引导参数指定的init程序(例如systemd)以寻找并挂载根文件系统。 完成根文件系统的挂载之后,内核启动由"init="内核引导参数指定的init程序(例如systemd)以接管系统的控制权。 该init程序将会负责检测所有其他的硬件设备、挂载必要的文件系统、启动所有必要的服务,等等。 关机时,init程序将会停止所有服务、卸载所有文件系统、(可选的)返回initrd环境卸载根文件系统,最后关闭电源。
常规启动流程
当成功挂载了"root="内核引导参数指定的根文件系统之后,内核将启动由"init="内核引导参数指定的init程序, 从这个时间点开始,即进入了"常规启动流程":检测硬件设备并加载驱动、挂载必要的文件系统、启动所有必要的服务,等等。 对于systemd系统来说,上述"init程序"就是systemd进程, 而整个"常规启动流程"也以几个特殊的 target 单元(详见 )作为节点,被划分为几个阶段性步骤。 在每个阶段性步骤内部,任务是高度并行的,所以无法准确预测其中的单元的顺序,但是不同阶段之间的先后顺序总是固定的。 当启动系统时,systemd 将会以 default.target 为启动目标,借助单元之间环环相扣的依赖关系,即可完成"常规启动流程"。 通常,default.target 只是一个指向 graphical.target(图形界面) 或 multi-user.target(文本控制台) 的软连接。 为了强制启动流程的规范性以及提高单元的并行性,预先定义了一些具有特定含义的 target 单元。 下面的图表解释了这些具有特定含义的 target 单元之间的依赖关系以及各自在启动流程中的位置。 图中的箭头表示了单元之间的依赖关系与先后顺序,整个图表按照自上而下的时间顺序执行。 local-fs-pre.target | v (各个 mounts 与 (各个 swap (各个加密块设备 fsck services) devices) devices) (各个底层服务 (各个底层API虚拟 | | | services: udevd, 文件系统 mounts: v v v tmpfiles, random mqueue, configfs, local-fs.target swap.target cryptsetup.target seed, sysctl ...) debugfs ...) | | | | | \__________________|_________________ | ___________________|____________________/ \|/ v sysinit.target | ____________________________________/|\________________________________________ / | | | \ | | | | | v v | v v (各个 timers) (各个 paths) | (各个 sockets) rescue.service | | | | | v v | v v timers.target paths.target | sockets.target rescue.target | | | | v \_________________ | ___________________/ . \|/ . . . . . . . . . . . . . . . . . . . v basic.target | ____________________________________/| emergency.service / | | | | | | v v v v emergency.target display- (图形界面所必须 (各个系统服务) manager.service 的各个系统服务) | | | v | | multi-user.target | | | \_________________ | _________________/ \|/ v graphical.target 用粗体下划线标识的目标单元经常被用作启动目标。有两种方法可以指定启动目标: (1)使用 systemd.unit= 内核命令行参数(参见systemd手册);(2)使用 default.target 软连接。 因为 timers.target 以异步方式包含在 basic.target 中,所以 timer 单元可以依赖于在 basic.target 之后才启动的服务。
initrd 启动流程
在initrd内部,也可以将 systemd 用作init程序(由"rdinit="内核引导参数指定),此时 initrd.target 将是默认目标。 initrd内部启动流程的上半部分与前一小节 basic.target 之前的部分完全相同,随后的启动流程将如下图所示。 如果成功的将根文件系统挂载到 /sysroot 目录,那么 sysroot.mount 单元将被激活,然后进一步激活 initrd-root-fs.target 目标。 initrd-parse-etc.service 将会分析 /sysroot/etc/fstab 文件以挂载 /usr (若需要)与带有 x-initrd.mount 标记的挂载点。 这些挂载点都将被挂载到 /sysroot 之下,然后流程到达 initrd-fs.target 目标。 再接下来 initrd-cleanup.service 将会使用 /usr/bin/systemctl --no-block isolate initrd-switch-root.target 命令启动 initrd-switch-root.target 目标。因为 isolate 表示立即停止所有在新的目标单元中不需要的进程, 所以此动作实际上是为接下来切换根目录做预先的准备(也就是清理环境)。 最后,激活 initrd-switch-root.service 服务,将系统的根目录切换至 /sysroot 目录。 (之前的流程与上一小节完全相同) : v basic.target | emergency.service ______________________/| | / | v | sysroot.mount emergency.target | | | v | initrd-root-fs.target | | | v v initrd-parse-etc.service (各个自定义的 | initrd services) v | (sysroot-usr.mount 以及 | fstab 中带有 x-initrd.mount | 标记的各个挂载点) | | | v | initrd-fs.target \______________________ | \| v initrd.target | v initrd-cleanup.service (使用 isolates 启动 initrd-switch-root.target) | v ______________________/| / v | initrd-udevadm-cleanup-db.service v | (各个自定义的 | initrd services) | \______________________ | \| v initrd-switch-root.target | v initrd-switch-root.service | v 切换到主机上的操作系统
关机流程
systemd 系统在关机时同样遵循固定的流程,具体如下图所示: (与所有系统服务互斥) (与所有文件系统 mounts, swaps, cryptsetup devices 互斥) | | v v shutdown.target umount.target | | \______________________ _____________/ \ / v (各个底层 services) | v final.target | _____________________________________/ \_________________________________ / | | \ | | | | v v v v systemd-reboot.service systemd-poweroff.service systemd-halt.service systemd-kexec.service | | | | v v v v reboot.target poweroff.target halt.target kexec.target 用粗体下划线标识的目标单元经常被用作关机目标。