第 13 堂課:服務管理與開機流程管理
之前的課程介紹過 process 與 program 的差別,也談過 PID 資訊的觀察,以及包括 job control 等與程序相關的資料。 本節課會繼續介紹 process 管理所需要具備的 signal 資訊。另外,管理員是需要管理服務的,每個服務都是需要被啟動的 process。 最終會介紹開機流程到底是如何運作。
- 13.1:服務管理
- 13.1.1:程序的管理透過 kill 與 signal
- 13.1.2:systemd 簡介
- 13.1.3:systemctl 管理服務的啟動與關閉
- 13.1.4:systemctl 列表系統服務
- 13.1.5:systemctl 取得與切換預設操作界面
- 13.1.6:網路服務管理初探
- 13.2:開機流程管理
- 13.2.1:Linux 系統在 systemd 底下的開機流程
- 13.2.2:核心與核心模組
- 13.2.3:grub2 設定檔初探
- 13.2.4:grub2 設定檔維護
- 13.2.5:開機檔案的救援問題
- 13.3:課後練習操作
13.1:服務管理
服務就是一個被啟動的程序,這個程序可以常駐於記憶體當中提供網路連線、例行工作排程等任務,就可稱為服務。
13.1.1:程序的管理透過 kill 與 signal
一個程式被執行觸發之後會變成在記憶體當中的一個活動的單位,那就是程序 (process)。之前的課程介紹過 PID 與程序的觀察, 本小節會繼續介紹 PID 的管理方面的任務。
管理員可以透過給某程序一個訊號 (signal) 去告知該程序你想要讓它作什麼。主要的程序訊號可以使用 kill -l 或 man 7 signal 查詢, 底下擷取較常見的訊號代號與對應內容:
至於傳輸 signal 則是透過 kill 這個指令。舉例來說,若管理員想要直接讓前一堂課介紹的 rsyslogd 這個程序重讀其設定檔, 而不透過服務管理的正常機制時,可以嘗試如下處理方式:
[root@localhost ~]# pstree -p | grep rsyslog |-rsyslogd(6701)-+-{rsyslogd}(6708) | |-{rsyslogd}(6709) | `-{rsyslogd}(6710) [root@localhost ~]# kill -1 6701 [root@localhost ~]# tail /var/log/messages ....... May 24 14:57:37 www rsyslogd: [origin software="rsyslogd" swVersion="7.4.7" x-pid="6701" x-info="http://www.rsyslog.com"] rsyslogd was HUPed |
讀者可以發現在登錄檔出現了 rsyslogd 被要求重新讀取設定檔的記錄 (HUPed)!而除了 PID 之外,管理員也能夠使用指令名稱來給予 signal, 直接透過 killall 即可。如下管理方式:
[root@localhost ~]# killall -1 rsyslogd
|
例題:
|
13.1.2:systemd 簡介
從 CentOS 7.x 以後,Red Hat 系列的 distribution 放棄沿用多年的 System V 開機啟動服務的流程, 改用 systemd 這個啟動服務管理機制~採用 systemd 的原因如下:
- 平行處理所有服務,加速開機流程
- 一經要求就回應的 on-demand 啟動方式 (因為 systemd 為單一程序且常駐於記憶體)
- 服務相依性的自我檢查
- 依 daemon 功能分類
- 將多個 daemons 集合成為一個群組
但是 systemd 也有許多存在的問題:
- 全部的 systemd 都用 systemctl 這個管理程式管理,而 systemctl 支援的語法有限制,不可自訂參數。
- 如果某個服務啟動是管理員自己手動執行啟動,而不是使用 systemctl 去啟動的,那麼 systemd 將無法偵測到該服務
- systemd 啟動過程中,無法與管理員透過 standard input 傳入訊息!因此,自行撰寫 systemd 的啟動設定時,務必要取消互動機制
- systemd 的設定檔放置目錄
基本上, systemd 將過去所謂的 daemon 執行腳本通通稱為一個服務單位 (unit),而每種服務單位依據功能來區分時,就分類為不同的類型 (type)。 基本的類型有包括系統服務、資料監聽與交換的插槽檔服務 (socket)、儲存系統狀態的快照類型、提供不同類似執行等級分類的操作環境 (target) 等等。 至於設定檔都放置在底下的目錄中:
- /usr/lib/systemd/system/:每個服務最主要的啟動腳本設定;
- /run/systemd/system/:系統執行過程中所產生的服務腳本,這些腳本的優先序要比 /usr/lib/systemd/system/ 高!
- /etc/systemd/system/:管理員依據主機系統的需求所建立的執行腳本,執行優先序又比 /run/systemd/system/ 高!
也就是說,到底系統開機會不會執行某些服務其實是看 /etc/systemd/system/ 底下的設定,所以該目錄底下就是一大堆連結檔。而實際執行的 systemd 啟動腳本設定檔, 其實都是放置在 /usr/lib/systemd/system/ 底下的!
- systemd 的 unit 類型分類說明
/usr/lib/systemd/system/ 內的資料主要使用副檔名來進行分類,底下嘗試找出 cron 與 multi-user 這些服務的資料:
[root@localhost ~]# ll /usr/lib/systemd/system/ | grep -E '(multi|cron)' -rw-r--r--. 1 root root 284 7月 27 2015 crond.service -rw-r--r--. 1 root root 597 11月 20 2015 multipathd.service -rw-r--r--. 1 root root 492 11月 20 2015 multi-user.target drwxr-xr-x. 2 root root 4096 2月 18 02:56 multi-user.target.wants lrwxrwxrwx. 1 root root 17 2月 18 02:55 runlevel2.target -> multi-user.target lrwxrwxrwx. 1 root root 17 2月 18 02:55 runlevel3.target -> multi-user.target lrwxrwxrwx. 1 root root 17 2月 18 02:55 runlevel4.target -> multi-user.target |
所以我們可以知道 crond 其實算是系統服務 (service),而 multi-user 要算是執行環境相關的類型 (target type)。根據這些副檔名的類型, 我們大概可以找到幾種比較常見的 systemd 的服務類型如下:
副檔名 | 主要服務功能 |
.service | 一般服務類型 (service unit):主要是系統服務,包括伺服器本身所需要的本機服務以及網路服務都是!比較經常被使用到的服務大多是這種類型! |
.socket | 內部程序資料交換的插槽服務 (socket unit): 這種類型的服務通常在監控訊息傳遞的插槽檔,當有透過此插槽檔傳遞訊息來說要連結服務時,就依據當時的狀態將該用戶的要求傳送到對應的 daemon, 若 daemon 尚未啟動,則啟動該 daemon 後再傳送用戶的要求。 使用 socket 類型的服務一般是比較不會被用到的服務,因此在開機時通常會稍微延遲啟動的時間。一般用於本機服務比較多, 例如我們的圖形界面很多的軟體都是透過 socket 來進行本機程序資料交換的行為。 |
.target | 執行環境類型 (target unit):其實是一群 unit 的集合,例如上面表格中談到的 multi-user.target 其實就是一堆服務的集合~也就是說, 選擇執行 multi-user.target 就是執行一堆其他 .service 或/及 .socket 之類的服務就是了! |
其中又以 .service 的系統服務類型最常見。
例題:
|
13.1.3:systemctl 管理服務的啟動與關閉
一般來說,服務的啟動有兩個階段,一個是『開機的時候設定要不要啟動這個服務』, 以及『現在要不要啟動這個服務』兩個階段。 這兩個階段都可以使用 systemctl 指令來管理。systemctl 的基本語法為:
[root@localhost ~]# systemctl [command] [unit]
|
上表所謂的 command 主要有:
- start :立刻啟動後面接的 unit
- stop :立刻關閉後面接的 unit
- restart :立刻關閉後啟動後面接的 unit,亦即執行 stop 再 start 的意思
- reload :不關閉後面接的 unit 的情況下,重新載入設定檔,讓設定生效
- enable :設定下次開機時,後面接的 unit 會被啟動
- disable :設定下次開機時,後面接的 unit 不會被啟動
- status :目前後面接的這個 unit 的狀態,會列出有沒有正在執行、開機預設執行否、登錄等資訊等!
例題:
|
13.1.4:systemctl 列表系統服務
預設的情況下, systemctl 可以列出目前系統已經啟動的服務群,如下列表:
[root@localhost ~]# systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION
.......
chronyd.service loaded active running NTP client/server
crond.service loaded active running Command Scheduler
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
timers.target loaded active active Timers
systemd-tmpfiles-clean.timer loaded active waiting Daily Cleanup of Temporary Directories
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
153 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
|
列表當中,LOAD/ACTIVE/DESCRIPTION 等意義為:
- UNIT :項目的名稱,包括各個 unit 的類別 (看副檔名)
- LOAD :開機時是否會被載入,預設 systemctl 顯示的是有載入的項目而已喔!
- ACTIVE :目前的狀態,須與後續的 SUB 搭配!就是我們用 systemctl status 觀察時,active 的項目!
- DESCRIPTION :服務的詳細描述
如上表顯示 chronyd 為 service 的類別,下次開機會啟動 (load),而現在的狀態是運作中 (active running)。最底下兩行顯示共有 153 的 unit 顯示在上面, 如果想要列出系統上還沒有被列出的服務群,可以加上 --all 來繼續觀察。此外,我們也能夠僅針對 service 的類別來觀察,如下所示:
[root@localhost ~]# systemctl list-units --type=service --all
|
如果想要觀察更詳細的每個啟動的資料,可以透過底下的方式來處理:
[root@localhost ~]# systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
.......
mdadm-last-resort@.timer static
systemd-readahead-done.timer static
systemd-tmpfiles-clean.timer static
unbound-anchor.timer disabled
368 unit files listed.
|
例題:
|
13.1.5:systemctl 取得與切換預設操作界面
Linux 預設的操作畫面可以是純文字也能夠是文字加上圖形界面。早期的 systemV 系統稱文字界面為 runlevel 3 而圖形界面為 runlevel 5。 systemd 提供多種的操作界面,主要是透過『 target 』這種 unit 來作為規範。讀者可以使用如下的指令來觀察所有的 target:
[root@localhost ~]# systemctl list-units --type=target --all
|
在 CentOS 7 底下常見的操作界面 (target unit) 有底下幾種:
- multi-user.target:純文字模式
- graphical.target:文字加上圖形界面,其實就是 multi-user.target 再加圖形操作。
- rescue.target:在無法使用 root 登入的情況下,systemd 在開機時會多加一個額外的暫時系統,與你原本的系統無關。這時你可以取得 root 的權限來維護你的系統。
- emergency.target:緊急處理系統的錯誤,還是需要使用 root 登入的情況,在無法使用 rescue.target 時,可以嘗試使用這種模式!
- shutdown.target:就是關機的流程。
- getty.target:可以設定你需要幾個 tty 之類的,如果想要降低 tty 的項目,可以修改這個東西的設定檔!
而上述的操作模式中,預設的是 multi-user 與 graphical 這兩種。其實這些模式彼此之間還是有相依性的,讀者可以使用如下的方式查出來 graphical 執行前, 有哪些 target 需要被執行:
[root@localhost ~]# systemctl list-dependencies graphical.target
graphical.target
● ├─.......
● └─multi-user.target
● ├─.......
● ├─basic.target
● │ ├─.......
● │ ├─sockets.target
● │ │ └─.......
● │ ├─sysinit.target
● │ │ ├─.......
● │ │ ├─local-fs.target
● │ │ │ └─.......
● │ │ └─swap.target
● │ │ └─.......
● │ └─timers.target
● │ └─.......
● ├─getty.target
● │ └─.......
● ├─nfs-client.target
● │ └─.......
● └─remote-fs.target
● └─nfs-client.target
● └─.......
|
上述的表格已經精簡化過,僅保留了 unit=target 的項目,從裡面讀者也能夠發現到要執行 graphical 之前,還得需要其他的 target 才行。 若須取得目前的操作界面,可以使用如下的方式來處理:
[root@localhost ~]# systemctl get-default
graphical.target
|
若需要設定預設的操作界面,例如將原本的圖形界面改為文字界面的操作方式時,可以使用如下的方式來處理:
[root@localhost ~]# systemctl set-default multi-user.target Removed symlink /etc/systemd/system/default.target. Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/multi-user.target. [root@localhost ~]# systemctl get-default multi-user.target |
如此即可將文字界面設定為預設的操作環境。上述的作法是開機時才進行的預設操作環境界面,若需要即時將圖形界面改為文字界面, 或者反過來處理時,可以使用如下的方式來處置:
[root@localhost ~]# systemctl isolate multi-user.target
|
例題:
|
13.1.6:網路服務管理初探
如果是網路服務,一般都會啟動監聽界面在 TCP 或 UDP 的封包埠口上。取得目前監聽的埠口可以使用如下的方式:
[root@localhost ~]# netstat -tlunp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1452/dnsmasq
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 29941/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 29938/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 30092/master
tcp6 0 0 :::22 :::* LISTEN 29941/sshd
tcp6 0 0 ::1:631 :::* LISTEN 29938/cupsd
tcp6 0 0 ::1:25 :::* LISTEN 30092/master
udp 0 0 0.0.0.0:53273 0.0.0.0:* 29287/avahi-daemon:
udp 0 0 192.168.122.1:53 0.0.0.0:* 1452/dnsmasq
udp 0 0 0.0.0.0:67 0.0.0.0:* 1452/dnsmasq
udp 0 0 0.0.0.0:5353 0.0.0.0:* 29287/avahi-daemon:
udp 0 0 0.0.0.0:514 0.0.0.0:* 29256/rsyslogd
udp6 0 0 :::514 :::* 29256/rsyslogd
|
重點在 Local Address 那一行,會顯示該服務是啟動在本機的哪一個 IP 界面的哪一個埠口上,如此管理員即可了解啟動該埠口的服務是哪一個。 若無須該網路服務,則可以將該程序關閉。以上述表格來說,如果需要關閉 avahi-daemon 以及 cupsd 時,可以使用如下的方式取得服務名稱:
[root@localhost ~]# systemctl list-unit-files | grep -E '(avahi|cups)'
cups.path enabled
avahi-daemon.service enabled
cups-browsed.service disabled
cups.service enabled
avahi-daemon.socket enabled
cups.socket enabled
|
若需要將其關閉,則應該使用如下的方式,將『目前』與『預設』的服務啟動都關閉才行:
[root@localhost ~]# systemctl stop avahi-daemon.service avahi-daemon.socket [root@localhost ~]# systemctl stop cups.path cups.service cups.socket [root@localhost ~]# systemctl disable avahi-daemon.service avahi-daemon.socket [root@localhost ~]# systemctl disable cups.path cups.service cups.socket [root@localhost ~]# netstat -tlunp |
讀者將可發現到 avahi-daemon 以及 cupsd 的服務已經被關閉。而若需要啟動某個網路服務,則需要了解到該服務是由哪一個軟體所啟動的, 該軟體需要先安裝後才可以啟動該服務。
例題:
|
13.2:開機流程管理
系統如果出錯,可能需要進入救援模式才能夠處理相關的任務。但如何進入救援模式?這就需要從開機流程分析來下手。
13.2.1:Linux 系統在 systemd 底下的開機流程
一般正常的情況下, Linux 的開機流程會是如下所示:
- 載入 BIOS 的硬體資訊與進行自我測試,並依據設定取得第一個可開機的裝置;
- 讀取並執行第一個開機裝置內 MBR 的 boot Loader (亦即是 grub2, spfdisk 等程式);
- 依據 boot loader 的設定載入 Kernel ,Kernel 會開始偵測硬體與載入驅動程式;
- 載入 kernel file 與 initramfs 檔案在記憶體內解壓縮
- initramfs 會在記憶體模擬出系統根目錄,提供 kernel 相關的驅動程式模組
- 核心裝置驅動程式完整的驅動硬體
- 在硬體驅動成功後,Kernel 會主動呼叫 systemd 程式,並以 default.target 流程開機;
- systemd 執行 sysinit.target 初始化系統及 basic.target 準備作業系統;
- systemd 啟動 multi-user.target 下的本機與伺服器服務;
- systemd 執行 multi-user.target 下的 /etc/rc.d/rc.local 檔案;
- systemd 執行 multi-user.target 下的 getty.target 及登入服務;
- systemd 執行 graphical 需要的服務
如上,讀者們可以發現核心檔案驅動系統完成後,接下來就是 systemd 的任務,也就是前一小節所探討的內容。但核心檔案在哪裡? 以及如何設定不同的核心檔案開機,那就是開機管理程式的任務了。
例題:
|
13.2.2:核心與核心模組
系統的核心大多放置於 /boot/vmlinuz* 開頭的檔案中,而 initramfs 則放置於 /boot/initramfs* 。 至於核心的模組則放置於 /lib/modules/$(uname -r)/ 目錄內。
目前系統上面已經載入的模組,可以使用底下的方式來觀察:
[root@localhost ~]# lsmod [root@localhost ~]# lsmod | grep xfs |
找到名為 xfs 的模組後,若想了解該模組的功能,可以使用如下的方式查詢:
[root@localhost ~]# modinfo xfs
filename: /lib/modules/3.10.0-327.el7.x86_64/kernel/fs/xfs/xfs.ko
license: GPL
description: SGI XFS with ACLs, security attributes, no debug enabled
author: Silicon Graphics, Inc.
alias: fs-xfs
rhelversion: 7.2
srcversion: 978077FBDF054363971A9EE
depends: libcrc32c
intree: Y
vermagic: 3.10.0-327.el7.x86_64 SMP mod_unload modversions
signer: CentOS Linux kernel signing key
sig_key: 79:AD:88:6A:11:3C:A0:22:35:26:33:6C:0F:82:5B:8A:94:29:6A:B3
sig_hashalgo: sha256
|
若想要載入某個模組,就使用 modprobe 來載入,卸載則使用 modprobe -r 來卸載即可。
例題:
|
- 使用 /etc/sysctl.conf 處理核心參數
某些情況下,你會需要更動核心參數。而預設的核心參數位於 /proc/sys/ 底下。一般不建議使用者直接使用手動修改方式處理 /proc 內的檔案 (因為下次開機就不會持續提供),應使用修改 /etc/sysctl.conf 來處理。舉例而言,若你的 server 不想要回應 ping 的封包, 則可以如此測試:
[root@localhost ~]# ping -c 2 localhost PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.050 ms 64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.049 ms --- localhost ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.049/0.049/0.050/0.007 ms [root@localhost ~]# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all [root@localhost ~]# ping -c 2 localhost PING localhost (127.0.0.1) 56(84) bytes of data. --- localhost ping statistics --- 2 packets transmitted, 0 received, 100% packet loss, time 999ms [root@localhost ~]# echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all |
讀者可以發現 icmp 確實不會回應 ping 的要求了。而這個設定值如果一定要每次開機都生效, 可以寫入 sysctl.conf 內,寫法為:
[root@localhost ~]# vim /etc/sysctl.conf net.ipv4.icmp_echo_ignore_all = 1 [root@localhost ~]# sysctl -p [root@localhost ~]# cat /proc/sys/net/ipv4/icmp_echo_ignore_all 1 |
如此則可以每次都生效了。不過,這個功能對於內部環境的測試還是很重要的,因此還是請修訂回來比較妥當。
例題:
|
13.2.3:grub2 設定檔初探
核心的載入與設定是由開機管理程式來處理的,而 CentOS 7 預設的開機管理程式為 grub2 這一個軟體。該軟體的優點包括有:
- 認識與支援較多的檔案系統,並且可以使用 grub2 的主程式直接在檔案系統中搜尋核心檔名;
- 開機的時候,可以『自行編輯與修改開機設定項目』,類似 bash 的指令模式;
- 可以動態搜尋設定檔,而不需要在修改設定檔後重新安裝 grub2 。亦即是我們只要修改完 /boot/grub2/grub.cfg 裡頭的設定後,下次開機就生效了!
- 磁碟在 grub2 內的代號定義
開機時,資料得從磁碟讀出,因此磁碟、分割槽的代號資訊得先要了解釐清才行。 grub2 對磁碟的代號定義如下:
(hd0,1) # 一般的預設語法,由 grub2 自動判斷分割格式 (hd0,msdos1) # 此磁碟的分割為傳統的 MBR 模式 (hd0,gpt1) # 此磁碟的分割為 GPT 模式 |
- 硬碟代號以小括號 ( ) 包起來;
- 硬碟以 hd 表示,後面會接一組數字;
- 以『搜尋順序』做為硬碟的編號!(這個重要!)
- 第一個搜尋到的硬碟為 0 號,第二個為 1 號,以此類推;
- 每顆硬碟的第一個 partition 代號為 1 ,依序類推。
所以說,整個硬碟代號為:
硬碟搜尋順序 | 在 Grub2 當中的代號 |
第一顆(MBR) | (hd0) (hd0,msdos1) (hd0,msdos2) (hd0,msdos3).... |
第二顆(GPT) | (hd1) (hd1,gpt1) (hd1,gpt2) (hd1,gpt3).... |
第三顆 | (hd2) (hd2,1) (hd2,2) (hd2,3).... |
- /boot/grub2/grub.cfg 設定檔的理解
基本上,開機時 grub2 會去讀取的設定檔就是 grub.cfg 這個檔案,但是這個檔案是由系統程式分析建立的,不建議讀者們手動修改。 因此底下讀者先觀察該檔案內容即可,先不要修訂。
[root@localhost ~]# cat /boot/grub2/grub.cfg ### BEGIN /etc/grub.d/00_header ### set pager=1 if [ -s $prefix/grubenv ]; then load_env fi ....... if [ x$feature_timeout_style = xy ] ; then set timeout_style=menu set timeout=5 # Fallback normal timeout code in case the timeout_style feature is # unavailable. else set timeout=5 fi ### END /etc/grub.d/00_header ### ### BEGIN /etc/grub.d/00_tuned ### set tuned_params="" ### END /etc/grub.d/00_tuned ### ### BEGIN /etc/grub.d/01_users ### if [ -f ${prefix}/user.cfg ]; then source ${prefix}/user.cfg if [ -n ${GRUB2_PASSWORD} ]; then set superusers="root" export superusers password_pbkdf2 root ${GRUB2_PASSWORD} fi fi ### END /etc/grub.d/01_users ### ### BEGIN /etc/grub.d/10_linux ### menuentry 'CentOS Linux (3.10.0-327.el7.x86_64) 7 (Core)' --class centos --class gnu-linux --class gnu --class os --unrestricted $menuentry_id_option 'gnulinux-3.10.0-327.el7.x86_64-advanced-fb871e94-6242-48c9-82ee-3c2df02a070e' { load_video set gfxpayload=keep insmod gzio insmod part_gpt insmod xfs set root='hd0,gpt2' if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root --hint='hd0,gpt2' ..... else search --no-floppy --fs-uuid --set=root a026bf1c-3028-4962-88e3-cd92c6a2a877 fi linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/centos-root ro rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet LANG=en_US.UTF-8 initrd16 /initramfs-3.10.0-327.el7.x86_64.img } ....... ### END /etc/grub.d/10_linux ### ....... ### BEGIN /etc/grub.d/40_custom ### # This file provides an easy way to add custom menu entries. Simply type the # menu entries you want to add after this comment. Be careful not to change # the 'exec tail' line above. ### END /etc/grub.d/40_custom ### |
上表中 menuentry 後面接的就是選單的的標題與實際的內容了。而該內容比較重要的項目有:
- set root='hd0,gpt2':這 root 是指定 grub2 設定檔所在的那個裝置。如果你下達 df 這個指令,會發現到 /boot 這個目錄是掛載於 /dev/vda2 這個裝置上, 因此設定資訊就是在 /dev/vda2 亦即 grub2 的 (hd0,2) 。也因為我們用的是 gpt 的分割格式,因此系統就用 (hd0,gpt2) 來顯示。
- linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=/dev/mapper/centos-root ....:這一行指的是核心檔案在哪裡?因為我們的核心在 /boot/vmlinuz.... 上面, 而 /boot 是在 /dev/vda2 上面,因此檔名為 (/dev/vda2)/vmlinuz-...,由於上一個 set root 已經指定了 (hd0,gpt2) 了,因此這裡就簡寫為 /vmlinuz-... 囉。 後面參數接的 root 就是 Linux 根目錄所在了。
- initrd16 /initramfs-3.10.0-327.el7.x86_64.img:指的當然就是 initramfs 檔案的所在,檔名的設計與 linux16 相同。
13.2.4:grub2 設定檔維護
基本上,修改 grub2 設定檔你可以在如下的位置進行:
- /etc/default/grub:主要修改環境設定
- /etc/grub.d/ :可以設定其他選單
主要環境設定內容為:
[root@www ~]# cat /etc/default/grub GRUB_TIMEOUT=5 # 指定預設倒數讀秒的秒數 GRUB_DEFAULT=saved # 指定預設由哪一個選單來開機,預設開機選單之意 GRUB_DISABLE_SUBMENU=true # 是否要隱藏次選單,通常是藏起來的好! GRUB_TERMINAL_OUTPUT="console" # 指定資料輸出的終端機格式,預設是透過文字終端機 GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet" # 就是在 menuentry 括號內的 linux16 項目後續的核心參數 GRUB_DISABLE_RECOVERY="true" # 取消救援選單的製作 |
若有修改上述檔案,則需要使用 grub2-mkconfig -o /boot/grub2/grub.cfg 來進行修訂。現在假設:
- 開機選單等待 40 秒鐘
- 預設用第一個選單開機
- 選單請顯示出來不要隱藏
- 核心外帶『elevator=deadline』的參數值
那應該要如何處理 grub.cfg 呢?基本上,你應該要修訂 /etc/default/grub 的內容如下:
[root@localhost ~]# vim /etc/default/grub GRUB_TIMEOUT=40 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=0 GRUB_TIMEOUT_STYLE=menu GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_CMDLINE_LINUX="rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet elevator=deadline" GRUB_DISABLE_RECOVERY="true" |
修改完畢之後再來則是進行輸出修訂的任務:
[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-327.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-327.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-741c73b552ed495d92a024bc7a9768cc
Found initrd image: /boot/initramfs-0-rescue-741c73b552ed495d92a024bc7a9768cc.img
done
|
若想要知道是否完整的變更了,請 vim /boot/grub2/grub.cfg 查閱相關設定值是否變更即可。
- 選單建置的腳本 /etc/grub.d/*
grub2-mkconfig 執行之後會去分析 /etc/grub.d/* 裡面的檔案,然後執行該檔案來建置 grub.cfg。至於 /etc/grub.d/ 目錄底下會有這些檔案存在:
- 00_header:主要在建立初始的顯示項目,包括需要載入的模組分析、螢幕終端機的格式、倒數秒數、選單是否需要隱藏等等,大部分在 /etc/default/grub 裡面所設定的變數,大概都會在這個腳本當中被利用來重建 grub.cfg 。
- 10_linux:根據分析 /boot 底下的檔案,嘗試找到正確的 linux 核心與讀取這個核心需要的檔案系統模組與參數等,都在這個腳本運作後找到並設定到 grub.cfg 當中。 因為這個腳本會將所有在 /boot 底下的每一個核心檔案都對應到一個選單,因此核心檔案數量越多,你的開機選單項目就越多了。 如果未來你不想要舊的核心出現在選單上,那可以透過移除舊核心來處理即可。
- 30_os-prober:這個腳本預設會到系統上找其他的 partition 裡面可能含有的作業系統,然後將該作業系統做成選單來處理就是了。 如果你不想要讓其他的作業系統被偵測到並拿來開機,那可以在 /etc/default/grub 裡面加上『 GRUB_DISABLE_OS_PROBER=true 』取消這個檔案的運作。
- 40_custom:如果你還有其他想要自己手動加上去的選單項目,或者是其他的需求,那麼建議在這裡補充即可!
所以,一般來說,我們會更動到的就是僅有 40_custom 這個檔案即可。那這個檔案內容也大多在放置管理員自己想要加進來的選單項目就是了。 好了,那問題來了,我們知道 menuentry 就是一個選單,那後續的項目有哪些東西呢?簡單的說,就是這個 menuentry 有幾種常見的設定? 亦即是 menuentry 的功能啦!常見的有這幾樣:
- 直接指定核心開機
基本上如果是 Linux 的核心要直接被用來開機,那麼你應該要透過 grub2-mkconfig 去抓 10_linux 這個腳本直接製作即可,因此這個部份你不太需要記憶! 因為在 grub.cfg 當中就已經是系統能夠捉到的正確的核心開機選單了!不過如果你有比較特別的參數需要進行呢?這時候你可以這樣作: (1)先到 grub.cfg 當中取得你要製作的那個核心的選單項目,然後將它複製到 40_custom 當中 (2)再到 40_custom 當中依據你的需求修改即可。
這麼說或許你很納悶,我們來做個實際練習好了:
問: 如果你想要使用第一個原有的 menuentry 取出來後,增加一個選單,該選單可以強制 systemd 使用 graphical.target 來啟動 Linux 系統,
讓該選單一定可以使用圖形界面而不用理會 default.target 的連結,該如何設計?
答:
當核心外帶參數中,有個『 systemd.unit=??? 』的外帶參數可以指定特定的 target 開機!因此我們先到 grub.cfg 當中,去複製第一個 menuentry ,
然後進行如下的設定:
|
- 透過 chainloader 的方式移交 loader 控制權
所謂的 chain loader (開機管理程式的鏈結) 僅是在將控制權交給下一個 boot loader 而已, 所以 grub2 並不需要認識與找出 kernel 的檔名 ,『 他只是將 boot 的控制權交給下一個 boot sector 或 MBR 內的 boot loader 而已 』 所以通常他也不需要去查驗下一個 boot loader 的檔案系統!
一般來說, chain loader 的設定只要兩個就夠了,一個是預計要前往的 boot sector 所在的分割槽代號, 另一個則是設定 chainloader 在那個分割槽的 boot sector (第一個磁區) 上!假設我的 Windows 分割槽在 /dev/sda1 ,且我又只有一顆硬碟,那麼要 grub 將控制權交給 windows 的 loader 只要這樣就夠了:
menuentry "Windows" { insmod chain # 你得要先載入 chainloader 的模組對吧? insmod ntfs # 建議加入 windows 所在的檔案系統模組較佳! set root=(hd0,1) # 是在哪一個分割槽~最重要的項目! chainloader +1 # 請去 boot sector 將 loader 軟體讀出來的意思! } |
透過這個項目我們就可以讓 grub2 交出控制權了!
問:
假設你的測試系統上面使用 MBR 分割槽,並且出現如下的資料:
答:
windows 7 在 /dev/vda2 亦即是 hd0,msdos2 這個地方,而 MBR 則是 hd0 即可,不需要加上分割槽啊!因此整個設定會變這樣:
|
13.2.5:開機檔案的救援問題
一般來說,如果是檔案系統錯誤,或者是某些開機過程中的問題,我們可以透過開機時進入 grub2 的互動界面中, 在 linux16 的欄位,加入 rd.break 或者是 init=/bin/bash 等方式來處理即可。但是,如果是 grub2 本身就有問題, 或者是根本就是核心錯誤,或者是 initramfs 出錯時,那就無法透過上述的方式來處理了。
在 CentOS 7 的操作經驗中,在升級核心時,偶而會有 initramfs 製作錯誤的情況導致新核心無法開機的問題。 此時,若你已經沒有保留舊的核心,此時就無法順利開機了。
要處理這個問題,最常見的就是透過『原版光碟開機,然後使用救援模式 (rescue) 來自動偵測硬碟系統, 再透過 chroot 的動作,同時使用 dracut 來重建 initramfs 』即可。
- 調整 BIOS 變成光碟開機 (或 USB 開機),同時放入原版光碟,之後開機
- 進入光碟安裝模式後,選擇『 Troubleshooting 』的項目,再選擇『 Rescue a CentOS Linux system 』環境
- 此時系統會自動偵測硬碟,然後載入適當的模組,之後應該會找到我們的硬碟
- 當出現 1)Continue, 2)Read-only mount, 3)Skip to shell, 4)Quit(reboot) 時,按下 1 即可!
- 若一切都順利,光碟環境會提供『 chroot /mnt/sysimage 』指令,作為切換成原本系統的手動。
- 進入 shell 環境後,輸入『 df 』應該會看到原本系統資料通通掛載在 /mnt/sysimage 底下, 因此請使用『 chroot /mnt/sysimage 』指令來進入原本的系統。
- 使用底下的指令來找到 initramfs 的檔名:
上面那個 initramfs-3.10.0-514.el7.x86_64.img 就是等等我們需要建立的檔名了!sh4.2# grep init /boot/grub2/grub.cfg initrd16 /initramfs-3.10.0-514.el7.x86_64.img initrd16 /initramfs-0-rescue-741c73b552ed495d92a024bc7a9768cc.img
- 透過 dracut 來進行 initramfs 的重建,重建的方法也很簡單!最重要的是取得核心的版本。
從上面的查詢來看,我們的核心版本應該是 3.10.0-514.el7.x86_64,所以建置的方式為:
當然,你也可以選擇其他的核心,來開機,不過我們這裡就使用預設核心即可。這樣應該就可以救援你的系統了! 這個光碟救援的步驟最好能夠多操作幾次,偶而它會是你的救命符!sh4.2# dracut -v /boot/initramfs-3.10.0-514.el7.x86_64.img 3.10.0-514.el7.x86_64 sh4.2# touch /.autorelabel sh4.2# exit sh4.2# reboot
13.3:課後練習操作
前置動作:請使用 unit13 的硬碟進入作業環境,並請先以 root 身分執行 vbird_book_setup_ip 指令設定好你的學號與 IP 之後,再開始底下的作業練習。
請使用 root 的身份進行如下實做的任務。直接在系統上面操作,操作成功即可,上傳結果的程式會主動找到你的實做結果。
- 系統救援:
- 你目前這個系統上,由於某些緣故, initramfs 檔案已經失效,所以應該是無法順利開機成功。
- 請進入系統救援的模式,並依據系統既有的核心版本,將 initramfs 重建
- 注意,重建時,應考慮 grub2 的原本設定檔,以找到正確的檔名,方可順利成功開機喔
- 不要忘記了,如果順利開機成功,請記得執行 vbird_book_setup_ip 設定好學號與 IP
- 請回答下列問題,並將答案寫在 /root/ans13.txt 檔案內:
- 管理系統的 process 時,通常是使用給予訊號 (signal) 的方式。而手動給予 Signal 的指令常見有哪兩個?
- 承上,常見的 signal 有 1, 9, 15, 19,各代表甚麼意思?
- 在 CentOS 7 系統上,所有的 systemd 服務腳本 (無論有沒有 enable) 放在哪個目錄內?
- 承上,但是系統【預設開機會載入】的腳本,又是放在哪個目錄內?
- systemd 會將服務進行分類,主要分為 X.service, X.socket, X.target,請問這幾個類型分別代表甚麼意思?
- 在此課堂上,啟動系統預設的網路服務,可以使用那五個口訣來處理?每個口訣對應的指令為何?
- Systemd 的操作與核心功能
- 透過網路服務監聽埠口觀察的指令查出系統有多少服務在啟動?無論如何,請將服務關閉到只剩下 port 22 與 port 25 兩個。 在底下有其他服務啟動後,自然會有多的埠口,不過在這個題目前,只能有這兩個埠口的存在。
- 讓這部 Linux 主機,預設會啟動在純文字模式下,亦即開機時,預設不會有圖形介面
- 讓系統預設啟動 IP 轉遞 (IP forward) 的功能。
- 系統開機之後,會自動寄出一封 email 給 root,說明系統開機了。指令可以是『 echo "reboot new" | mail -s 'reboot message' root 』, 請注意,這個動作必須是系統『自動於開機完成後就動作』,而不需要使用者或管理員登入喔!
- 預設服務的啟動
- 請依據課堂上的服務啟動口訣,啟動 WWW 服務。並假設你知道 WWW 的首頁目錄位於 /var/www/html/ 以及首頁檔名為 index.html。 請在 index.html 內以 vim 新建兩行,分別是學號與姓名。
- 請依據課堂上的服務啟動口訣,啟動 FTP 服務。並假設你知道 FTP 的首頁目錄在 /var/ftp ,你要讓 /etc/fstab 提供給用戶端以 ftp://your.server.ip/pub/fstab 的網址下載,該如何複製 /etc/fstab 到正確的位置去?
- grub2 相關應用
- 修改開機時的預設值,讓選單等待達到 30 秒
- 讓開機時,核心加入 noapic 及 noacpi 兩個預設參數
- 增加一個選單,選單名稱為【 Go go MBR 】,透過 chainloader 的方式,讓這個選單出現在開機時的選擇畫面中 (但是,預設值還是正常的 Linux 開機選單)
- 以預設的正常 Linux 開機選單為依據範本,再建立一個名為【Graphical Linux】的選單,這個選單會強制進入圖形介面, 而不是預設的文字介面。(hint: systemd.unit=???)
作業結果傳輸:請以 root 的身分執行 vbird_book_check_unit 指令上傳作業結果。 正常執行完畢的結果應會出現【XXXXXX;aa:bb:cc:dd:ee:ff;unitNN】字樣。若需要查閱自己上傳資料的時間, 請在作業系統上面使用: http://192.168.251.250 檢查相對應的課程檔案。
2017/04/04:加入了 sysctl.conf 的使用以及加入了習題囉!
2017/04/05:沒有想到第一題習題就出問題,忘記沒有講解原版ISO開機的救援問題...所以加上 13.2.5 的開機救援方式!
2016/05/26以來統計人數