前言,本來讓我寫博客我是拒絕的然而看見大家都在寫,還能不能一起友好的玩耍了?
一、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 # 默認等待時間 splashimage=(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.設置登錄終端 [--> 啓動圖形終端]