Linux 基礎學習訓練教材 - CentOS 8.x

第 13 堂課:服務管理與開機流程管理

Linux 的服務管理,就是玩一玩 systemctl 這個指令!還有開機流程的管理,也就是 grub2 囉!

最近更新時間: 2020/06/08

之前的課程介紹過 process 與 program 的差別,也談過 PID 資訊的觀察,以及包括 job control 等與程序相關的資料。 本節課會繼續介紹 process 管理所需要具備的 signal 資訊。另外,管理員是需要管理服務的,每個服務都是需要被啟動的 process。 最終會介紹開機流程到底是如何運作。

13.1:服務管理

服務就是一個被啟動的程序,這個程序可以常駐於記憶體當中提供網路連線、例行工作排程等任務,就可稱為服務。

13.1.1:程序的管理透過 kill 與 signal

一個程式被執行觸發之後會變成在記憶體當中的一個活動的單位,那就是程序 (process)。之前的課程介紹過 PID 與程序的觀察, 本小節會繼續介紹 PID 的管理方面的任務。

管理員可以透過給某程序一個訊號 (signal) 去告知該程序你想要讓它作什麼。主要的程序訊號可以使用 kill -l 或 man 7 signal 查詢, 底下擷取較常見的訊號代號與對應內容:

代號名稱內容
1SIGHUP啟動被終止的程序,可讓該 PID 重新讀取自己的設定檔,類似重新啟動
2SIGINT相當於用鍵盤輸入 [ctrl]-c 來中斷一個程序的進行
9SIGKILL代表強制中斷一個程序的進行,如果該程序進行到一半, 那麼尚未完成的部分可能會有『半產品』產生,類似 vim會有 .filename.swp 保留下來。
15SIGTERM以正常的結束程序來終止該程序。由於是正常的終止, 所以後續的動作會將他完成。不過,如果該程序已經發生問題,就是無法使用正常的方法終止時, 輸入這個 signal 也是沒有用的。
19SIGSTOP相當於用鍵盤輸入 [ctrl]-z 來暫停一個程序的進行

至於傳輸 signal 則是透過 kill 這個指令。舉例來說,若管理員想要直接讓前一堂課介紹的 rsyslogd 這個程序重讀其設定檔, 而不透過服務管理的正常機制時,可以嘗試如下處理方式:

[root@localhost ~]# pstree -p | grep rsyslog
           |-rsyslogd(1769)-+-{rsyslogd}(1778)
           |                |-{rsyslogd}(1779)
           |                `-{rsyslogd}(1781)

[root@localhost ~]# kill -1 1769
[root@localhost ~]# rjournalctl -u rsyslog
[root@localhost ~]# tail /var/log/messages
......
May 26 17:14:00 station200 rsyslogd[1769]: [origin software="rsyslogd" swVersion="8.37.0-13.el8" 
  x-pid="1769" x-info="http://www.rsyslog.com"] rsyslogd was HUPed

讀者可以發現在登錄檔出現了 rsyslogd 被要求重新讀取設定檔的記錄 (HUPed)!而除了 PID 之外,管理員也能夠使用指令名稱來給予 signal, 直接透過 killall 即可。如下管理方式:

[root@localhost ~]# killall -1 rsyslogd
例題 13.1.1-1: 使用程序管理與訊號傳遞管理程序
  1. 使用 ps 這個指令,列出系統全部程序的『 pid, nice值, pri值, command 』資訊
  2. 找出系統內程序執行檔名為 sshd 的 PID
  3. 將上述的 PID 給予 signal 1 的方式為何?
  4. 觀察一下 /var/log/secure 的內容是否正確的輸出相關的程序行為?
  5. 如何將系統上所有的 bash 程序通通刪除?

13.1.2:systemd 簡介

從 CentOS 7 以後,Red Hat 系列的 distribution 放棄沿用多年的 System V 開機啟動服務的流程, 改用 systemd 這個啟動服務管理機制~採用 systemd 的原因如下:

  • 平行處理所有服務,加速開機流程
  • 一經要求就回應的 on-demand 啟動方式 (因為 systemd 為單一程序且常駐於記憶體)
  • 服務相依性的自我檢查
  • 依 daemon 功能分類
  • 將多個 daemons 集合成為一個群組

但是 systemd 也有許多存在的問題:

  • 全部的 systemd 都用 systemctl 這個管理程式管理,而 systemctl 支援的語法有限制,不可自訂參數 (所以使用 shell script 外帶參數的方法就不行了!)。
  • 如果某個服務啟動是管理員自己手動執行啟動,而不是使用 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/ | egrep 'multi-user|cron'
-rw-r--r--. 1 root root  356 11月  9  2019 crond.service
-rw-r--r--. 1 root root  532  6月 22  2018 multi-user.target
drwxr-xr-x. 2 root root  258  5月 25 21:28 multi-user.target.wants
lrwxrwxrwx. 1 root root   17  4月 10 05:52 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root   17  4月 10 05:52 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root   17  4月 10 05:52 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.2-1:嘗試找出 systemd 的實際路徑與軟體名稱
  1. 透過 ps 找出 systemd 這個執行檔的完整路徑
  2. 上述的指令是由那一個軟體所提供?
  3. 該軟體提供的全部檔名如何查詢?

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.3-1: 學習使用 systemctl
  1. 查詢系統有沒有 cupsd 這個指令?
  2. 使用 rpm 查詢該指令屬於哪個軟體?
  3. 使用 rpm 查詢該軟體的功能為何?
  4. 請觀察 cups 這個服務目前是啟動或關閉?開機時會不會啟動這個服務?
  5. 請將 cups 關閉,且下次開機還是會關閉
  6. 再次觀察 cups 這個服務。
  7. 觀察登錄檔有沒有記錄 cups 這個服務的相關資料?

13.1.4:systemctl 列表系統服務

預設的情況下, systemctl 可以列出目前系統已經啟動的服務群,如下列表:

[root@localhost ~]# systemctl
UNIT                                    LOAD   ACTIVE SUB       DESCRIPTION
.....
proc-sys-fs-binfmt_misc.automount       loaded active waiting   Arbitrary Executable File>
sys-devices-pci0000:00-0000:00:01.1-ata2-host1-target1:0:0-1:0:0:0-block-sr0.device loade>
sys-devices-pci0000:00-0000:00:03.0-virtio0-net-ens3.device loaded active plugged   Virti>
chronyd.service                         loaded active running   NTP client/server
colord.service                          loaded active running   Manage, Install and Gener>
crond.service                           loaded active running   Command Scheduler
firewalld.service                       loaded active running   firewalld - dynamic firew>
ModemManager.service                    loaded active running   Modem Manager
graphical.target                        loaded active active    Graphical Interface

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.

170 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)。最底下兩行顯示共有 170 的 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
.......
atd.service                                enabled
crond.service                              enabled
.......
unbound-anchor.timer                       enabled

416 unit files listed.
例題 13.1.4-1:找出 systemd 管理的服務列表資訊
  1. 找出系統中以 ksm 為開頭的所有的服務名稱,並觀察其狀態
  2. 將該服務設定為『開機不啟動』且『目前立刻關閉』的情況

13.1.5:systemctl 取得與切換預設操作界面

Linux 預設的操作畫面可以是純文字也能夠是文字加上圖形界面。早期的 systemV 系統稱文字界面為 runlevel 3 而圖形界面為 runlevel 5。 systemd 提供多種的操作界面,主要是透過『 target 』這種 unit 來作為規範。讀者可以使用如下的指令來觀察所有的 target:

[root@localhost ~]# systemctl list-units --type=target --all

在 CentOS 8 底下常見的操作界面 (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 /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target 
   → /usr/lib/systemd/system/multi-user.target.

[root@localhost ~]# systemctl get-default
multi-user.target

如此即可將文字界面設定為預設的操作環境。上述的作法是開機時才進行的預設操作環境界面,若需要即時將圖形界面改為文字界面, 或者反過來處理時,可以使用如下的方式來處置:

[root@localhost ~]# systemctl isolate multi-user.target
例題 13.1.5-1: 變更操作環境的方式
  1. 使用 netstat -tlunp 查看一下系統的網路監聽埠口
  2. 請在本機目前的狀態下,將操作界面模式更改為 rescue.target 這個救援模式
  3. 使用 netstat -tlunp 查看一下系統的網路監聽埠口是否有變少?
  4. 將環境改為原本的操作界面 (預設為圖形、變更為 GUI)

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 0.0.0.0:5355      0.0.0.0:*         LISTEN  3076/systemd-resolv
tcp        0      0 0.0.0.0:111       0.0.0.0:*         LISTEN  1/systemd
tcp        0      0 192.168.122.1:53  0.0.0.0:*         LISTEN  2136/dnsmasq
tcp        0      0 0.0.0.0:22        0.0.0.0:*         LISTEN  2390/sshd
tcp        0      0 127.0.0.1:25      0.0.0.0:*         LISTEN  2765/master
tcp6       0      0 :::5355           :::*              LISTEN  3076/systemd-resolv
tcp6       0      0 :::111            :::*              LISTEN  1/systemd
tcp6       0      0 :::22             :::*              LISTEN  2390/sshd
tcp6       0      0 ::1:25            :::*              LISTEN  2765/master
udp        0      0 0.0.0.0:50055     0.0.0.0:*                 2247/avahi-daemon:
udp        0      0 127.0.0.53:53     0.0.0.0:*                 3076/systemd-resolv
udp        0      0 192.168.122.1:53  0.0.0.0:*                 2136/dnsmasq
udp        0      0 0.0.0.0:67        0.0.0.0:*                 2136/dnsmasq
udp        0      0 0.0.0.0:35930     0.0.0.0:*                 3082/rsyslogd
udp        0      0 0.0.0.0:111       0.0.0.0:*                 1/systemd
udp        0      0 0.0.0.0:5353      0.0.0.0:*                 2247/avahi-daemon:
udp        0      0 0.0.0.0:5355      0.0.0.0:*                 3076/systemd-resolv
udp        0      0 127.0.0.1:323     0.0.0.0:*                 2262/chronyd
udp        0      0 0.0.0.0:514       0.0.0.0:*                 3082/rsyslogd
udp6       0      0 :::111            :::*                      1/systemd
udp6       0      0 :::5353           :::*                      2247/avahi-daemon:
udp6       0      0 :::5355           :::*                      3076/systemd-resolv
udp6       0      0 :::57581          :::*                      2247/avahi-daemon:
udp6       0      0 ::1:323           :::*                      2262/chronyd
udp6       0      0 :::514            :::*                      3082/rsyslogd

重點在 Local Address 那一行,會顯示該服務是啟動在本機的哪一個 IP 界面的哪一個埠口上,如此管理員即可了解啟動該埠口的服務是哪一個。 若無須該網路服務,則可以將該程序關閉。以上述表格來說,如果需要關閉 avahi-daemon, systemd-resolv 時,可以使用如下的方式取得服務名稱:

[root@localhost ~]# systemctl list-unit-files | egrep 'avahi|systemd-resolv'
avahi-daemon.service           enabled
systemd-resolved.service       enabled
avahi-daemon.socket            enabled

若需要將其關閉,則應該使用如下的方式,將『目前』與『預設』的服務啟動都關閉才行:

[root@localhost ~]# systemctl stop avahi-daemon.service systemd-resolved.service avahi-daemon.socket
[root@localhost ~]# systemctl disable avahi-daemon.service systemd-resolved.service avahi-daemon.socket
[root@localhost ~]# netstat -tlunp

讀者將可發現到 avahi-daemon 以及 systemd-resolv 的服務已經被關閉。而若需要啟動某個網路服務,則需要了解到該服務是由哪一個軟體所啟動的, 該軟體需要先安裝後才可以啟動該服務。比較特別的是 dnsmasq 這個服務,事實上,這個服務是被虛擬化系統所喚醒使用的,所以, 要關閉這個服務,得要關閉虛擬化資料才行。

實際練習:嘗試關閉虛擬化環境的服務:
  1. 先查閱 libvirtd 有沒有在啟動,同時,使用 virsh list 指令查詢目前有沒有虛擬機器在運作?
    [root@localhost ~]# systemctl status libvirtd
    ● libvirtd.service - Virtualization daemon
       Loaded: loaded (/usr/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
       Active: active (running) since Tue 2020-05-26 23:08:27 CST; 8min ago
         Docs: man:libvirtd(8)
               https://libvirt.org
     Main PID: 2391 (libvirtd)
    .....
    # 確實活著喔!
    
    [root@localhost ~]# virsh list
     Id    名稱                         狀態
    ----------------------------------------------------
    
  2. 查詢是否有特定的虛擬化網路界面,因為使用 nmcli 時,有看到以 virbr 開頭的網路界面之故:
    [root@localhost ~]# virsh net-list
     名稱               狀態     自動啟動  Persistent
    ----------------------------------------------------------
     default              啟用     yes           yes
    
  3. 關閉這個網路界面,並且永遠取消設定:
    [root@localhost ~]# virsh net-destroy default
    [root@localhost ~]# virsh net-undefine default
    
  4. 這時再回頭看看網路埠口的情況:
    [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 0.0.0.0:111      0.0.0.0:*        LISTEN  1/systemd
    tcp        0      0 0.0.0.0:22       0.0.0.0:*        LISTEN  2390/sshd
    tcp        0      0 127.0.0.1:25     0.0.0.0:*        LISTEN  2765/master
    tcp6       0      0 :::111           :::*             LISTEN  1/systemd
    tcp6       0      0 :::22            :::*             LISTEN  2390/sshd
    tcp6       0      0 ::1:25           :::*             LISTEN  2765/master
    udp        0      0 0.0.0.0:35930    0.0.0.0:*                3082/rsyslogd
    udp        0      0 0.0.0.0:111      0.0.0.0:*                1/systemd
    udp        0      0 127.0.0.1:323    0.0.0.0:*                2262/chronyd
    udp        0      0 0.0.0.0:514      0.0.0.0:*                3082/rsyslogd
    udp6       0      0 :::111           :::*                     1/systemd
    udp6       0      0 ::1:323          :::*                     2262/chronyd
    udp6       0      0 :::514           :::*                     3082/rsyslogd
    

上面這幾個服務大概就是一台正常的 Linux 系統應該要具有的服務,所以,不要在隨便關閉喔!

例題 13.1.6-1:嘗試安裝、啟動、開機啟動、防火牆、測試等五步驟處理正常的網路服務!
  1. 安裝:WWW 網路服務是由 httpd 這個軟體所提供的,請先安裝該軟體;並查詢是否有 httpd 的服務存在了?
  2. 啟動:啟動該服務,並且查詢該服務啟動的埠口為何
  3. 開機啟動:設定為預設啟動該服務,並查詢該服務的狀態是否正確 (預設啟動/現在啟動)
  4. 防火牆:將 http 服務的防火牆埠口放行
  5. 測試:使用瀏覽器查詢本機 WWW 服務是否正確啟動了。

13.1.7:系統效能優化 - tuned, tuned-adm

因為每個 Server 的使用情境不同,有的在虛擬機當中,有的是實體機,有的需要使用一般網路服務功能,有的要加強本身網路傳輸, 有的則是需要進行科學運算等等。也因為不同的設計參考依據不一樣,因此預設的系統參數可能就不會相當適合於你的環境。

以前要調整 (tune) 系統效能時,需要進行一大堆的設定,包括核心模組、核心參數、網路參數、磁碟參數等等,相當複雜。 現在的系統則加入了名為 tuned 這個服務,透過這個服務的動態處理,可以隨時以你選定的環境 (profile) 來統一處理效能優化的相關問題, 而無須每項事情都要管理員去處理了!

tuned 這個服務預設提供了許多的環境讓你選擇優化的情境,要查閱可以使用底下的方式處理:

[root@localhost ~]# tuned-adm list
Available profiles:
- balanced                - General non-specialized tuned profile
- desktop                 - Optimize for the desktop use-case
- hpc-compute             - Optimize for HPC compute workloads
- latency-performance     - Optimize for deterministic performance at the cost of 
                            increased power consumption
- network-latency         - Optimize for deterministic performance at the cost of 
                            increased power consumption, focused on low latency network performance
- network-throughput      - Optimize for streaming network throughput, generally only necessary 
                            on older CPUs or 40G+ networks
- powersave               - Optimize for low power consumption
- throughput-performance  - Broadly applicable tuning that provides excellent performance across 
                            a variety of common server workloads
- virtual-guest           - Optimize for running inside a virtual guest
- virtual-host            - Optimize for running KVM guests
Current active profile: virtual-guest

一般來說,如果是實體機器且沒有啟用虛擬化功能的話,建議使用『 throughput-performance 』即可,一般用來當測試機或桌機的話,選擇 『 desktop 』應該是不錯的,如果是用來跑科學計算,或許也能使用『 hpc-compute 』,只是用來作為 IoT 的資料收集用伺服器, 使用『 powersave 』應該也可以。如果是在虛擬機裡面,但是有需要用到網路功能,想要降低延遲的話 (代價就是整體頻寬使用率會較低), 或許也能使用『 network-latency 』。總之,要依據你的使用情境而挑選。

為了避免麻煩,其實 tuned-adm 也會自己分析你的系統所處環境,然後給予適當的建議!你就可以依據該建議來設計你的環境優化。

當然這個建議或許不是很適合你,只是單純依據當下的系統而給的建議而已喔!以鳥哥的科學計算環境來說,該環境底下經常會有大量網路傳輸的需求, 並且需要的並不是頻寬 (因為頻寬已經達到 10G 了),而是反應速度。此時,該環境比較適合的情境或許要選擇『network-latency』才對! 但是一般這樣的實體機器系統,tuned 會建議使用 throughput-performance。然而鳥哥的經驗中, throughput-performance 確實是當中效能最高的! 不過,如果不是單獨本機運作的軟體,需要跨足到其他台主機協同運作時,經常會有網路延遲的問題啊!

實際練習: 以 tuned 建議的方式設計優化環境
  1. 先查看 tuned 的建議:
    [root@localhost ~]# tuned-adm recommend
    virtual-guest
    
    看起來是建議使用 virtual-guest 的環境,因為教材的系統就是使用虛擬化,所以這個建議應該是沒問題的!
  2. 以建議的優化環境參數設計 tuned 的運作:
    [root@localhost ~]# tuned-adm profile virtual-guest
    [root@localhost ~]# tuned-adm active
    Current active profile: virtual-guest
    
    這樣應該就已經設定好我們的環境了!
  3. 使用 tuned 的檢查功能,看看環境設定有沒有問題?
    [root@localhost ~]# tuned-adm verify
    Verification failed, current system settings differ from the preset profile.
    You can mostly fix this by restarting the Tuned daemon, e.g.:
      systemctl restart tuned
    or
      service tuned restart
    Sometimes (if some plugins like bootloader are used) a reboot may be required.
    See tuned log file ('/var/log/tuned/tuned.log') for details.
    
    有些時候設計完畢後, tuned 可能沒有辦法直接處理,這時可以依據上述的登錄檔內容,查詢一下可能的問題。 虛擬機器會失敗的原因,是因為虛擬機器不能改 CPU 的運作模式,該模式必需要實體機器去設定才行。 要確認你的系統是否能夠支援 CPU 的修改,可以使用底下的方式來處理:
    [root@localhost ~]# cpupower frequency-info
    analyzing CPU 0:
      no or unknown cpufreq driver is active on this CPU
      CPUs which run at the same hardware frequency: Not Available
      CPUs which need to have their frequency coordinated by software: Not Available
      maximum transition latency:  Cannot determine or is not supported.
    Not Available
      available cpufreq governors: Not Available
      Unable to determine current policy
      current CPU frequency: Unable to call hardware
      current CPU frequency:  Unable to call to kernel
      boost state support:
        Supported: no
        Active: no
    
    正常的情境下,上面表格中的 cpufreq governors 會告訴你可用的 CPU 環境設計,這裡並不行啊!這是因為虛擬機器的影響所致。 所以,上面的檢測錯誤是可以被忽略的!

13.2:開機流程管理

系統如果出錯,可能需要進入救援模式才能夠處理相關的任務。但如何進入救援模式?這就需要從開機流程分析來下手。

13.2.1:Linux 系統在 systemd 底下的開機流程

一般正常的情況下, Linux 的開機流程會是如下所示:

  1. 硬體階段:載入 BIOS / UEFI 的硬體資訊與進行自我測試,並依據設定取得第一個可開機的裝置;
  2. 系統啟動階段:這個階段大致又分兩種機制,一種是使用傳統 BIOS 讀取裝置,一種是透過 UEFI 讀取裝置:
    • BIOS:根據設定,讀取並執行第一個開機裝置內 MBR 的 boot Loader (亦即是 grub2, spfdisk 等程式);
    • UEFI:搜尋系統內的開機分割槽 (分割槽 System ID 為 EF00, 檔案系統 FAT),讀取內部的開機 loader
  3. 依據 boot loader 的設定載入 Kernel ,Kernel 會開始偵測硬體與載入驅動程式;
    • 載入 kernel file 與 initramfs 檔案在記憶體內解壓縮
    • initramfs 會在記憶體模擬出系統根目錄,提供 kernel 相關的驅動程式模組
    • 核心裝置驅動程式完整的驅動硬體
  4. 在硬體驅動成功後,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.1-1: 啟動舊版 Linux distribution 經常使用的 /etc/rc.d/rc.local 開機流程處理檔
  1. 找出與 local, rc 有關的服務或檔案資料:
    1. 使用 systemctl list-units --all 的功能,找出 local 關鍵字
    2. 使用 systemctl list-unit-files 的功能,找出 local 關鍵字
    3. 使用 systemctl show xxx.service 的功能,找出上述軟體的執行檔
  2. 實際載入 rc.local 的服務,讓系統開機後能夠執行 rc.local 的內容:
    1. 查閱 /etc/rc.d/rc.local 的權限,同時加上 x 的權限
    2. 重新載入 systemd ,讓上述修訂生效
    3. 使用 systemctl status XXX 的功能,判斷一下有沒有啟用該服務喔!

13.2.2:核心與核心模組

系統的核心大多放置於 /boot/vmlinuz* 開頭的檔案中,而 initramfs 則放置於 /boot/initramfs* 。 至於核心的模組則放置於 /lib/modules/$(uname -r)/ 目錄內。

目前系統上面已經載入的模組,可以使用底下的方式來觀察:

[root@localhost ~]# lsmod
[root@localhost ~]# lsmod | egrep 'Module|xfs'
Module          Size  Used by
xfs          1474560  2
libcrc32c      16384  3 nf_conntrack,nf_nat,xfs

如上所示,xfs 為獨立運作的模組,不過還是被 2 個其他程序所使用 (Used by)!如果你使用 df -T | grep xfs 去查閱一下, 就會知道目前系統應該有兩個裝置就是使用 xfs 檔案系統掛載的情境。另外,這個 xfs 模組會去使用到 libcrc32c 這個模組的意思! 也就是說,其實,模組也是有相依性的喔!

至於,若找到名為 xfs 的模組後,要想了解該模組的功能,可以使用如下的方式查詢:

[root@localhost ~]# modinfo xfs
filename:       /lib/modules/4.18.0-147.8.1.el8_1.x86_64/kernel/fs/xfs/xfs.ko.xz
license:        GPL
description:    SGI XFS with ACLs, security attributes, no debug enabled
author:         Silicon Graphics, Inc.
alias:          fs-xfs
rhelversion:    8.1
srcversion:     6EB85FD6AC0E0ED926C6D92
depends:        libcrc32c
intree:         Y
name:           xfs
vermagic:       4.18.0-147.8.1.el8_1.x86_64 SMP mod_unload modversions
sig_id:         PKCS#7
signer:         CentOS Linux kernel signing key
sig_key:        57:35:0B:1E:DC:CE:14:72:7C:A0:26:12:B2:7B:38:69:93:62:B5:22
sig_hashalgo:   sha256
signature:      4B:ED:60:E8:55:5D:A1:67:0A:56:A8:74:89:1B:C0:92:CE:A1:09:2A:
.....

若想要載入某個模組,就使用 modprobe 來載入,卸載則使用 modprobe -r 來卸載即可。

例題 13.2.2-1: 核心模組的使用
  1. 在核心模組的目錄下,使用 find 找出系統有沒有 fat 關鍵字的模組?
  2. 是否已經有載入 fat 相關的模組了?若無,請載入該模組,再次檢查是否載入成功。
  3. 再次檢查有無 cifs 模組,若無,請載入,並查詢該模組的功能為何?
  4. 卸載 cifs 模組。
  5. 在核心模組的目錄下,有沒有 ntfs 的關鍵字?
  6. 在 yum 的使用上,啟用 epel 軟體庫,搜尋 ntfs 這個關鍵字軟體
  7. 嘗試安裝上述找到的軟體名稱
  • 使用 /etc/sysctl.conf 處理核心參數

某些情況下,你會需要更動核心參數。而預設的核心參數位於 /proc/sys/ 底下。一般不建議使用者直接使用手動修改方式處理 /proc 內的檔案 (因為下次開機就不會持續提供),應使用修改 /etc/sysctl.conf 來處理。舉例而言,若你的 server 不想要回應 ping 的封包, 則可以如此測試:

[root@localhost ~]# ping -c 2 localhost4
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.044 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.047 ms

--- localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 30ms
rtt min/avg/max/mdev = 0.044/0.045/0.047/0.006 ms

[root@localhost ~]# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
[root@localhost ~]# ping -c 2 localhost4
PING localhost (127.0.0.1) 56(84) bytes of data.
--- localhost ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 31ms

[root@localhost ~]# echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all

讀者可以發現 icmp 確實不會回應 ping 的要求了。而這個設定值如果一定要每次開機都生效, 可以寫入 /etc/sysctl.d/*.conf 內,寫法為:

[root@localhost ~]# vim /etc/sysctl.d/mycentos.conf
net.ipv4.icmp_echo_ignore_all = 1

[root@localhost ~]# sysctl -p /etc/sysctl.d/mycentos.conf
[root@localhost ~]# cat /proc/sys/net/ipv4/icmp_echo_ignore_all
1

如此則可以每次都生效了。不過,這個功能對於內部環境的測試還是很重要的,因此還是請修訂回來比較妥當。

例題 13.2.2-2: 調整系統的一些參數設定
  1. 請將 icmp_echo_ignore_all 改為預設的不要啟動 (0)
  2. 讓 ip_forward 設定為啟動
  3. 讓 /proc/sys/dev/raid/speed_limit_{max|min} 分別設定為 50000/40000 (單位為 Kbytes)。
  4. 立刻啟動上述設定

13.2.3:grub2 設定檔初探

核心的載入與設定是由開機管理程式來處理的,而 CentOS 8 預設的開機管理程式為 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 [ -f ${config_directory}/grubenv ]; then
  load_env -f ${config_directory}/grubenv
elif [ -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/10_linux ###
insmod part_gpt
insmod ext2
set root='hd0,gpt2'   <==Linux 核心所在的分割槽
if [ x$feature_platform_search_hint = xy ]; then
  search --no-floppy --fs-uuid --set=root --hint='hd0,gpt2'  73f13e7b-43c4-43c5-93b4-9e65b962752d
  # 上一列的 --set=root 則是指定具有這個 UUID 的檔案系統為根目錄
else
  search --no-floppy --fs-uuid --set=root 73f13e7b-43c4-43c5-93b4-9e65b962752d
fi
set default_kernelopts="root=/dev/mapper/centos-root ro crashkernel=auto  quiet "
# This section was generated by a script. Do not modify the generated file - all changes
# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
#
# The blscfg command parses the BootLoaderSpec files stored in /boot/loader/entries and
# populates the boot menu. Please refer to the Boot Loader Specification documentation
# for the files format: https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/.
insmod blscfg
blscfg
### END /etc/grub.d/10_linux ###

.......

### BEGIN /etc/grub.d/41_custom ###
if [ -f  ${config_directory}/custom.cfg ]; then
  source ${config_directory}/custom.cfg
elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
  source $prefix/custom.cfg;
fi
### END /etc/grub.d/41_custom ###

這個 grub.cfg 檔案分為數個部份,分別由不同的設定檔整合而來,上表中的特殊字體是比較重要的部份。至於比較重要的內容,大致說明如下:

  • /etc/grub.d/00_header 之 timeout=5 : 00_header 檔案裡面規範到是否要列出選單, 以及等待的時間 timeout 資料等。開機選單會倒數 5 秒鐘,就是在這個階段以『 timeout=5 』來設定的結果。
  • /etc/grub.d/10_linux 的 insmod 與 set root 功能:10_linux 的階段則是實際的 Linux 核心選單重頭戲! 該段落的過程中,首先是載入 GPT 以及 ext2 的檔案系統模組 (insmod),然後設定放置 /boot 這個目錄的分割槽代碼,在本系統當中是 /dev/vda2,也就是 (hd0,2) 這個磁碟代碼,因此設定了『 set root='hd0,gpt2' 』這個設定值。
  • /etc/grub.d/10_linux 的 search 功能:開機的時候總是需要掛載根目錄的,根目錄就根據 search 這個項目去搜尋。 根據整體 Linux 內含的檔案系統,該檔案系統 UUID 若為 73f13e7b-43c4-43c5-93b4-9e65b962752d 時,就將該檔案系統設定為根目錄。
  • /etc/grub.d/10_linux 的 set default_kernelopts 功能:核心功能參數寫入在這裡。 因為核心可能有多個選單,每個選單若需要分別設計,那未來修改很麻煩,因此就將共用的核心參數寫入在這個變數中!
  • /etc/grub.d/10_linux 的 blscfg 功能:事實上,所有的開機選單是分別放置到 /boot/loader/entries/ 裡面的 .conf 檔案, 每一個檔案就是一個選單。透過 blscfg 指令,會將 /boot/loader/entries/ 中的檔案呼叫進來成為選單之意。
  • /etc/grub.d/41_custom 階段:若有更多的開機選單或設定,再寫入到這個檔案中。

在 10_linux 的階段中,有兩個主要的 root 設定,一個是設定核心所在處的『 set root='hd0,gpt2' 』,另一個則是設定根目錄的所在檔案系統, 也就是『 search --no-floppy --fs-uuid --set=root 』那一行!兩個 root 的意義不相同喔!這點要特別留意!

上面談到的 blscfg 當中,透過文件的說明,可以發現 blscfg 會去呼叫 /boot/loader/entries/ 裡面的設定檔,先來看看該目錄有什麼資訊:

[root@localhost ~]# ls /boot/loader/entries/
502dbaaf2a074134909a59ef9ab651c1-0-rescue.conf
502dbaaf2a074134909a59ef9ab651c1-4.18.0-147.8.1.el8_1.x86_64.conf
502dbaaf2a074134909a59ef9ab651c1-4.18.0-147.el8.x86_64.conf

直接拿 4.18.0-147.el8.x86_64 這個檔案內容來瞧瞧:

[root@localhost ~]# cat /boot/loader/entries/*-4.18.0-147.el8.x86_64.conf
title    CentOS Linux (4.18.0-147.el8.x86_64) 8 (Core)
version  4.18.0-147.el8.x86_64
linux    /vmlinuz-4.18.0-147.el8.x86_64
initrd   /initramfs-4.18.0-147.el8.x86_64.img $tuned_initrd
options  $kernelopts $tuned_params
id       centos-20191204215851-4.18.0-147.el8.x86_64
grub_users $grub_users
grub_arg   --unrestricted
grub_class kernel

這個檔案當中,比較重要的項目大概是:

  • title :就是選單的內容,選擇一個易懂的名稱顯示即可。
  • version :通常是核心版本。
  • linux :就是核心檔案放置的地方。由於 /boot 已經設定為 root,就是 grub.cfg 裡面已經指定了核心所在目錄為 hd0,gpt2, 因此, /boot/vmlinuz-xxx ==> 'hd0,gpt2'/vmlinuz-xxx,所以,這裡只要寫 /vmlinuz 即可。若 /boot 並沒有獨立的目錄存在, 這邊才寫 /boot/vmlinuz-xxx 喔!
  • initrd :就是核心在開機過程當中需要載入的核心模組以及開機過程需要的根目錄,預設解壓縮後會以記憶體模擬根目錄。
  • options :將剛剛 grub.cfg 的參數呼叫到這裡來,這個 options 就是核心參數!
  • id :讓這個開機選單具有一個識別碼,方便在其他地方也能呼叫到這個選單!

13.2.4:grub2 設定檔維護

基本上,修改 grub2 設定檔你可以在如下的位置進行:

  • /etc/default/grub:主要修改環境設定
  • /etc/grub.d/ :可以設定其他選單
  • /boot/loader/entries/:各別開機選單放置的位置

主要環境設定內容為:

[root@www ~]# cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto resume=/dev/mapper/centos-swap rd.lvm.lv=centos/root rd.lvm.lv=centos/swap rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
  • GRUB_TIMEOUT: 指定預設倒數讀秒的秒數
  • GRUB_DISTRIBUTOR: 由釋出系統的官網資料來展示開機的選單
  • GRUB_DEFAULT: 指定預設由哪一個選單來開機,預設開機選單之意
  • GRUB_DISABLE_SUBMENU: 是否要隱藏次選單,通常是藏起來的好!
  • GRUB_TERMINAL_OUTPUT: 指定資料輸出的終端機格式,預設是透過文字終端機
  • GRUB_CMDLINE_LINUX: 就是在 /boot/loader/entries/ 內部檔案的 linux 項目後續的核心參數
  • GRUB_DISABLE_RECOVERY: 取消救援選單的製作
  • GRUB_ENABLE_BLSCFG: 就是使用 blscfg 去呼叫 /boot/loader/entries/ 裡面的選單之意

若有修改上述檔案,則需要使用 grub2-mkconfig -o /boot/grub2/grub.cfg 來進行修訂。現在假設:

  • 開機選單等待 40 秒鐘
  • 核心外帶『 intel_iommu=on 』的參數值

那應該要如何處理 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=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=auto (..中間省略..) rhgb quiet intel_iommu=on"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true

修改完畢之後再來則是進行輸出修訂的任務:

[root@localhost ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
done

[root@localhost ~]# reboot

若想要知道是否完整的變更了,請 vim /boot/grub2/grub.cfg 查閱相關設定值是否變更即可。重新開機後,你就可以發現選單會等待到 40 秒喔!然後,重新開機完畢並登入系統, 查詢一下核心參數是否正確的啟用了:

[root@localhost ~]# cat /proc/cmdline
BOOT_IMAGE=(hd0,gpt2)/vmlinuz-4.18.0-147.8.1.el8_1.x86_64 root=/dev/mapper/centos-root ro 
   crashkernel=auto resume=/dev/mapper/centos-swap rd.lvm.lv=centos/root 
   rd.lvm.lv=centos/swap rhgb quiet intel_iommu=on
  • 選單建置的腳本 /etc/grub.d/*

grub2-mkconfig 執行之後會去分析 /etc/grub.d/* 裡面的檔案,然後執行該檔案來建置 grub.cfg。至於 /etc/grub.d/ 目錄底下會有這些檔案存在:

  • 00_header:主要在建立初始的顯示項目,包括需要載入的模組分析、螢幕終端機的格式、倒數秒數、選單是否需要隱藏等等,大部分在 /etc/default/grub 裡面所設定的變數,大概都會在這個腳本當中被利用來重建 grub.cfg 。
  • 10_linux:在 CentOS 7 以前的系統,這個 10_linux 會去找尋目前系統正確的核心,然後依據核心去建置選單。 新的機制使用了 blscfg 了,選單已經建置好放在 /boot/loader/entries/ 當中,所以這個檔案的功能就剩下處理預設核心參數等項目。
  • 30_os-prober:這個腳本預設會到系統上找其他的 partition 裡面可能含有的作業系統,然後將該作業系統做成選單來處理就是了。 如果你不想要讓其他的作業系統被偵測到並拿來開機,那可以在 /etc/default/grub 裡面加上『 GRUB_DISABLE_OS_PROBER=true 』取消這個檔案的運作。
  • 40_custom:如果你還有其他想要自己手動加上去的選單項目,或者是其他的需求,那麼建議在這裡補充即可!

所以,一般來說,我們會更動到的就是僅有 40_custom 這個檔案即可。然而由於 CentOS 8 使用了 blscfg 的模組, 因此 Linux 相關的檔案系統選單,請自行到 /boot/loader/entries/ 去建置相關的設定即可。那如果需要額外的其他作業系統的選單時, 才需要用到 40_custom 的內容喔!

  • 直接指定 Linux 核心開機

在預設的核心裡面,你還需要有額外的選單,例如你要建立一個一定進入圖形界面與一個一定進入文字界面的選單時, 就可以額外建立兩個選單檔案!直接跑到 /boot/loader/entries/ 裡頭去處理即可!也不需要重新建立 grub.cfg 喔!相當簡單:

實際練習:建立多重選單的方式,思考方向如下:
  • 透過教材原有的核心版本 (不是升級後的版本) 開機選單檔案,額外建立兩個選單,一個強制 systemd 使用 graphical.target, 一個強制使用 multi-user.target 來啟動,而不考慮源有的 default.target。
  • 要考量選單的檔案是放在哪裡喔。
處理方式如下:
  1. 核心參數的設計:當核心外帶參數中,有個『 systemd.unit=??? 』的外帶參數可以指定特定的 target 開機! 所以,來到 /boot/loader/entries 目錄下,複製多個選單項目即可:
    [root@localhost ~]# cd /boot/loader/entries/
    [root@localhost entries]# cp 502...-4.18.0-147.el8.x86_64.conf custom-graphical-4.18.0-147.el8.x86_64.conf
    [root@localhost entries]# cp 502...-4.18.0-147.el8.x86_64.conf custom-textmode-4.18.0-147.el8.x86_64.conf
    [root@localhost entries]# vim custom-graphical-4.18.0-147.el8.x86_64.conf
    title CentOS Linux (4.18.0-147.el8.x86_64) 8 (Core) - GUI Mode
    version 4.18.0-147.el8.x86_64
    linux /vmlinuz-4.18.0-147.el8.x86_64
    initrd /initramfs-4.18.0-147.el8.x86_64.img $tuned_initrd
    options $kernelopts $tuned_params systemd.unit=graphical.target
    id centos-20191204215851-4.18.0-147.el8.x86_64
    grub_users $grub_users
    grub_arg --unrestricted
    grub_class kernel
    
    [root@localhost entries]# vim custom-textmode-4.18.0-147.el8.x86_64.conf
    title CentOS Linux (4.18.0-147.el8.x86_64) 8 (Core) - Text Mode
    version 4.18.0-147.el8.x86_64
    linux /vmlinuz-4.18.0-147.el8.x86_64
    initrd /initramfs-4.18.0-147.el8.x86_64.img $tuned_initrd
    options $kernelopts $tuned_params systemd.unit=multi-user.target
    id centos-20191204215851-4.18.0-147.el8.x86_64
    grub_users $grub_users
    grub_arg --unrestricted
    grub_class kernel
    
  2. 接下來請重新開機,重新開機完畢後選擇純文字界面開機後,登入系統,再次查詢核心的外帶參數,看看有沒有加入 multi-user 的相關字樣:
    圖13.2.4-1、修改 grub 選單後的展示樣式
    圖13.2.4-1、修改 grub 選單後的展示樣式
    [root@localhost ~]# cat /proc/cmdline
    BOOT_IMAGE=(hd0,gpt2)/vmlinuz-4.18.0-147.el8.x86_64 .... intel_iommu=on systemd.unit=multi-user.target
    
當你有特殊開機選單的需求時,只要在 /boot/loader/entries/ 裡面設計就好了!
  • 透過 chainloader 的方式移交 loader 控制權 - 僅針對 BIOS 系統

所謂的 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 交出控制權了!

實際練習:透過分析原有的 Linux/Windows 系統,建置好多重開機選單的方式
假設你的測試系統上面使用 MBR 分割槽,由於使用多重作業系統的安裝,因此觀察分割槽會出現如下的資料:
[root@study ~]# fdisk -l /dev/vda
   Device Boot      Start         End      Blocks   Id  System
/dev/vda1            2048    10487807     5242880   83  Linux
/dev/vda2   *    10487808   178259967    83886080    7  HPFS/NTFS/exFAT
/dev/vda3       178259968   241174527    31457280   83  Linux
其中 /dev/vda2 使用是 windows 10 的作業系統。現在我需要增加兩個開機選項,一個是取得 windows 10 的開機選單,一個是回到 MBR 的預設環境,應該如何處理呢?
實做的方法有點像底下這樣:
windows 10 在 /dev/vda2 亦即是 hd0,msdos2 這個地方,而 MBR 則是 hd0 即可,不需要加上分割槽啊!因此整個設定會變這樣:
[root@study ~]# vim /etc/grub.d/40_custom
menuentry 'Go to Windows 10' --id 'win10' {
        insmod chain
        insmod ntfs
        set root=(hd0,msdos2)
        chainloader +1
}
menuentry 'Go to MBR' --id 'mbr' {
        insmod chain
        set root=(hd0)
        chainloader +1
}

[root@study ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
另外,如果每次都想要讓 windows 變成預設的開機選項,那麼在 /etc/default/grub 當中設定好『 GRUB_DEFAULT=win10 』 然後再次 grub2-mkconfig 這樣即可啦!不要去算 menuentry 的順序喔!透過 --id 內容來處理即可!

不同的檔系統允許安裝 grub 的區塊並不相同。XFS 檔案系統似乎沒有預留 boot sector 給 boot loader 使用, 因此 XFS 並不能安裝獨立的 boot loader。如果你想要讓每個獨立的 OS 都有自己的 boot sector,那麼就得要使用 ext2 家族, 例如 ext4 才行!

至於 UEFI 的開機管理方式與 BIOS 並不相同,處理上就不能使用本章節的方式了!

13.2.5:開機檔案的救援問題

一般來說,如果是檔案系統錯誤,或者是某些開機過程中的問題,我們可以透過開機時進入 grub2 的互動界面中, 在 linux 的欄位,加入 rd.break 或者是 init=/bin/bash 等方式來處理即可。但是,如果是 grub2 本身就有問題, 或者是根本就是核心錯誤,或者是 initramfs 出錯時,那就無法透過上述的方式來處理了。

在 CentOS 7 的操作經驗中,在升級核心時,偶而會有 initramfs 製作錯誤的情況導致新核心無法開機的問題。 此時,若你已經沒有保留舊的核心,此時就無法順利開機了。在 CentOS 8 裡面倒是比較少出現這樣的問題。

但若是發生這問題是,最常見的解決方法有兩個:

  • 第一個比較單純,如果還有之前舊版的核心存在,請使用舊版核心開機,正常進入系統之後,以 dracut 重建 initramfs 即可;
  • 第二個方法比較特別,如果無法使用舊核心開機,那請透過『原版光碟開機,然後使用救援模式 (rescue) 來自動偵測硬碟系統, 再透過 chroot 的動作取回到原本的系統環境,再以 dracut 來重建 initramfs 』即可。
例題 13.2.5-1: 重建新版核心的 initramfs 虛擬根目錄系統
  1. 觀察你的系統內的核心版本,務必要有兩個核心版本以上的環境 (若無兩個環境,請依據前幾章的內容升級一個新的核心)
  2. 重新開機後,使用舊版核心開機,並確認確實為舊版核心。
  3. 前往 /boot 目錄,將新版的 initramfs 暫時更名為其他檔案,例如副檔名增加 .raw 之類的方式。
  4. 使用 dracut 重新建置該新版核心的 initramfs,且檔名最好與原本的檔名相同。另外,新建此 initramfs 時,加入 ixbge 這個網路卡模組。
  5. 重新開機之後,選擇新核心開機,看看是否可以順利開機進入系統。

如果是一開始安裝就出事,那就得要透過底下的方案來處理了!下面是模擬進入光碟救援模式的方式:

  1. 調整 BIOS 變成光碟開機 (或 USB 開機),同時放入原版光碟,之後開機
  2. 進入光碟安裝模式後,選擇『 Troubleshooting 』的項目,再選擇『 Rescue a CentOS Linux system 』環境
    • 此時系統會自動偵測硬碟,然後載入適當的模組,之後應該會找到我們的硬碟
    • 當出現 1)Continue, 2)Read-only mount, 3)Skip to shell, 4)Quit(reboot) 時,按下 1 即可!
    • 若一切都順利,光碟環境會提供『 chroot /mnt/sysimage 』指令,作為切換成原本系統的手動。
  3. 進入 shell 環境後,輸入『 df 』應該會看到原本系統資料通通掛載在 /mnt/sysimage 底下, 因此請使用『 chroot /mnt/sysimage 』指令來進入原本的系統。
  4. 接下來請按照上一題的流程來重新建置好你的 initramfs 檔案即可。
  5. 將 initramfs 建置完畢後,還得要進行底下的流程才能夠離開系統喔:
    sh4.2# touch /.autorelabel
    sh4.2# exit   
    sh4.2# reboot
    

13.3:課後練習操作

  • 上課的課後練習,非作業:
  1. 想出並執行兩種重新載入 (reload) atd 的方法
  2. 一般來說,伺服器系統通常不會啟動圖形化見面,所以,請讓你的系統變成預設文字界面,然後有需要再登入切換成為圖形界面即可。
  3. 嘗試啟動名為 vsftpd 的 FTP 網路服務。
  4. 強迫使用『 network-latency 』的 tuned 環境優化設定
  5. 讓系統盡量少用 swap 的功能,同時減少 dirty page (磁碟與記憶體非同步) 的要求,將底下的數據修改:
    /proc/sys/vm/dirty_ratio            改成 40
    /proc/sys/vm/dirty_background_ratio 改成 5
    /proc/sys/vm/swappiness             改成 10
    
    且每次系統開機都會生效!
  6. 以現有的新的核心製作一個新的開機選單,該選單每次都會主動進入圖形界面,且預設開機選單會指向這個圖形界面的選單!
  • 作業 (不提供學生答案,僅提供教師參考答案)

作業硬碟一般操作說明:

  • 開啟雲端虛擬機器前,請務必確認你開啟的硬碟是『unit13』,否則就會做錯題目
  • 若要使用圖形界面,請務必使用 student 身份登入,若需要切換身份,再啟用終端機處理。
  • 若有簡答題需要使用中文,請自行以第一堂課的動作自行處理輸入法安裝。
  • 每部虛擬機器均有獨特的網卡位址,請勿使用他人硬碟上傳,否則計分為 0 分。
  • 每位同學均有自己的 IP 尾數,請先向老師詢問您的 IP 尾數,才可以進行作業上傳。
  • 最終上傳作業結果,請務必使用 root 身份上傳。
  • 進入作業硬碟後,先用 root 身份執行 vbird_book_setup_ip , 執行流程請參考:vbird_book_setup_ip

作業當中,某些部份可能為簡答題~若為簡答題時,請將答案寫入 /home/student/ans.txt 當中,並寫好正確題號,方便老師訂正答案。 請注意,檔名寫錯將無法上傳!

請使用 root 的身份進行如下實做的任務。直接在系統上面操作,操作成功即可,上傳結果的程式會主動找到你的實做結果。

  1. (20%) 系統救援:
    • 你目前這個系統上,由於某些緣故, initramfs 檔案已經遺失,所以應該是無法成功開機到正常的系統中。
    • 請使用原版光碟進入系統救援的模式,並依據系統既有的核心版本 (/lib/modules/),將 initramfs 重建
    • 注意,重建時,應考慮 grub2 的原本設定檔 (參考 /boot/loader/entries/),以找到正確的檔名,方可順利成功開機喔
    • 不要忘記了,如果順利開機成功,請記得執行 vbird_book_setup_ip 設定好學號與 IP
  2. (20%) 請回答下列問題,並將答案寫在 /root/ans13.txt 檔案內:
    1. 管理系統的 process 時,通常是使用給予訊號 (signal) 的方式。而手動給予 Signal 的指令常見有哪兩個?
    2. 承上,常見的 signal 有 1, 9, 15, 19,各代表甚麼意思?
    3. 在 CentOS 8 系統上,所有的 systemd 服務腳本 (無論有沒有 enable) 放在哪個目錄內?
    4. 承上,但是系統【預設開機會載入】的腳本,又是放在哪個目錄內?
    5. systemd 會將服務進行分類,主要分為 X.service, X.socket, X.target,請問這幾個類型分別代表甚麼意思?
    6. 在此課堂上,啟動系統預設的網路服務,可以使用那五個口訣來處理?每個口訣對應的指令為何?
  3. (20%) Systemd 的操作與核心功能
    1. 透過網路服務監聽埠口觀察的指令查出系統有多少服務在啟動?無論如何,請將服務關閉到只剩下 tcp 的 port 22 與 port 111 兩個。 在底下有其他服務啟動後,自然會有多的埠口,不過在這個題目前,只能有這兩個埠口的存在。
    2. 讓這部 Linux 主機,預設會啟動在純文字模式下,亦即開機時,預設不會有圖形介面
    3. 讓系統預設啟動 IP 轉遞 (IP forward) 的功能,同時修改 dirty_ratio 成為 60, dirty_background_ratio 為 3
    4. 系統開機之後,會自動寄出一封 email 給 root,說明系統開機了。指令可以是『 echo "reboot new" | mail -s 'reboot message' root 』, 請注意,這個動作必須是系統『自動於開機完成後就動作』,而不需要使用者或管理員登入喔!
  4. (20%) 預設服務的啟動
    1. 讓系統使用『 network-latency 』的最佳化參數處理系統的優化功能。
    2. 請依據課堂上的服務啟動口訣,啟動 WWW 服務,WWW 服務使用 httpd 這個軟體。 並假設你知道 WWW 的首頁目錄位於 /var/www/html/ 以及首頁檔名為 index.html。 請在 index.html 內以 vim 新建兩行,分別是學號與姓名。
    3. 請依據課堂上的服務啟動口訣,啟動 FTP 服務,FTP 服務使用 vsftpd 這個軟體。 並假設你知道 FTP 的首頁目錄在 /var/ftp ,你要讓 /etc/fstab 提供給用戶端以 ftp://your.server.ip/pub/fstab 的網址下載,該如何複製 /etc/fstab 到正確的位置去?
  5. (20%) grub2 相關應用
    1. 修改開機時的預設值,讓選單等待達到 30 秒
    2. 讓開機時,核心加入 noapic 及 noacpi 兩個預設參數
    3. 在 grub2 主設定檔中增加一個選單,選單名稱為【 Go go MBR 】,透過 chainloader 的方式,讓這個選單出現在開機時的選擇畫面中 (但是,預設值還是正常的 Linux 開機選單)
    4. 在 /boot/loader/entries/ 中,建立名為 custom.conf 的選單檔案,從最新的核心選單檔案複製相關參數到此檔案中, 然後再建立一個名為【Graphical Linux】的選單,這個選單會強制進入圖形介面,而不是預設的文字介面。(hint: systemd.unit=???)

作業結果傳輸:請以 root 的身分執行 vbird_book_check_unit 指令上傳作業結果。 正常執行完畢的結果應會出現【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字樣。若需要查閱自己上傳資料的時間, 請在作業系統上面使用瀏覽器查詢: http://192.168.251.254 檢查相對應的課程檔案。 相關流程請參考: vbird_book_check_unit

修改歷史:
  • 2016/05/26:完成!
  • 2017/04/04:加入了 sysctl.conf 的使用以及加入了習題囉!
  • 2017/04/05:沒有想到第一題習題就出問題,忘記沒有講解原版ISO開機的救援問題...所以加上 13.2.5 的開機救援方式!
  • 2020/05/28:加入了 tuned 的功能、dracut 的使用、更多 sysctl.conf 的應用、修改 grub2 的 blscfg 功能!
  • 2020/06/08:作業的處理也加進來了!
2020/05/28 以來統計人數
計數器
伺服器篇文件
各版本彙整說明
CentOS 6.x