20170828 系统启动与内核管理 (一)
- CentOS 6启动流程
- CentOS 5,6的init启动过程详解
- grub启动过程详解
- 启动过程错误修复
一、CentOS 6启动流程
(一)Linux组成
-
linux由kernel和rootfs组成:
- kernel:进程管理、内存管理、网络管理、驱动程序、文件系统、安全功能
- rootfs:包含程序和库(glibc)
-
内核涉及流派:
- 单内核(monolithic kernel):所有功能集成于一个程序,如linux
- 微内核(micro kernel):每种功能由单独子系统实现,如Windows
-
linux内核特点:
- 模块化设计:体现为众多的.ko文件(内核模块文件),实现文件系统、硬件驱动、网络协议等kernel功能
- 可以动态装载、卸载内核模块
-
linux内核组成
- 核心文件:/boot/vmlinuz-version-release
- 辅助的伪根系统ramdisk(系统启动时非常重要):
/boot/initrd-VERSION-release.img (CentOS 5)
/boot/initramfs-VERSION-release.img (CentOS 6, 7) - 模块文件:
/lib/modules/version-release目录下
(二)CentOS 6启动流程概述
-
大致流程:POST加电自检-->MBR引导-->GRUB-->加载内核-->启动init进程-->按照配置文件描述运行相应脚本
-
第1步 POST(Power-On-Self-Test):加电自检
运行BIOS的自检程序,完成硬件系统的检测。随后按照BIOS设置的启动顺序查找第一个有引导程序的设备为本次启动设备,将设备管理权限移交给启动设备上的引导程序。
-
第2步 bootloader:引导程序
位于MBR的前446字节,允许用户选择启动的系统或内核版本,装载、运行内核并把管理权限移交给内核程序。目前linux使用的主流bootloader为GRUB(CentOS 6使用GRUB 0.9, CentOS 7使用GRUB 2)
-
第3步 GRUB的分阶段引导
由于MBR给bootloader预留的空间太狭小,GRUB程序分布在硬盘的多个位置
-
primary bootloader:1st stage(位于MBR的前446字节), 1.5 stage(识别/boot分区类型并加载相应的驱动)
-
secondary bootloader:2nd stage(位于/boot/grub,显示启动菜单和用户交互程序,负责内核加载,并将管理权移交给内核)
-
-
第4步 内核自身初始化
-
探测硬件设备
-
在ramdisk提供基本驱动(只用于满足启动使用)的前提下,加载各硬件驱动
- ramdisk管理工具:mkinitrd(CentOS 6), dracut(CentOS 7)
-
以只读方式挂载根文件系统
-
-
实验:为当前正在使用的内核重新制作启动文件
mkinitrd /boot/initramfs-`uname -r`.img `uname -r`
或者
dracut /boot/initramfs-`uname -r`.img `uname -r`
删除/boot目录下的initramfs文件
重启后进入系统失败,进入救援模式,先使用chroot命令切换根目录,重建initramfs文件,重启后正常进入系统
- 第5步 运行用户空间第一个应用程序/sbin/init,启动相关服务
二、CentOS 5,6的init启动过程详解
(一)init程序类型
启动程序 | 进程名称 | 应用版本 | 配置文件 |
---|---|---|---|
SysV | init | CentOS 5之前 | /etc/inittab |
Upstart | init | CentOS 6 | /etc/inittab, /etc/init/*.conf |
Systemd | systemd | CentOS 7 | /usr/lib/systemd/system, /etc/systemd/system |
(二)运行级别
-
定义:为系统运行和维护目的而设定,共有0-6共7个级别
- 0:关机
- 1:单用户模式,root自动登录,可用于重置root密码
- 2:不完全的多用户模式,启用网络功能,但不启用NFS
- 3:完全的多用户模式
- 4:预留
- 5:图形界面模式
- 6:重启
-
默认的运行级别:/etc/inittab中设置,一般设为3或者5,不能设置为0或者6
-
修改运行级别:
init LEVEL
,LEVEL取值为0-6 -
查看运行级别:
runlevel
或who -r
-
实验:忘记root密码时重置root密码
启动时,在bootloader启动倒计时键盘任意键进入启动项管理页面
按提示输入a,在提示的画面字符串后输入1,代表进入runlevel: 1的单用户模式
无需输入密码,即可进入root账户,此时可以重置root密码
(三)CentOS 5和6的/etc/inittab文件
-
CentOS 5的/etc/inittab文件:
- 内容:文件的每一行定义一个action和与其对应的process
- 格式:
id:runlevel:action:process
说明:
id:仅起到标识作用
runlevel:运行级别
action:
(1) wait:切换至此级别运行一次
(2) respawn:若process终止,则重新运行它,一般在mingetty时使用
如:1:2345:respawn:/usr/sbin/mingettytty1
,这样结束mingetty1进程后会自动产生新的mingetty进程,保证有足够终端供人使用
(3) initdefault:设定为默认运行级别,process省略
(4) sysinit:设定系统初始化方式,一般process设为/etc/rc.d/rc.sysinit
-
CentOS 6的/etc/inittab文件和相关文件
CentOS 6的/etc/inittab文件只保留了设定默认运行级别的语句,其他内容被移动到/etc/init/*.conf各类设置文件中
(四)CentOS 5的init启动流程
(1)运行/etc/rc.d/rc.sysinit系统初始化脚本
- 主要功能:
(1) 设置主机名
(2) 设置欢迎信息
(3) 激活udev和selinux
(4) 挂载/etc/fstab文件中定义的文件系统
(5) 检测根文件系统,并以读写方式重新挂载根文件系统
(6) 设置系统时钟
(7) 激活swap设备
(8) 根据/etc/sysctl.conf文件设置内核参数
(9) 激活lvm及software raid设备
(10) 加载额外设备的驱动程序
(11) 清理操作
(2)按照/etc/inittab文件规定的默认运行级别,运行相应级别的/etc/rc.d/rcN.d(N为运行级别)目录下的文件
-
/etc/rc.d/rcN.d文件格式:
- rcN.d下的文件均为指向/etc/rc.d/init.d目录下服务的软链接文件
- 软链接的命名格式:K##或者S##
- S表示运行时开启服务,K表示运行时关闭服务
- ##代表运行顺序,排序越靠前,越先运行。排序方式为依次对比相同位置的数字字母,数字小于字母
如:100比99靠前,因为从第1位比较1比9靠前
又如:99比9a靠前,因为第1位相同,比较第2位9比a靠前 - 以K开头的服务越靠前,代表服务越依赖于其他服务,因为只有先停止本服务,被依赖的服务才能停止
- 以S开头的服务越靠前,代表服务越被其他服务所依赖,因为只有先开启本服务,依赖其运行的服务才能开启
- /etc/rc.d/rc{2,3,4,5}.d目录下最后启动的服务均为S99local,此链接文件链指向/etc/rc.d/rc.local脚本,rc.local脚本不是服务。当需要开机执行一些指令,又不想在/etc/rc.d/init.d目录下专门写一个服务脚本时,可以在本脚本文件中定义。
-
chkconfig命令:设置服务在所有运行级别的开启、关闭情况,语法设置如下:
chkconfig [--list] [service_name] //查询服务
chkconfig --add service_name //添加服务
chkconfig --del service_name //删除服务
chkconfig --levle LLLL sevice_name <on|off|reset>
//修改服务,指定的运行级别--level LLLL省略时默认为2345
chkconfig实质是修改/etc/rc.d/rcN.d目录下文件前缀K或S,如下图所示,关闭atd在runlevel 5级别下启动后,在/etc/rc.d/rc5.d目录下以S开头的atd文件消失,而以K开头的atd文件出现,同时可以看到S靠后的服务往往K靠前,反之亦然,证明先启动的服务需要后退出,而后启动的服务需要先退出
删除/etc/rc.d/rc5.d下的K05atd软链接后,手动建立S95atd软链接,使用chkconfig查询发现已经变成了on,进一步印证chkconfig的工作原理
- ntsysv:改变运行级别服务的开启、关闭情况
ntsysv [--level=RUN_LEVEL],默认修改当前运行级别
- 实验:创建一个自定义服务S97serv,添加、修改、删除服务
第1步,在/etc/rc.d/init.d目录下,新建服务脚本文件
#! /bin/bash
# checkconfig: 35 96 07 //表示在runlevel=3, 5时开启服务,在/etc/rc.d/rc3.d和/etc/rc.d/rc5.d目录下的软链接文件名前缀为S96和K07
# description: //本描述内容在CentOS 5中必须有,在CentOS 6中可以有
脚本内容略
第2步,chkconfig命令添加此服务,查询此服务在各个运行级别的开启、关闭状态是否符合服务脚本文件中的描述
第3步,chkconfig修改此服务在运行级别3的状态为off
第4步,chkconfig删除此服务
-
service命令:手动管理服务
- 语法:
service service_name start|stop|restart|status
,服务开启、关闭、重启、状态查询
service --status-all
,查询所有服务的状态
- 语法:
-
xinetd管理的服务:
- xinetd管理非独立服务(又称瞬态服务),这些服务的使用率不高,为了节省资源占用,平时xinetd服务负责监听这些服务的端口,一旦xinetd服务发现其所管理服务的请求,立即唤醒相应的服务,并将相应服务的端口移交给服务
- xinetd管理很多服务,所以又称其为超级守护进程
- 非独立服务依赖于xinetd服务,若xinetd服务尚未安装,则安装非独立服务时xinetd作为依赖服务将一并安装
- 配置文件:/etc/xinetd.conf, /etc/xinetd.d/<service>
-
实验:开启Telnet服务
第1步,chkconfig --list命令发现telnet服务属于非独立服务,需要修改xinetd服务的配置文件第2步,配置/etc/xinetd.d/telnet,将disabled的值由yes改为no,重新执行chkconfig --list命令,发现telnet的状态已经变成yes
第3步,重启xinetd服务,此时通过
netstat -ntlp
查看监听端口,发现xinetd正在监听telnet的23端口第4步,远程telnet登录本机,此时通过
ss -ntup
查看tcp端口,发现telnet正在23端口处于连接状态
(3)按照/etc/inittab文件的规定,设置登录终端
CentOS 5 init启动顺序总结:
- 运行/sbin/init,创建用户空间第一个进程-->
- 查询/etc/inittab初始化配置文件,设置默认运行级别-->
- 运行/etc/rc.d/rc.sysinit系统初始脚本、完成系统初始化-->
- 关闭(可能出现)对应下需要关闭的服务,启动需要启动服务/etc/rc.d/rcN.d-->
- 设置登录终端
- CentOS 6的启动过程与CentOS 5基本相似,区别在于CentOS 6的init启动过程配置文件为/etc/inittab和/etc/init/*.conf,遵循upstart程序规定的配置文件语法格式
三、grub启动过程详解
(一)grub简介
-
版本:
grub 0.97: CentOS 6使用,grub经典版,以下介绍的都是此版本的操作
grub 2:CentOS 7开始使用 -
grub的阶段:grub程序分布在硬盘的不同位置,被分为多个阶段
- stage 1:bootloader,位于MBR,446字节
- stage 1_5:位于MBR之后的扇区,确保stage1的bootloader能够识别stage2所在分区的文件系统
- stage 2:
1)显示启动菜单,实现与用户的交互
2)加载用户选择的内核或操作系统
3)为菜单提供了保护机制
-
stage 2 和内核文件一般安装至一个基本的磁盘分区(/boot一般是独立分区)
-
grub安装:grub-install命令
将stage 1和stage 1_5安装至启动硬盘,并复制grub相关文件至启动硬盘的启动分区
(二)grub的详细配置
(1) grub命令行模式:
-
命令:
- help:获取帮助列表
- help KEYWORD:详细帮助信息
- root (hd#,#):指定grub的根分区,即stage2文件和内核文件所在的分区
- kernel /PATH/TO/KERNEL_FILE:设定本次启动时用到的内核文件;额外还可添加许多内核支持使用的cmdline参数,可通过
cat /proc/cmdline
查询内核参数 - initrd /PATH/TO/INITRAMFS_FILE:设定为选定的内核提供额外文件的ramdisk
- boot:引导启动选定的内核
-
硬盘分区编号规则(hd#,#):
- hd#:磁盘编号,用数字表示;从0开始编号
- #:分区编号,用数字表示; 从0开始编号
- (hd0,0) 表示第一块硬盘,第一个分区
-
手动通过grub命令行启动系统:
grub> root (hd#,#) grub> kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE grub> initrd /initramfs-VERSION-RELEASE.img grub> boot
(2)grub配置文件 /boot/grub/grub.conf:
-
格式:
通用设置
default=#:默认启动菜单项,从0开始编号
timeout=#:自动进入默认启动菜单项的倒计时
splashimage=(hd#,#)/PATH/XPM_FILE:菜单界面背景图片
hiddenmenu:默认隐藏启动菜单
password [-md5|] string:启动菜单编辑认证
以下是关于菜单项的设置,可以重复使用多次用于设置多个菜单项
title TITLE:菜单项标题
root (hd#,#):指定grub的根分区,即stage2文件和内核文件所在的分区
kernel /PATH/TO/VMLINUZ_FILE:指定kernel文件的路径
initrd /PATH/TO/INITRAMFS_FILE:指定内核匹配的initramfs文件路径
password [-md5 | encrypted] string:启动选定内核或操作系统时认证 -
生成grub密码:
grub-md5-crypt:生成md5加密密码
grub-crypt:生成sha512加密密码 -
实验:/boot/grub/grub.conf文件格式要求
实验(1):判断kernel行和initrd行可否交换次序:
在/boot/grub/grub.conf文件中复制当前启动菜单选项设置,交换kernel行和initrd行的次序
重启系统,进入复制的启动项,发现错误提示:kernel必须在initrd前
按任意键回到启动菜单,键盘输入e后编辑启动项,综合使用键盘d:删除,键盘e:编辑,键盘o:新增加空行,将kernel行与initrd行交换次序,键盘b执行启动,最终成功启动
由于本次启动属于在grub中临时更改启动项,在系统启动之后,需要及时对/boot/grub/grub.conf文件进行修改,确保今后启动正常
实验(2):给grub的启动过程加密:
可以在grub的启动过程的两个环节加密:1)给启动菜单项编辑权限加密;2)启动特定菜单项的加密,加密命令相同,但是位于/boot/grub/grub.conf文件的不同位置
加密可以使用明文密码,但安全性太差。目前使用md5和sha-512加密方式加密,现在用md5加密启动项编辑权限,用sha-512加密启动特定菜单项
可以在vim编辑器下使用:r!grub-md5-crypt
和r!grub-crypt
命令直接生成md5和sha-512加密密码。启动项编辑权限加密需要在选项信息前设置(第一个红框),启动特定菜单项需要在本启动菜单项后面设置(第二个红框)。
加密选项的语法为:
md5加密:password --md5 加密密码
sha-512加密:password --encrypted 加密密码
重启后发现启动界面没有e编辑选项,提示键入p输入密码,证明已被加密
选择加密过的启动项,回车后弹出密码输入提示,证明已被加密
四、启动过程错误修复
(一)仅保留/boot/grub目录下的grub.conf文件
mv /boot/grub/* /app
mv /app/grub.conf /boot/grub
重启后发现系统正常启动,这说明进入stage 2必要的文件只有/boot/grub/grub.conf文件,其他文件只是stage1, stage 1_5, stage 2的备份文件
(二)grub的stage 1 丢失
mv /boot/grub/* /app
mv /app/grub.conf /boot/grub //在/boot/grub目录中只保留grub.conf文件
dd if=/dev/zero of=/dev/sda bs=1 count=446 //删除磁盘前446字节,即grub的stage 1
使用hexdump -C -n 512 /dev/sda
查看/dev/sda磁盘的前512字节,发现前446字节已经清零
重启后,BIOS认为/dev/sda不是启动磁盘,当没有其他启动介质时,启动失败停在黑屏中。光盘启动,进入救援模式。在救援模式下,先进行切根操作,在使用grub-install /dev/sda
命令修复,成功后即可正常启动。
修复成功后,可以看到在/boot/grub目录下丢失的文件也恢复了
(三)grub的stage 1_5丢失
dd if=/dev/zero of=/dev/sda bs=1 count=10240 skip=512 seek=512 //除stage1之外的前20个扇区的内容全部清零
使用hexdump -C -n 10240 /dev/sda
查看/dev/sda磁盘的前10240字节,发现stage1_5确实已经清零。此时重启系统,BIOS发现磁盘是引导磁盘开始stage1,但是stage1_5被破坏,故启动失败。光盘启动,进入救援模式。
切根后,使用grub交互方式恢复stage1_5
grub> root (hd0,0)
grub> setup (hd0)
运行结果发现grub程序寻找/boot/grub下面的stage1_5文件尝试恢复并成功,故这种修复方式需要确保/boot/grub/下的stage文件没有缺损。修复成功后重启成功。
(四)/boot/grub/grub.conf文件丢失
当删除/boot/grub/grub.conf文件后,重新启动系统进入stage 2但是因为没有启动项设置,进入提示符。此时,手动输入关键启动参数root, kernel, initrd等关键信息,boot回车重启成功
(五)/boot/grub下的所有文件全部丢失
删除/boot/grub目录,此时stage2文件丢失,重新启动系统报错。进入救援模式,切根后使用grub-install /dev/sda
命令修复恢复stage2文件。此外,手动编写grub.conf文件,提供启动菜单,最基本的grub.conf文件如下:
default=0
timeout=6
title linux_2.6
kernel /vmlinuz-2.6.32-696.el6.x86_64 root=/dev/sda2
initrd /initramfs-2.6.32-696.el6.x86_64.img
重启后,正常进入系统。
(六)/boot目录下的所有文件丢失
/boot目录下要恢复的文件如下:kernel文件,initramfs文件,grub stage2相关文件,grub.conf文件。这些文件的恢复操作上文都有所提及。
首先进入救援模式,切根(红框1)之后,挂载光盘(红框2),将光盘上的内核文件复制到/boot目录下(红框3),然后使用mkinitrd命令恢复initramfs文件(红框4)
使用grub-install命令恢复stage2 相关文件
编辑grub.conf文件
重新启动成功
(七)/sbin/init文件丢失
重启后,会因为没有/sbin/init文件而卡死在启动过程中。此时重新启动,编辑启动项,改为用bash启动。在bash环境下,用光盘重新安装init程序对应的软件包。
启动项画面键盘a键,进入启动项命令行编辑页面,指定由/bin/bash代替/sbin/init开始用户空间的初始化操作,行尾添加init=/bin/bash
重启后,发现可以在bash环境下操作。此时,用rpm命令查询/sbin/init文件对应的安装包为upstart,挂载光盘到/mnt目录为安装做准备。由于/目录挂载状态为只读,重新挂载并设置为读写。
rpm重新安装upstart软件包。因为只是丢失了/sbin/init文件,所以需要添加--force
选项强制覆盖安装。
重新启动后,成功进入系统。
(八)/etc/fstab文件和/boot目录下的所有文件丢失
/boot目录下的文件丢失的情况,在上文第6条已经说明。但是,由于/etc/fstab文件丢失,在救援模式下执行/etc/rc.d/rc.sysinit初始化时无法挂载分区,救援系统无法自动将根分区挂载至/mnt/sysimage下,使后续对/boot目录文件丢失的修复操作无法进行。所以这种情况需要分两步进行:第一步,重建/etc/fstab文件。第二步,重启进入救援模式,再恢复/boot目录内容。
第一次进入救援模式,提示找不到硬盘分区。
此时,手动重建/etc/fstab文件。通过fdisk -l /dev/sda
命令查看分区表,对每个分区表尝试挂载,了解分区内容,找到/boot分区和根分区,并在重建/etc/fstab文件中设置挂载信息。(红框1:确定未能成功挂载到/mnt/sysimage;红框2:尝试挂载/dev/sda1,挂载后分区没有内容,结合fdisk命令提示本分区属于启动分区,确定此分区应为/boot分区;红框3:尝试挂载/dev/sda2,挂在后分区内容很明显应为根分区。至于/dev/sda3,在fdisk命令结果已经显示为swap分区,不用再尝试挂载了)
此时重建fstab文件,需要注意由于之前根目录挂载失败,当前根分区挂载到/mnt/unknown目录下,则命令应为vi /mnt/unknown/etc/fstab
。编辑时可以使用:r!blkid
读入blkid的命令执行结果,加快编辑速度。保存退出,重启进入救援系统,此时系统正确识别文件系统。
此时的错误环境与上文第6条错误相同,修复方法参照上文。本次只尝试在安装kernel和initramfs文件的过程中,使用rpm命令安装光盘上的kernel的rpm包,提供另一种修复内核的方式。其他修复过程,完全相同。
此处需要注意的是:由于kernel的安装文件只破坏了一部分,rpm安装时必须添加--force选项强制覆盖,否则会提示已经安装而修复失败。
(九)逻辑卷环境下/etc/fstab文件和/boot目录下的所有文件丢失
与上文第8条错误相似,修复的方法也相似,但是需要考虑逻辑卷的特殊情况。重启进入救援模式,首先使用blkid, fdisk等命令查看磁盘分区情况,/boot目录不能被逻辑卷挂载,故/dev/sda1是boot分区,而/dev/sda2为逻辑卷。
lvscan命令发现当前的逻辑卷处于非活动状态,要想挂载逻辑卷,需要激活逻辑卷组,执行vgchange -ay
激活所有逻辑卷,再用lvscan查看时发现已经处于活动状态。由于逻辑卷的名称非常直观,省去了挂载逻辑卷查看内容判断真实挂载分区的步骤。
此时应建立临时挂载目录如/mnt/temp
,挂载操作mount /dev/VolGroup/lv_root /mnt/temp
,随后手动建立fstab文件于/mnt/temp/etc/目录下。保存退出后,重启再次进入救援模式。
此后的修复方式与第8条错误的修复方案相似,都是rpm强制重装kernel的rpm包恢复/boot目录下的kernel和initramfs文件,接下来是grub-install命令修复/boot/grub下的驱动文件,最后是手动重建/boot/grub/grub.conf文件。(红框1:切换根目录,红框2:挂载光盘,红框3:rpm重装kernel包,红框4:grub-install修复)
在手动建立grub.conf文件时,注意根目录的名称此时为逻辑卷,其他没有变化。
保存重启,系统正常启动。