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 以来统计人数
计数器
其他链接
环境工程模式篇
鸟园讨论区
鸟哥旧站

今日 人数统计
昨日 人数统计
本月 人数统计
上月 人数统计