前言,本来让我写博客我是拒绝的然而看见大家都在写,还能不能一起友好的玩耍了?
一、Linux启动内核文件
1.Linux系统组成
动态视角:内核+根文件系统
静态视角:磁盘分区+相关文件
2.Kernel特点
(1)支持某块化:.ko (kernel object)文件
centos7的ko文件:
注意:
Linux内核模块文件的命名方式通常为<模块名称.ko>
centos6系统的内核模块被集放在/lib/modules/'uname -r '/目录下
centos7系统的内核模块被集放在/usr/lib/modules/'uname -r '/目录下
(2)支持模块运行时动态装载或卸载;
模块的相关命令:
a)加载模块:insmod modprobe
insmod和modprobe的区别
当a模块与b模块有依赖关系时,假设安装b模块需先安装a模块。
如果用insmod命令那么需要先insmod a.ko 然后再insmod b.ko。
如果用modprobe命令那么直接可以modprobeb.ko。
其中/lib/modules/“内核版本号”/modules.dep中记录了模块之间的依赖关系。
通过modprobe加载的内核均在当前的计算机内有效,计算机重新启动后需要重新加载才有效。
如果想要开机后自动挂载内核,需要将modprobe命令写入/etc/rc.sysint文件中
b)卸载模块:rmmod modprobe -r
rmmod:只需要调用模块名即可,比如安装的时候是inmod a.ko 安装完毕后该模块存在于内核中的名字为a,那么卸载该模块只需要rmmod a即可。
[root@openstack01 ~]# modprobe ip_vs #动态加载ip_vs模块 [root@openstack01 ~]# lsmod |grep ip_vs #查看模块是否加载成功 ip_vs 125220 0 libcrc32c 1246 1 ip_vs ipv6 317340 289 ip_vs [root@openstack01 ~]# modprobe -r ip_vs #卸载动态模块 [root@openstack01 ~]# lsmod |grep ip_vs #模块已经卸载干净
c)查看模块:lsmod
输出三列信息
分别为模块 占用内存 是否被调用
如果第三列为0则该模块可以随时可以卸载。
总结:Linux kernel在单内核设计模型上,吸取了多内核设计的优点,使用了模块化设计
单内核设计:把所有功能集成于同一个程序;如Linux
微内核设计:每种功能使用一个单独的子系统实现;如Windows, Solaris
3.kernel组成
(1)核心文件
1)/boot/vmlinuz-VERSION-release
注: vmlinuz最后一一个z表示压缩格式的kernel文件
2)ramdisk(中间临时文件根系统,动态创建出来的,使用缓冲和缓存来加速对磁盘上的文件访问)
安装操作系统后临时生成的文件,能够扫描当前操作系统的硬盘驱动,装载对应的模块
用于实现系统初始化的基于内存的磁盘设备,把内存中的一段空间当内存使用
CentOS 5:/boot/initrd-VERSION-release.img
工具程序:mkinitrd
CentOS 6,7:/boot/initramfs-VERSION-release.img
工具程序:dracut, mkinitrd
注意:
a)不是必须的,当自编译内核时候知道硬盘接口时候将硬盘驱动编译进kernel,ramdisk就不用了
b)initrd,基于ramdisk的磁盘映像文件;initramfs,基于ramdisk的文件系统
initrd启动该后用free查看memory时候,有一段空间被buffers和cached占用,二次缓存
从2.6内核开始,initrd.img采用cpio压缩,不再是2.4内核使用的ext2格式,无法使用mount -o loop 挂载。需要使用gunzip解压缩,然后再使用cpio解包
cpio命令: cpio - copy files to and from archives -i, --extract Extract files from an archive (run in copy-in mode) 将打包文件解压或者将设备上的备份还原到系统。 -v, --verbose Verbosely list the files processed 显示打包过程中的文件名称。 -o, --create Create the archive (run in copy-out mode) 将文件拷贝打包成文件或者将文件输出到设备上。 -d, --make-directories Create leading directories where needed 在cpio还原文件的过程中,自动的建立相应的目录。 -m, --preserve-modification-time Retain previous file modification times when creating files 在创建文件时保留以前的文件修改时间
(2)img文件压缩及解压
centos7的initrd文件解压流程:
centos6的initrd文件解压流程:
(3)img文件挂载方法
在linux中,对于img文件(例如,虚拟机的img文件),有时候需要将其挂载,以便修改其中的内容。能不能将它像iso文件一样挂载呢?
使用kpartx命令:
kpartx - Create device maps from partition tables -a Add partition mapping -d Delete partition mappings -l List partition mappings that would be added -a -p set device name-partition number delimiter -f force creation of mappings; overrides ’no_partitions’ feature -g force GUID partition table (GPT) -s sync mode. Don’t return until the partitions are created -v Operate verbosely
(然并卵,我在centos6和centos7失败)
据说这样使用: kpartx -av xxx.img mount /dev/mapper/loop0p1 /mnt
(4)模块文件:/lib/modules/VERSION-release(与内核版本发行号相同的目录)/*
arch :与平台相关的特有代码,专有的汇编级的代码
crypto:加密解密组件
drivers:驱动程序
fs :文件系统
kernel :内核自己追踪用到的文件
lib:库文件
mm:内存管理功能,memory manage
net:网络功能
sound:和声音相关的驱动程序,单独放出来,因为有很多与声音相关的×××
二、CentOS系列PC架构MBR主机启动流程
POST --> Boot Sequence(BIOS) --> Boot Loader (MBR) --> Kernel(ramdisk) --> rootfs --> switchroot --> /sbin/init -->(/etc/inittab, /etc/init/*.conf) --> 设定运行级别 --> 系统初始化脚本 --> 关闭或启动对应级别下的服务 --> 启动终端
1.POST:加电自检,检查硬件设备是否存在
用于实现POST的代码在主板上ROM(CMOS)芯片上
BIOS:Basic Input and Output System 基本上输入输出系统,固化在ROM芯片上
POST(PowerOnSelfTest)首先对每一个设备进行检查。完成后会寻找存有引导记录的设备,找到后读入操作系统引导记录,然后将系统控制权交给引导记录,并由引导记录来完成系统的顺利启动。
2.Boot Sequence:
按次序查找各引导设备,第一个有引导程序的设备即为本次启动要用到的设备;
3.MBR引导,bootloader:引导加载器,程序;
MBR(Master Boot Record) MBR记录一般是在磁盘 0 磁道 1 扇区,共512个字节。前446个字节是BootLoder,后 4*16 的 64 个字节是存放分区信息的,最后 2 个字节是校验信息,一般是 55AA。
提供一个菜单,允许用户选择要启动的系统或不同的内核版本; 把用户选定的内核装载到RAM中的特定空间中,解压、展开,而后把系统控制权移交给内核;
(1)Windows上引导加载器:ntloader
(2)Linux上引导加载器:
1)LILO:短小精悍的linux加载器,1024柱面之后无法加载,现在多用于安卓手机启动
2)GRUB:Grand Uniform Bootloader统一引导加载器
GRUB 0.X(CentOS 5/6):Grub Legacy
GRUB 1.X(CentOS 7):Grub2,完全重写,设计理念上很大改变
GRUB(GRand Unified Bootloader)加载内核,就是MBR中的前 446 个字节,是BooTLoader的一种,它的作用是要选择要启动的内核。
1)GRUB程序的组成:
centos6:
主要是由device.map,menulst,stage1,stage2,以及一系列的stage1_5组成。对于这些部分我的理解是这样:
device.map:存放的是内核文件的根分区
menu.lis:是grub.conf的链接文件,但是这个名字我觉得更与它的功能接近,就是菜单列表。里卖弄设置了可以选择的内核菜单。存放于stage2中。
stage:用于grub引导程序过大,所以分2段引导,第一段存放在MBR中,第二段存放于内核文件系统中,第一段引导完成后可以找到 第二段。 但是,第二段是存放于内核文件系统中的,此时还没有格式化文件系统,如何可以访问到第二段的 menu.lst 呢??就需要借助于中间层 stage1_5,有它来协助 stage1 段来访问 stage2 段。stage1_5通常位于 stage1 字段后的 63 个扇区。 由于stage2 在内存中存放可以使用的文件系统不确定,所以这就是有多个 stage1_5 的原因了。
2)grub.conf 文件参数意义
default=0 # 默认启动的内核title, 0 表示是第一个 timeout=5 # 默认等待时间 splashp_w_picpath=(hd0,0)/grub/splash.xpm.gz # 指定菜单的背景图片的路径。为xpm格式,采用gzip压缩,只能为14bits色 hiddenmenu # 隐藏菜单 title CentOS (2.6.32-431.el6.x86_64) # 标题名,用户可自定义 root (hd0,0) # 指定 grub 的根位置 # 指定 kernel 文件的位置,还要指出 root(系统启动后) 的位置,挂载方式 ro,这项很关键。 # 加载后会启动 init 进程。 kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=17df3f60-a2a2-4de3-bdeb-b6fb4950d848 rd_NO_LUKS KEYBOARDTYPE=pc KEYTABLE=us LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 rd_NO_LVM crashkernel=auto rhgb quiet rd_NO_DM rhgb quiet # 在内核启动过程中装载根文件系统时有用 initrd /initramfs-2.6.32-431.el6.x86_64.img
# initramfs 是以 gzip 压缩的 cpio 格式的文件。内核启动时将他作为一个临时的根文件系统。 # grub 的 stage2 将initrd加载到内存里,让后将其中的内容释放到内容中, # 内核便去执行init脚本,这时内核将控制权交给了init文件处理。 # init 它也主要是加载各种存储介质相关的设备驱动程序。当所需的驱动程序加载完后, # 会创建一个根设备,然后将根文件系统rootfs以只读的方式挂载。 # 这一步结束后,释放未使用的内存,转换到真正的根文件系统上面去,同时运行/sbin/init程序, # 执行系统的1号进程。此后系统的控制权就全权交给/sbin/init进程了。
Linux内核在初始化之后会执行init进程,而init进程会挂载我们的根文件系统,但由于init程序也是在根文件系统上的,所以这就有了悖论。
Linux采用两步走的方法来解决这个问题。
Linux2.6 版以前的方法是:除了内核vmlinuz之外还有一个独立的initrd.img映像文件,其实它就是一个文件系统映像,linux内核在初始化后会 mount initrd.img作为一个临时的根文件系统,而init进程就是在initrd.img里的,然后init进程会挂载真正的根文件系统,然后 umount initrd.img。
但Linux2.6内核的实现方式却不太一样,虽然完成的功能是一样的。Linux2.6采用initramfs。 initramfs:init ram filesystem,它是一个cpio格式的内存文件系统,制作的方法有两个,一个是http://blog.csdn.net/htttw/article/details/7215858介绍的,但这样做出来的initramfs是和内核vmlinuz分开的,因此我们需要在grub里写上initramfs的路径。
而另 一种方法是把内核和initramfs制作在一起成为一个文件,方法是在linux源码make menuconfig,然后General setup-->选择Initial RAM filesystem and RAM disk (initramfs/initrd) support,然后在Initramfs source file(s)里输入我们的initramfs目录,然后make bzImage。这种方法做出来的内核就只有一个文件,不需要指定initramfs了。
从2.6内核以后真正的内核文件是initramfs开头的!!initrd开头的注意后面的结尾dump,可能是原始备份的
centos7:
3)grub的功能
(1)提供菜单,并提供交互式接口
(2)选择要启动的内核或系统
允许传递引导参数给内核
选择界面可隐藏
# 可以自启动是通过 grub 像内核传递参数。 # 应用之一是:修改 root 密码(忘记密码),使用 e 选项,传递单用户指令。
centos7:
centos6:
(3)为编辑功能提供保护机制
启用内核文件
选择运行指定的内核得先输入密码
传递参数
使用e命令得先输入密码
[root@openstack01 ~]# grub-md5-crypt Password: Retype password: $1$32hfn$HcmdhoMIJvGir.2hNKz8W0 # 上面是生成的加密字符串 # 然后将信息加入到 grub.conf 文件中,格式如下: password --md5 $1$32hfn$HcmdhoMIJvGir.2hNKz8W0 # 当然加入 grub.conf 文件的位置不同,加密效果也不一样。 # 加入到 title 之前的话,会加密整个菜单。 # 加入到 title 指内的话,会加密对应的操作系统的入口。
4.Kernel实现功能
kernel自身初始化,实现功能
---> 探测可识别到的所有硬件设备;
---> 加载硬件驱动程序;(有可能会借助于ramdisk加载驱动)
---> 以只读方式挂载根文件系统;
---> 运行用户空间的第一个应用程序:/sbin/init
5./sbin/init管理用户空间服务进程
init程序的在不同CentOS版本上类型:
CentOS 5及以前:SysV init 配置文件:/etc/inittab
CentOS 6:Ubantu研发的Upstart 配置文件:/etc/inittab /etc/init/*.conf
CentOS 7:Systemd 配置文件:/usr/lib/systemd/system/, /etc/systemd/system/
(1)CentOS 5:
SysV init,配置文件:/etc/inittab
[root@openstack01 ~]# cat /etc/inittab id:3:initdefault: 此处 表示默认启动级别为3文本界面,不能为0级别 /etc/inittab文件:每行定义一种action 以及与之对应的process 格式:id:runlevels:action:process id:一个任务的标识符; runlevels:在哪些级别启动此任务;#,###,若此处为空则表示所有级别; action:在什么条件下启动此任务; wait:等待切换至此任务所在的级别时执行一次; respawn:再次发起;此任务终止,就自动重新启动; initdefault:设定默认运行级别;此时process会省略,不是设定任务,而是默认启动级别; sysinit:设定系统初始化方式,此处一般为指定/etc/rc.d/rc.sysinit脚本(CentOS5和6用到,7无); process:任务;
(2)CentOS 6:
init程序:upstart,但依然为/sbin/init,
其配置文件: /etc/init/*.conf, /etc/inittab(仅用于定义默认运行级别)
注意:*.conf为upstart风格的配置文件;各功能切割成片段
init-system-dbus.conf:主要在哪儿启动服务的配置文件
rcS.conf: 系统初始化脚本
start-ttys.conf:启动时的终端数量
rc.conf:启动服务的配置文件
系统初始化首先从/etc/init/rcS.conf开始
end script exec /etc/rc.d/rc.sysinit
rcS.conf里面有这样行,表明这个rcS.conf执行完后才开始执行rc.sysinit配置文件
更改默认tty数量文件:
(3)CentOS 7:不需要任何启动脚本
init程序:systemd,配置文件:/usr/lib/systemd/system/*, /etc/systemd/system/*
完全兼容SysV脚本机制;因此,service命令依然可用;不过,建议使用systemctl命令来控制服务;
# systemctl {start|stop|restart|status} name[.service]
6.启动运行级别初始化控制:/etc/rc.d/rc#.d
(1)系统运行级别:为了系统的运行或维护等目的而设定的机制;
0-6:共7个级别;
0:关机, shutdown
1:单用户模式(single user),root用户,无须认证;维护模式;
2:多用户模式(multi user),会启动网络功能,但不会启动NFS;维护模式;
3:多用户模式(mutli user),完全功能模式;文本界面;
4:预留级别:目前无特别使用目的,但习惯以同3级别功能使用;
5:多用户模式(multi user), 完全功能模式,图形界面;
6:重启,reboot
1) 默认级别:3, 5
2) 级别切换:init #
3) 级别查看命令:who -r ; runlevel
(2)/etc/rc.d目录
1)rc #脚本:接受一个运行级别数字为参数;当级别切换时启动或关闭服务
K*:要停止的服务;
K##*,优先级,数字越小,越是优先关闭;依赖的服务先关闭,而后关闭被依赖的;
S*:要启动的服务;
S##*,优先级,数字越小,越是优先启动;被依赖的服务先启动,而依赖的服务后启动;
注意:按照glob通配,数字越小排在前面
注意:开机时启动的服务,越早开启,关闭的时候越靠后
2)/etc/rc.d/rc脚本框架(vim /etc/rc.d/rc)
关闭服务脚本:
for i in /etc/rc$runlevel.d/K* ; do # Check if the subsystem is already up. subsys=${i#/etc/rc$runlevel.d/K??} [ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] || continue check_runlevel "$i" || continue # Bring the subsystem down. [ -n "$UPSTART" ] && initctl emit --quiet stopping JOB=$subsys $i stop [ -n "$UPSTART" ] && initctl emit --quiet stopped JOB=$subsys done
开启服务脚本:
for i in /etc/rc$runlevel.d/S* ; do # Check if the subsystem is already up. subsys=${i#/etc/rc$runlevel.d/S??} [ -f /var/lock/subsys/$subsys ] && continue [ -f /var/lock/subsys/$subsys.init ] && continue check_runlevel "$i" || continue # If we're in confirmation mode, get user confirmation if [ "$do_confirm" = "yes" ]; then confirm $subsys rc=$? if [ "$rc" = "1" ]; then continue elif [ "$rc" = "2" ]; then do_confirm="no" fi fi update_boot_stage "$subsys" # Bring the subsystem up. [ -n "$UPSTART" ] && initctl emit --quiet starting JOB=$subsys if [ "$subsys" = "halt" -o "$subsys" = "reboot" ]; then export LC_ALL=C exec $i start fi $i start [ -n "$UPSTART" ] && initctl emit --quiet started JOB=$subsys done
开启的时候执行最后一个启动脚本时,执行/etc/rc.d/rc.local脚本,此脚本是启动过程中最后启动的一个脚本。
S99local做了一个软链接给rc.local
(3)/etc/init.d/* (/etc/rc.d/init.d/*)脚本执行方式:
# /etc/init.d/SRV_SCRIPT {start|stop|restart|status}
# service SRV_SCRIPT {start|stop|restart|status}
1.CentOS 6:
chkconfig命令:
管理控制/etc/init.d/每个服务脚本在各级别下的启动或关闭状态;
1) 查看:chkconfig --list [name]
2) 添加:chkconfig --add name
3) 删除:chkconfig --del name
4) 修改指定的链接类型:
chkconfig [--level LEVELS] name <on|off|reset>
--level LEVELS:指定要控制的级别;默认为2345;
5) 能被添加的服务的脚本定义格式:
#!/bin/bash # # chkconfig: ### ## ## ======注释:运行级别、启动优先级、关闭优先级====== # description:
2.CentOS 7:(待续)
(4)/etc/rc.d/rc.local脚本:开机自动读取此文件中命令
正常级别下,最后启动的一个服务S99local没有链接至/etc/init.d下的某脚本
而是链接至了/etc/rc.d/rc.local (/etc/rc.local)脚本;
因此,不便或不需写为服务脚本的程序期望能开机自动运行时,直接放置于此脚本文件中即可。
7.系统初始化脚本:/etc/rc.d/rc.sysinit
(1) 设置主机名;
(2) 设置欢迎信息;
(3) 激活udev和selinux;
(4) 挂载/etc/fstab文件中定义的所有文件系统;
(5) 检测根文件系统,并以读写方式重新挂载根文件系统;
(6) 设置系统时钟;
(7) 根据/etc/sysctl.conf文件来设置内核参数;
(8) 激活lvm及软raid设备;
(9) 激活swap设备;
(10) 加载额外设备的驱动程序;
(11) 清理操作;
8.启动终端
tty1:2345:respawn:/usr/sbin/mingetty tty1
... ...
tty6:2345:respawn:/usr/sbin/mingetty
tty6
(1)mingetty会调用login程序;
(2)打开虚拟终端的程序除了mingetty之外,还有诸如getty等;
启动开机流程总结:
内核级别:
1.POST做开机启动时候的硬件检测功能
2.BootSequence(BIOS)启动加载主引导分区MBR中的引导加载器程序BootLoader
在LInux现行的BootLoader是三段划分(打破446字节限制)的GRUB程序,
第1段写在BootLoader中
第1.5段在其后扇区用于文件系统的引导
第2段在boot/grub中提供国土部接口和调用系统内核kernel
3.Kernel识别硬件、加载驱动、只读挂载根文件系统、同时交付给用户空间第一个程序/sbin/init
此处特别要注意,系统发行商为了适应多种硬件接口驱动调用,会在第一次安装系统时候,自动识别硬件接口,并调用唯一驱动程序来生成ramdisk文件,以内存当磁盘做虚根,驱动接口后会切换到真实的根文件系统上
CentOS 5系列是initrd,当磁盘映像文件会造成二次缓存缓冲
CentOS 6/7系列改进为initramfs,以文件系统形式可以不二次占用缓存和缓冲
用户空间级别
4./sbin/init接管后更具其配置文件来初始化
5.根据/sbin/init中的配置会设置默认运行级别,以及一些在/etc/init.d/设置的开机服务
6./etc/rc.d/rc.sysinit运行系统初始化脚本,完成系统初始化
7.关闭对应级别下需要停止的服务,启动对应级别下需要开启的服务
8.设置登录终端 [--> 启动图形终端]