CentOS系列啓動流程和內核原理(5系列,6系列,7系列)

前言,本來讓我寫博客我是拒絕的t_0021.gif然而看見大家都在寫,還能不能一起友好的玩耍了?

我要是不寫怎能和同大神們一起ZB呢?遂開博客!


一、Linux啓動內核文件

1.Linux系統組成

動態視角:內核+根文件系統

靜態視角:磁盤分區+相關文件

2.Kernel特點

(1)支持某塊化:.ko (kernel object)文件

centos7的ko文件:

wKiom1dAWsqgGSJbAAGIzZrrfQg922.jpg

centos6的ko文件:wKiom1dAW9PSC1y-AAGLXq46iqM024.jpg

注意:

    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文件中

wKiom1dAYD_w1ssNAAEwyRfwgfg333.jpg

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則該模塊可以隨時可以卸載。

wKiom1dAXiWCynvDAAB99f8BiMk997.jpg


總結:Linux kernel在單內核設計模型上,吸取了多內核設計的優點,使用了模塊化設計

    單內核設計:把所有功能集成於同一個程序;如Linux

    微內核設計:每種功能使用一個單獨的子系統實現;如Windows, Solaris


3.kernel組成

(1)核心文件

1)/boot/vmlinuz-VERSION-release

注: vmlinuz最後一一個z表示壓縮格式的kernel文件

wKioL1dAZq_huB2oAABysMFAEbk838.jpg        

2)ramdisk(中間臨時文件根系統,動態創建出來的,使用緩衝和緩存來加速對磁盤上的文件訪問)

參考:Linux內核Ramdisk(initrd)機制 

安裝操作系統後臨時生成的文件,能夠掃描當前操作系統的硬盤驅動,裝載對應的模塊

用於實現系統初始化的基於內存的磁盤設備,把內存中的一段空間當內存使用

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文件解壓流程:

wKiom1dBvAODPaahAAD_hnq-iVE143.jpg

wKioL1dBvPOCpS7-AABK8MPGx6w079.jpg

centos6的initrd文件解壓流程:

wKioL1dBvwrzaa3cAAD5sF2RB88287.jpg

wKiom1dBvhvToiLPAAChMC6PXVY233.jpg

修改內核後,自定義打包一個內核initrd文件:

wKiom1dBwbyyCMJLAAFqKlXG6lU156.jpg


(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(與內核版本發行號相同的目錄)/*

wKiom1dB1o3hQx76AAEUPUbWEmc257.jpg

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:

按次序查找各引導設備,第一個有引導程序的設備即爲本次啓動要用到的設備;  

wKioL1dB2b_Qcq9OAACu7XN5gEY952.jpg

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,完全重寫,設計理念上很大改變

wKiom1dB213yVMoDAAC09jdFxPs158.jpg

GRUB(GRand Unified Bootloader)加載內核,就是MBR中的前 446 個字節,是BooTLoader的一種,它的作用是要選擇要啓動的內核。

1)GRUB程序的組成:

centos6:

wKiom1dCp5WgBlGhAAEh5GGwyhI640.jpg

主要是由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 文件參數意義

wKiom1dCqLDSGNNxAABmmZIuTQ4690.jpg

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:

wKiom1dCpvPBYVj0AAE9_Syx4Sw343.jpg


3)grub的功能

(1)提供菜單,並提供交互式接口

(2)選擇要啓動的內核或系統

允許傳遞引導參數給內核

選擇界面可隱藏

# 可以自啓動是通過 grub 像內核傳遞參數。  
# 應用之一是:修改 root 密碼(忘記密碼),使用 e 選項,傳遞單用戶指令。

centos7:

wKiom1dCr8-hmir2AABAQHGjt6Q069.jpg

wKioL1dCsMCCX00rAACQjOLdlHM612.jpg

centos6:

wKiom1dCr9CTgNEnAABiGjaNLJA974.jpg

wKiom1dCr9CCKy60AAB8eLH8_eA632.jpg

wKioL1dCsMGQ-EQ5AAA_hPwJkk0395.jpg

(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風格的配置文件;各功能切割成片段

wKioL1dB5J7TNw_JAAC9CSAf16I436.jpgwKiom1dB4qShyTMoAACpuDT9ric023.jpginit-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配置文件j_0028.gif


更改默認tty數量文件:

wKiom1dB5EShDObeAABvv8d8DYU847.jpg


(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通配,數字越小排在前面

wKiom1dB5g3DvE46AAE0Y1yfXE0916.jpg

注意:開機時啓動的服務,越早開啓,關閉的時候越靠後

wKiom1dB5r6w5Q74AAENlzE8luU399.jpg

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

wKioL1dCt1bziJC3AACSbbfpEv8385.jpg

開啓的時候執行最後一個啓動腳本時,執行/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]

wKiom1dCfjaDkz0ZAACsHdnMMpQ411.jpg

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)腳本;

因此,不便或不需寫爲服務腳本的程序期望能開機自動運行時,直接放置於此腳本文件中即可。

wKioL1dCgD3RS5JcAAAyKZAlIyk994.jpg


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.設置登錄終端 [--> 啓動圖形終端]






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章