CentOS5、6的启动流程
Linux:kernel + rootfs,Linux系统就是内核加上根文件系统。
内核之上是库:
库:函数集合,function,函数具有调用接口,库函数不能单独执行,必须被其他程序调用
过程调用:procedure,没有返回结果
函数调用:function,有返回结果
程序:程序调用库或系统调用,完成业务,可以单独执行。
内核设计流派:
单内核模式:Linux,把所有功能集成于同一个程序
微内核模式:Windows,Solaris,每种功能使用一个单独子系统实现
Linux内核特点:
支持模块化:.ko(是内核的模块,相对的有.so,共享对象模块,是共享库的模块文件)
支持模块的动态装载和卸载;
组成部分:
核心文件:/boot/vmlinuz-VERSION-release
ramdisk:
CentOS 5:/boot/initrd-VERSION-release.img
CentOS 6:/boot/initramfs-VERSION-release.img
模块文件:/lib/modules/VERSION-release
ramdisk是用文件来模拟磁盘,提供最开始的根文件系统,以装载系统启动必须的驱动。
CentOS 系统启动流程:
POST:加电自检
ROM:CMOS,BIOS:Basic Input and Output System
内存是ROM+RAM组成
BOOT sequence:按次序查找各引导设备,第一个有引导程序的设备即为本次启动用到的设备
bootloader:引导加载器,程序
windows:ntloader
Linux:LILO——LInux LOader;GRUB——GRand Uniform Bootloader,GRUB有0.X版,叫做GRUB Legacy,GRUB 1.X,叫GRUB2
bootloader功能:提供一个菜单,允许用户选择要启动系统或不同的内核版本;把用户选定的内核装载到内存中的特定空间中,解压、展开,并把系统控制权移交给内核;
MBR:(0磁道0扇区)
446:bootloader
64:fat
2:55AA
GRUB:
bootloader:1st stage
disk:2nd stage
kernel:
自身初始化:
探测可识别到的所有硬件设备;
加载硬件驱动程序;(有可能会借助于ramdisk加载驱动)
以只读方式挂载根文件系统;
运行用户空间的第一个应用程序:/sbin/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
ramdisk:
内核中的特性之一:使用缓冲和缓存来加速对磁盘上的文件的访问
ramdisk --> ramfs,CentOS5将ramdisk模拟成磁盘,导致内核再次缓冲
CentOS5:initrd,工具程序:mkinitrd
CentOS6:initramfs,工具程序:mkinitrd,dracut
系统初始化:
POST --> BootSequence(BIOS) --> Bootloader(MBR) --> kernel(ramdisk) --> rootfs(只读) --> init
/sbin/init
CentOS 5:
运行级别:为了系统的运行或维护等应用目的而设定,共0-6,一个7个级别
0 :关机
1 :单用户模式(root,无须登录),single,维护模式;
2 :多用户模式,会启动网络功能,但不会启动NFS,维护模式;
3 :多用户模式,正常模式,文本界面
4 :预留级别,可同3级别
5 :多用户模式,正常模式,图形界面
默认级别:3,5
切换级别:init #
查看级别:runlevel、who -r
各级别的不同之处,主要在于init按照配置文件进行的初始化的不同
配置文件:/etc/inittab (CentOS 5)
每行定义一种action以及与之对应的process
id : runlevel : action : process
action:
wait:切换至此级别运行一次
respawn:此process终止,就重新启动之
initdefault:设定默认运行级别,process省略
sysinit:设定系统初始化方式,此处一般指定为/etc/rc.d/rc.sysinit
示例:
id : 3 : initdefault :
si : : sysinit : /etc/rc.d/rc.sysinit
l0 : 0 : wait : /etc/rc.d/rc 0
l1 : 1 : wait : /etc/rc.d/rc 1
........
l6 : 6 : wait : /etc/rc.d/rc 6
说明:rc 0-->意味着读取/etc/rc.d/rc0.d/目录下的文件(脚本链接),文件以K或S开头
K*:K##*,##运行次序,越小越先运行,K是Kill要关闭的,数字越小的服务,通常为依赖到别的服务。
S*:S##*,S是Start,要启动的,数字越小越先运行,数字小的服务,通常为被依赖到的服务。
for srv in /etc/rc.d/rc0.d/K*;do
$srv stop
done
for srv in /etc/rc.d/rc0.d/S*;do
$srv start
done
chkconfig命令:查看每个服务在不同级别下是启动还是关闭的。
chkconfig --list
chkconfig --level 3 NetworkManager off 修改级别下是启动还是关闭,即修改K或S
添加:
SysV的服务脚本放置于/etc/rc.d/init.d (/etc/init.d)
chkconfig --add name
测试添加自定义的服务:testsrv:
1)在/etc/rc.d/init.d目录下新建testsrv文件
2)给testsrv文件增加执行权限:
chmod +x testsrv
3)加到服务中去:
chkconfig --add testsrv
下图是添加服务前的文件
添加后,查看结果:
删除:
chkconfig --del name
chkconfig --del testsrv
修改指定的链接类型
chkconfig [--level levels] name <on | off | reset>
--level ####:指定要设置的级别;省略时表示2345
特殊的S99local服务:正常级别下,最后启动的一个服务,没有连接至/etc/rc.d/init.d目录下
指向的是上级目录的rc.local,是一个脚本文件,可以将不便或不需要写为服务脚本放于/etc/rc.d/init.d目录下,不需要chkconfig管理,但又想开机时自动运行的命令或脚本写入此文件。
/etc/rc.local也指向/etc/rc.d/rc.local
在init的最后,就是要启动一个供用户登录的会话窗口,使用户可以登录,登录后,启动bash进行交互操作。假设这个登录在inittab中如下:
tty1:2345:respawn:/usr/sbin/mingetty tty1
tty2:2345:respawn:/usr/sbin/mingetty tty2
......
tty6:2345:respawn:/usr/sbin/mingetty tty6
mingetty会调用login程序,以验证用户登录合法性
/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)清理操作
总结:(CentOS 5的init)
/sbin/init --> (/etc/inittab) --> 设置默认运行级别 --> 运行系统初始化脚本、完成系统初始化 -->关闭对应级别下需要关闭的服务,启动需要启动的服务 --> 设置登录终端
CentOS 6:
init程序为:upstart,由Ubuntu研制,其配置文件:/etc/inittab 、/etc/init/*.conf,主要是后者,即将CentOS5的inittab分割成多个.conf文件。
注意:/etc/init/*.conf文件语法,遵循upstart配置文件语法格式;
网上找的启动流程图:
CentOS5、6忘记密码的解决:
启动系统时,设置其运行级别1:启动时,提示按任意键进入隐藏的GRUB菜单
按e键可以编辑菜单:
root (hd0,0)指定grub根目录所在设备位置,这里是第一个硬盘的第一个分区,这里root是grub的命令,指定boot所在的分区作为grub的根目录
kernel是加载内核,指定内核文件,以只读(ro)加载文件系统的根目录,即根分区,root=。。。参数指定文件系统根分区的位置,使用了lvm
initrd是将.img文件作为虚拟磁盘载入内存,模拟根文件系统,其上有少量驱动程序等,如要使用lvm,必须加载lvm文件系统驱动
以上指定的分区、设备可以参考下面查看到的信息
通过上面的信息,root(hd0,0)就是指定/boot所在的分区,即/dev/sda1,kernel加载的内核文件 /vmlinuz-2.6.32-754.el6.x86_64,实际上是(hd0,0)/vmlinuz-2.6.32-754.el6.x86_64,这里的根是指的boot分区,后面的参数root=/dev/mapper/vg_study610-lv_root,才是指定文件系统的根分区,其使用的是lvm,看上图,mount信息中根“/”的挂载设备就是这里的参数值。initrd是在没有加载文件系统根目录前,模拟的根文件系统,以提供部分驱动。如要想使用真正的根文件系统,必须加载lvm驱动,这个就要放在initrd的文件中。
这里编辑kernel这一行,这个命令行很长,具体如下:
kernel /vmlinuz-2.6.32-754.el6.x86_64 ro root=/dev/mapper/vg_study610-lv_root rd_NO_LUKS LANG=en_US.UTF-8 rd_NO_MD rd_LVM_LV=vg_study610/lv_swap SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg_study610/lv_root KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet
在其后添加空格 1或single,表示运行于level 1级别。然后回车,确认修改,回到上一级菜单,然后按b键,表示启动运行这个内核。
不需要输入密码,直接以root登录了,然后可以修改密码。
GRUB(Boot Loader):
grub legacy(grub1)
stage 1:mbr
stage1_5:mbr之后的扇区,让stage1中的bootloader能识别stage2所在的分区上的文件系统
stage2:磁盘分区(/boot/grub/)
配置文件:/boot/grub/grub.conf <-- /etc/grub.conf
stage2及内核等通常放置于一个基本磁盘分区;
功用:
(1)提供菜单,并提供交互式接口
e:编辑模式,用于编辑菜单
c:命令模式,交互式接口
(2)加载用户选择的内核或操作系统
允许传递参数给内核|
可隐藏此菜单
(3)位菜单提供了保护机制
为编辑菜单进行认证
为启用内核或操作系统进行认证
如何识别设备:
(hd#,#):第一个#表示磁盘号,第二个#表示第#个分区,都是从0开始编号。
grub的命令行接口:
find (hd#,#)/PATH/TO/SOMEFILE:查找特定文件
root (hd#,#):指定根目录
kernel /PATH/TO/KERNEL_FILE:设定本次启动时用到的内核文件;额外还可以添加许多内核支持使用的cmdline参数,如:
init=/path/to/init , selinux=0
initrd l /PATH/TO/INITRAMFS_FILE:设定为选定的内核提供额外文件的ramdisk
boot:引导启动选定的内核
手动在grub命令行接口启动系统:
grub>root (hd0,0)
grub>kernel /vmlinuz-VERSION-RELEASE ro root=/dev/DEVICE
grub>initrd /initramfs-VERSION-RELEASE.img
grub>boot
grub配置文件:/boot/grub/grub.conf
配置项:
default=#:设定默认启动的菜单项;菜单项(title)标号从0开始
timeout=#:指定菜单项等待选项选择的时长
splashimage=(hd#,#)/PATH/TO/XPM_PIC_FILE:指明菜单项背景图片文件路径
hiddenmenu:隐藏菜单
password [--md5] STRING:菜单编辑认证
title TITLE:定义菜单项“标题”,可出现多次,引导不同的内核
root (hd#,#):grub查找stage2及kernel文件所在设备分区:为grub的“根”
kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS] :启动的内核
initrd /PATH?TO?INITRAMFS_FILE:内核匹配的ramfs文件
password [--md5] STRING:启动选定的内核或操作系统时进行认证
grub-md5-crypt:grub提供的加密工具
安装grub:grub-install命令
(1)grub-install
grub-install --root-directory=ROOT /dev/DISK
(2)grub
grub>root (hd#,#)
grub set (hd#)
实验1:新增加一块硬盘,在此硬盘上安装grub并设置init为bash。(即为新盘安装系统)
(1)新增一块硬盘
(2)对新增的磁盘做分区
使用fdisk /dev/sdb进行分区
sdb1为boot分区,sdb2为swap分区,sdb3为根分区。
(3)安装文件系统:
(4)将sdb1挂载到当前系统中,sdb1作为新系统的boot分区
(5)安装grub
运行grub-install:
grub-install --root-directory=/mnt /dev/sdb
这里需要注意的是--root-directory的指定,这里是指定boot的根,实验的boot分区是挂载在/mnt/boot下,所以/mnt/boot应该为boot的根,但是grub安装程序会自动在根下创建boot子目录,所以,如果--root-directory指定为/mnt/boot的话,最终会创建/mnt/boot/boot/grub,所以根目录指定不包括boot子目录。如下的测试:
在grub目录下,可以看到stage1,stage1_5和stage2,stage1此时已经安装到了sdb磁盘的MBR,grub中缺少配置文件,手动创建一个。
同时,在boot的根目录下,此时还没有内核文件与ramfs文件,拷贝当前系统的文件到此目录下:
这里要注意的是:第一条 root (hd0,0)为何是(hd0,0),因为最终这块磁盘要单独作为系统使用,这就成为了第一磁盘,第二条kernel中的root,是最终单独使用磁盘时,作为根目录的磁盘,即前面分区的sdb3,最终成为sda3。
然后,要成为文件系统的根,需要按照FHS,创建相应的目录结构:
拷贝bash程序到对应目录,作为新系统启动后运行的进程,一个程序要运行,不但要拷贝程序本身,还要有对用的共享库,测试拷贝的bash是否可用,可以将根切换到新系统:chroot /mnt/sysroot
修改一下grub.conf配置文件,将kernel命令添加参数init=/bin/bash,即限定kernel后的init是bash,而不是默认的init。
(6)新建虚拟机,其硬盘使用刚才的磁盘。
(7),启动新建的虚拟机
启动失败,原因是拷贝的内核中启动了selinux,在配置菜单中添加禁止selinux的参数:
系统引导成功。
实验2:本机grub损坏,但是系统还在运行中。
(1)备份MBR,然后破坏MBR,但不破坏分区表,即MBR中的前446被破坏:
此时,重启系统就会出错。
(2)使用grub-install修复:
如此,便修复了MBR。
(3)还可以进入grub命令交互界面:
指定boot根:root (hd0,0)
修复: setup (hd0)
可以看到,setup检测到stage1不存在了,然后安装执行了stage1,在MBR,然后在随后的27个扇区安装的stage1_5。
如此,也修复完毕。
实验3:本机grub损坏,重启系统了,此时需要使用使用修复模式(Rescue)进行修复,需要另外的启动盘,如光盘、U盘等。
破坏MBR:
重新启动后:
链接ISO文件,从光驱启动:
最后一项回车:
选择Rescue a CentOS system,或者在第一个界面按Esc,进入命令行,键入:linux rescue
可以看到,已经发现了已安装的系统,并将其挂载到/mnt/sysimage下。
按回车,运行shell,在shell下,切换root到原来的系统
再次启动,可以引导。
CentOS6的界面:
以上方法恢复后,重新启动引导后出现如下警告:
等待重新加载后,启动成功。
Linux Kernel:
单内核模式、但充分借鉴了微内核模式的优先,为内核引入模块化机制。
内核组成部分:
kernel:内核核心,一般为bzImage,通常在/boot目录下,名称为vmlinuz-VERSION-RELEASE
kernel object:内核对象,一般放置于/lib/moudles/VERSION-RELEASE/目录下
内核对象可以做成模块功能的,有三种选择:
[ ]:N ,不选择,不编译此功能
[M]:M,选择编译成模块
[*] :Y,编译成内核核心部分。
辅助文件:ramdisk,两种
initrd 和 initramfs
运行中的内核:uname命令
uname [option]...
-n:显示节点名称
-r:显示VERSION-RELEASE号
lsmod :查看已经装载的内核模块,此命令读取的是/proc/modules文件的内容。
查看某模块详细信息:modinfo [option] 模块名
参数:-n、-p、-a、-d、-l
装载或卸载模块命令:modprobe
装载:modprobe [-C config-file] [moudlename] [module parameters...]
配置文件:/etc/modprobe.conf,/etc/modprobe.d/*.conf
卸载:modprobe [-r] modulename...
查询模块信息时,能够看到依赖关系,这个依赖关系是保存在/lib/modules/VERSION-RELEASE/modules.dep文件中,实际使用是将其编译成二进制,即modules.dep.bin文件。
depmod命令:内核模块依赖关系文件及系统信息映射文件的生成工具。
装载或卸载内核模块的其他命令:
insmod [filename] [module option]
rmmod modulename
/proc目录:
内核把自己内部状态信息及统计信息,以及可配置参数通过proc伪文件系统加以输出。
参数:
只读:输出信息
可写:可接受用户指定“新值”来实现对内核某功能或特性的配置,主要在 /proc/sys目录
sysctl命令用于查看或设定此目录中诸多参数
sysctl -w path.to.parameter=VALUE
echo命令通过重定向的方式也可以修改大多数参数的值;
echo "VALUE" > path/to/parameter
sysctl命令,配置文件为/etc/sysctl.conf
(1)设置某参数: sysctl -w path.to.parameter=VALUE
(2)通过读取配置文件设置参数:sysctl -p [/path/to/conf_file]
内核中的路由转发:是否开启功能是配置在如下位置的:
/proc/sys/net/ipv4/ip_forward
默认为0,没有开启路由转发功能
想修改为永久有效,可以编辑/etc/sysctl.conf:
将net.ipv4.ip_forward=0改为=1
修改后不会立即生效,需要重读配置文件
常用的几个参数:
net.ipv4.ip_forward :路由转发
vm.drop_caches :回收缓存
kernel.hostname :主机名
/sys目录:
sysfs:输出内核识别出的各硬件设备的相关属性信息,也有内核对硬件特性的设定信息;有些参数是可以修改的,用于调整硬件的工作特性。
udev通过此路径下输出的信息动态为各设备创建所需要设备文件;udev是运行在用户空间程序;专用工具:udevadmin、hotplug
udev为设备创建设备文件时,会读取其事先定义好的规则文件,一般在/etc/udev/rules.d及/lib/udev/rules.d目录下。
ramdisk文件的制作:
mkinitrd [OPTION...] [<initrd-image>] <kernel-version>
mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)
dracut [OPTION]... <image> <kernel-version>
dracut /boot/initramfs-$(uname -r).img $(uname -r)
ramdisk文件是一个gz压缩文件,修改后缀名后,解压缩,再看文件类型,是cpio归档文件,将其展开,基本上是简化的根系统。sbin/目录下有switch_root,就是内核完成启动后最后的根切换要执行的程序。
编译内核:
前提:
(1)准备好开发环境;
(2)获取目标主机上硬件设备的相关信息;
(3)获取到目标主机系统功能的相关信息,例如要启用的文件系统;
开发环境:
Development Tools和Server Platform Development两个包组
目标主机硬件设备相关信息:
CPU:cat /proc/cupinfo 或lscpu 或x86info -a (这个需要安装yum install x86info)
PCI设备:lspci -v 或 lsusb -v或lsblk
了解全部硬件设备信息,hal-device
编译时可以使用现有配置文件模板,在/boot目录下有当前运行系统编译时的配置文件,可以作为新系统编译时的配置模板:/boot/config-2.6.32-754.el6.x86_64
开始:
(1)下载新版本内核源码:如linux-3.10.67.tar.gz
(2)解压到/usr/src下:tar xf linux-3.10.67.tar.gz -C /usr/src
(3)做一个链接:理ln -sv linux-3.10.67.tar.gz linux
(4)拷贝/boot/config-2.6.32-754.el6.x86_64到/usr/src/linux/下,命名为.config
(5)make menuconfig,对新编译的版本进行配置
(6)开始编译,make ,还可以启动多线程make -j 4
因为make是终端相关的,如果一不小心关闭了终端,结果就悲剧了,所以可以使用screen,打开虚拟屏幕
使用Ctrl+ad退出。
执行make -j 4开始编译。此时终端断开,进入后编译依然存在。
screen -ls查看存在的虚拟屏幕,使用screen -r 编号 重新进入
(7)make modules_install
(8)make install
安装bzImage为/boot/vmlinuz-VERSION-RELEASE
生成initramfs文件
编辑grub配置文件
(9)重启系统,并测试新内核