在爱上 systemd,本系列的第一篇文章中,我研究了 systemd 的功能和架构,以及关于其作为旧 SystemV init 程序和启动脚本的替代品的争议。在第二篇文章中,我将开始探索管理 Linux 启动序列的文件和工具。我将解释 systemd 启动序列、如何更改默认启动目标(SystemV 术语中的运行级别),以及如何在不重启的情况下手动切换到不同的目标。
我还将介绍两个重要的 systemd 工具。第一个是 systemctl 命令,它是与 systemd 交互和向 systemd 发送命令的主要方式。第二个是 journalctl,它提供对 systemd 日志的访问,这些日志包含大量的系统历史数据,例如内核和服务消息(信息和错误消息)。
请务必使用非生产系统进行本文和未来文章中的测试和实验。您的测试系统需要安装 GUI 桌面(例如 Xfce、LXDE、Gnome、KDE 或其他)。
我在上一篇文章中写道,我计划在本文中研究创建 systemd 单元并将其添加到启动序列中。由于本文比我预期的要长,我将把这部分内容留到本系列的下一篇文章中。
使用 systemd 探索 Linux 启动
在您可以观察启动序列之前,您需要做几件事,使引导和启动序列公开可见。通常,大多数发行版都使用启动动画或启动画面来隐藏在 Linux 主机启动和关闭期间显示的详细消息。这在基于 Red Hat 的发行版上称为 Plymouth 启动画面。这些隐藏的消息可以为系统管理员提供大量关于启动和关闭的信息,以便查找信息来排除错误或只是了解启动序列。您可以使用 GRUB(Grand Unified Boot Loader)配置来更改此设置。
主要的 GRUB 配置文件是 /boot/grub2/grub.cfg,但是,由于此文件可以在内核版本更新时被覆盖,因此您不想更改它。相反,请修改 /etc/default/grub 文件,该文件用于修改 grub.cfg 的默认设置。
首先查看 /etc/default/grub 文件的当前未修改版本
[root@testvm1 ~]# cd /etc/default ; cat 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="resume=/dev/mapper/fedora_testvm1-swap rd.lvm.
lv=fedora_testvm1/root rd.lvm.lv=fedora_testvm1/swap rd.lvm.lv=fedora_
testvm1/usr rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
[root@testvm1 default]#
GRUB 文档的第 6 章包含 /etc/default/grub 文件中所有可能条目的列表,但我重点关注以下内容
- 我将 GRUB_TIMEOUT(GRUB 菜单倒计时的秒数)从 5 秒更改为 10 秒,以便在倒计时达到零之前有更多时间响应 GRUB 菜单。
- 我删除 GRUB_CMDLINE_LINUX 上的最后两个参数,其中列出了在启动时传递给内核的命令行参数。其中一个参数 rhgb 代表 Red Hat Graphical Boot,它在内核初始化期间显示小的 Fedora 图标动画,而不是显示启动时消息。另一个 quiet 参数阻止显示记录启动进度和发生的任何错误的启动消息。我删除 rhgb 和 quiet,因为系统管理员需要查看这些消息。如果在启动期间出现问题,屏幕上显示的消息可以指向问题的原因。
在您进行这些更改后,您的 GRUB 文件将如下所示
[root@testvm1 default]# cat grub
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="resume=/dev/mapper/fedora_testvm1-swap rd.lvm.
lv=fedora_testvm1/root rd.lvm.lv=fedora_testvm1/swap rd.lvm.lv=fedora_
testvm1/usr"
GRUB_DISABLE_RECOVERY="false"
[root@testvm1 default]#
grub2-mkconfig 程序使用 /etc/default/grub 文件的内容生成 grub.cfg 配置文件,以修改一些默认的 GRUB 设置。grub2-mkconfig 程序将其输出发送到 STDOUT。它有一个 -o 选项,允许您指定一个文件来发送数据流,但使用重定向同样容易。运行以下命令以更新 /boot/grub2/grub.cfg 配置文件
[root@testvm1 grub2]# grub2-mkconfig > /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.18.9-200.fc28.x86_64
Found initrd image: /boot/initramfs-4.18.9-200.fc28.x86_64.img
Found linux image: /boot/vmlinuz-4.17.14-202.fc28.x86_64
Found initrd image: /boot/initramfs-4.17.14-202.fc28.x86_64.img
Found linux image: /boot/vmlinuz-4.16.3-301.fc28.x86_64
Found initrd image: /boot/initramfs-4.16.3-301.fc28.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-7f12524278bd40e9b10a085bc82dc504
Found initrd image: /boot/initramfs-0-rescue-7f12524278bd40e9b10a085bc82dc504.img
done
[root@testvm1 grub2]#
重新启动您的测试系统以查看启动消息,否则这些消息将被 Plymouth 启动动画隐藏。但是,如果您需要查看启动消息但未禁用 Plymouth 启动动画怎么办?或者您已经禁用了,但消息流过快而无法读取?(它们确实如此。)
有几个选项,两者都涉及日志文件和 systemd 日志—它们是您的朋友。您可以使用 less 命令查看 /var/log/messages 文件的内容。此文件包含启动和启动消息以及操作系统在正常运行期间生成的消息。您也可以使用不带任何选项的 journalctl 命令来查看 systemd 日志,其中包含基本相同的信息
[root@testvm1 grub2]# journalctl
-- Logs begin at Sat 2020-01-11 21:48:08 EST, end at Fri 2020-04-03 08:54:30 EDT. --
Jan 11 21:48:08 f31vm.both.org kernel: Linux version 5.3.7-301.fc31.x86_64 (mockbuild@bkernel03.phx2.fedoraproject.org) (gcc version 9.2.1 20190827 (Red Hat 9.2.1-1) (GCC)) #1 SMP Mon Oct >
Jan 11 21:48:08 f31vm.both.org kernel: Command line: BOOT_IMAGE=(hd0,msdos1)/vmlinuz-5.3.7-301.fc31.x86_64 root=/dev/mapper/VG01-root ro resume=/dev/mapper/VG01-swap rd.lvm.lv=VG01/root rd>
Jan 11 21:48:08 f31vm.both.org kernel: x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
Jan 11 21:48:08 f31vm.both.org kernel: x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
Jan 11 21:48:08 f31vm.both.org kernel: x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
Jan 11 21:48:08 f31vm.both.org kernel: x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
Jan 11 21:48:08 f31vm.both.org kernel: x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-provided physical RAM map:
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x0000000000100000-0x00000000dffeffff] usable
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x00000000dfff0000-0x00000000dfffffff] ACPI data
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
Jan 11 21:48:08 f31vm.both.org kernel: BIOS-e820: [mem 0x0000000100000000-0x000000041fffffff] usable
Jan 11 21:48:08 f31vm.both.org kernel: NX (Execute Disable) protection: active
Jan 11 21:48:08 f31vm.both.org kernel: SMBIOS 2.5 present.
Jan 11 21:48:08 f31vm.both.org kernel: DMI: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
Jan 11 21:48:08 f31vm.both.org kernel: Hypervisor detected: KVM
Jan 11 21:48:08 f31vm.both.org kernel: kvm-clock: Using msrs 4b564d01 and 4b564d00
Jan 11 21:48:08 f31vm.both.org kernel: kvm-clock: cpu 0, msr 30ae01001, primary cpu clock
Jan 11 21:48:08 f31vm.both.org kernel: kvm-clock: using sched offset of 8250734066 cycles
Jan 11 21:48:08 f31vm.both.org kernel: clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
Jan 11 21:48:08 f31vm.both.org kernel: tsc: Detected 2807.992 MHz processor
Jan 11 21:48:08 f31vm.both.org kernel: e820: update [mem 0x00000000-0x00000fff] usable ==> reserved
Jan 11 21:48:08 f31vm.both.org kernel: e820: remove [mem 0x000a0000-0x000fffff] usable
<snip>
我截断了此数据流,因为它可能有数十万甚至数百万行长。(我的主工作站上的日志列表为 1,188,482 行。)请务必在您的测试系统上尝试此操作。如果它已运行一段时间—即使它已多次重启—将显示大量数据。探索此日志数据,因为它包含大量在进行问题确定时非常有用的信息。了解正常启动和启动的数据外观可以帮助您在问题发生时定位问题。
我将在本系列以后的文章中更详细地讨论 systemd 日志、journalctl 命令以及如何对所有数据进行排序以找到您想要的内容。
在 GRUB 将内核加载到内存后,它必须首先从文件的压缩版本中提取自身,然后才能执行任何有用的工作。在内核提取自身并开始运行后,它会加载 systemd 并将控制权移交给它。
这是引导过程的结束。此时,Linux 内核和 systemd 正在运行,但无法为最终用户执行任何生产任务,因为没有其他任何程序在运行,没有 shell 来提供命令行,没有后台进程来管理网络或其他通信链接,也没有任何使计算机能够执行任何生产功能的程序。
Systemd 现在可以加载将系统启动到选定目标运行状态所需的功能单元。
目标
systemd 目标表示 Linux 系统的当前或期望运行状态。与 SystemV 启动脚本非常相似,目标定义了系统在该状态下运行和处于活动状态所需的服务。图 1 显示了使用 systemd 的 Linux 系统的可能运行状态目标。如本系列的第一篇文章和 systemd 启动手册页 (man bootup) 中所示,还有其他中间目标是启用各种必要服务所必需的。这些可以包括 swap.target、timers.target、local-fs.target 等。一些目标(如 basic.target)用作检查点,以确保所有必需的服务都已启动并运行,然后再继续到更高级别的目标。
除非在 GRUB 菜单中的启动时另有更改,否则 systemd 始终启动 default.target。default.target 文件是指向真实目标文件的符号链接。对于桌面工作站,这通常是 graphical.target,它等效于 SystemV 中的运行级别 5。对于服务器,默认设置更可能是 multi-user.target,它类似于 SystemV 中的运行级别 3。emergency.target 文件类似于单用户模式。目标和服务是 systemd 单元。
下表(我在本系列的前一篇文章中包含)比较了 systemd 目标与旧的 SystemV 启动运行级别。systemd 目标别名由 systemd 提供,用于向后兼容。目标别名允许脚本—和系统管理员—使用 SystemV 命令(如 init 3)来更改运行级别。当然,SystemV 命令被转发到 systemd 进行解释和执行。
systemd 目标 | SystemV 运行级别 | 目标别名 | 描述 |
default.target | 此目标始终使用指向 multi-user.target 或 graphical.target 的符号链接进行别名。systemd 始终使用 default.target 来启动系统。default.target 永远不应别名为 halt.target、poweroff.target 或 reboot.target。 | ||
graphical.target | 5 | runlevel5.target | Multi-user.target,带 GUI |
4 | runlevel4.target | 未使用。在 SystemV 世界中,运行级别 4 与运行级别 3 相同。可以创建和自定义此目标以启动本地服务,而无需更改默认的 multi-user.target。 | |
multi-user.target | 3 | runlevel3.target | 所有服务都在运行,但仅限命令行界面 (CLI) |
2 | runlevel2.target | 多用户,没有 NFS,但所有其他非 GUI 服务都在运行 | |
rescue.target | 1 | runlevel1.target | 基本系统,包括挂载文件系统,仅运行最基本的服务,并在主控制台上提供救援 shell |
emergency.target | S | 单用户模式—没有服务在运行;文件系统未挂载。这是最基本的操作级别,仅在主控制台上运行紧急 shell,供用户与系统交互。 | |
halt.target | 停止系统,但不关闭电源 | ||
reboot.target | 6 | runlevel6.target | 重启 |
poweroff.target | 0 | runlevel0.target | 停止系统并关闭电源 |
图 1:SystemV 运行级别与 systemd 目标和目标别名的比较。
每个目标在其配置文件中都有一组依赖项描述。systemd 启动所需的依赖项,这些依赖项是在特定功能级别运行 Linux 主机所需的服务。当目标配置文件中列出的所有依赖项都已加载并运行时,系统在该目标级别运行。如果您愿意,您可以查看本系列第一篇文章 爱上 systemd 中的 systemd 启动序列和运行时目标。
探索当前目标
许多 Linux 发行版默认安装 GUI 桌面界面,以便可以将已安装的系统用作工作站。我总是从带有 Xfce 或 LXDE 桌面的 Fedora Live 启动 USB 驱动器安装。即使我正在安装服务器或其他基础设施类型的主机(例如我用于路由器和防火墙的主机),我也使用安装 GUI 桌面的这些安装之一。
我可以安装没有桌面的服务器(这对于数据中心来说是典型的),但这不符合我的需求。并不是我需要 GUI 桌面本身,而是 LXDE 安装包含我使用的许多其他工具,这些工具不在默认服务器安装中。这意味着在初始安装后我可以减少工作量。
但是仅仅因为我有 GUI 桌面并不意味着使用它是有意义的。我有一个 16 端口 KVM,我可以使用它来访问我的大多数 Linux 系统的 KVM 接口,但我与它们的大多数交互是通过从我的主工作站的远程 SSH 连接进行的。与 graphical.target 相比,这种方式更安全,并且使用更少的系统资源来运行 multi-user.target。
首先,检查默认目标以验证它是否是 graphical.target
[root@testvm1 ~]# systemctl get-default
graphical.target
[root@testvm1 ~]#
现在验证当前正在运行的目标。它应该与默认目标相同。您仍然可以使用旧方法,该方法显示旧的 SystemV 运行级别。请注意,先前的运行级别在左侧;它是 N(表示无),指示自主机启动以来运行级别未更改。数字 5 表示当前目标,如旧的 SystemV 术语中所定义
[root@testvm1 ~]# runlevel
N 5
[root@testvm1 ~]#
请注意,运行级别手册页指示运行级别已过时,并提供了转换表。
您也可以使用 systemd 方法。这里没有一句话的答案,但它确实以 systemd 术语提供了答案
[root@testvm1 ~]# systemctl list-units --type target
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target loaded active active Network
nfs-client.target loaded active active NFS client services
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target loaded active active Paths
remote-fs-pre.target loaded active active Remote File Systems (Pre)
remote-fs.target loaded active active Remote File Systems
rpc_pipefs.target loaded active active rpc_pipefs.target
slices.target loaded active active Slices
sockets.target loaded active active Sockets
sshd-keygen.target loaded active active sshd-keygen.target
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
timers.target loaded active active Timers
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.
21 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
这显示了所有当前已加载和活动的目标。您还可以看到 graphical.target 和 multi-user.target。在加载 graphical.target 之前,需要 multi-user.target。在此示例中,graphical.target 处于活动状态。
切换到不同的目标
切换到 multi-user.target 很简单
[root@testvm1 ~]# systemctl isolate multi-user.target
显示现在应该从 GUI 桌面或登录屏幕更改为虚拟控制台。登录并列出当前活动的 systemd 单元以验证 graphical.target 是否不再运行
[root@testvm1 ~]# systemctl list-units --type target
请务必使用 runlevel 命令来验证它是否同时显示了先前和当前的“运行级别”
[root@testvm1 ~]# runlevel
5 3
更改默认目标
现在,将默认目标更改为 multi-user.target,以便它始终启动到 multi-user.target 以获得控制台命令行界面,而不是 GUI 桌面界面。作为测试主机上的 root 用户,更改为维护 systemd 配置的目录并快速列出
[root@testvm1 ~]# cd /etc/systemd/system/ ; ll
drwxr-xr-x. 2 root root 4096 Apr 25 2018 basic.target.wants
<snip>
lrwxrwxrwx. 1 root root 36 Aug 13 16:23 default.target -> /lib/systemd/system/graphical.target
lrwxrwxrwx. 1 root root 39 Apr 25 2018 display-manager.service -> /usr/lib/systemd/system/lightdm.service
drwxr-xr-x. 2 root root 4096 Apr 25 2018 getty.target.wants
drwxr-xr-x. 2 root root 4096 Aug 18 10:16 graphical.target.wants
drwxr-xr-x. 2 root root 4096 Apr 25 2018 local-fs.target.wants
drwxr-xr-x. 2 root root 4096 Oct 30 16:54 multi-user.target.wants
<snip>
[root@testvm1 system]#
我缩短了此列表以突出显示一些重要的内容,这些内容将有助于解释 systemd 如何管理启动过程。您应该能够在您的虚拟机上看到目录和链接的完整列表。
default.target 条目是指向目录 /lib/systemd/system/graphical.target 的符号链接(symlink,软链接)。列出该目录以查看其中还有什么
[root@testvm1 system]# ll /lib/systemd/system/ | less
您应该在此列表中看到文件、目录和更多链接,但请特别查找 multi-user.target 和 graphical.target。现在显示 default.target 的内容,它是指向 /lib/systemd/system/graphical.target 的链接
[root@testvm1 system]# cat default.target
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
[root@testvm1 system]#
此指向 graphical.target 文件的链接描述了图形用户界面所需的所有先决条件和要求。我将在本系列的下一篇文章中探索至少其中一些选项。
要使主机启动到多用户模式,您需要删除现有链接并创建一个指向正确目标的新链接。如果 PWD /etc/systemd/system,如果它还不是
[root@testvm1 system]# rm -f default.target
[root@testvm1 system]# ln -s /lib/systemd/system/multi-user.target default.target
列出 default.target 链接以验证它是否链接到正确的文件
[root@testvm1 system]# ll default.target
lrwxrwxrwx 1 root root 37 Nov 28 16:08 default.target -> /lib/systemd/system/multi-user.target
[root@testvm1 system]#
如果您的链接看起来不完全像这样,请删除它并重试。列出 default.target 链接的内容
[root@testvm1 system]# cat default.target
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
[root@testvm1 system]#
default.target—此时实际上是指向 multi-user.target 的链接—现在在 [Unit] 部分中具有不同的要求。它不需要图形显示管理器。
重启。您的虚拟机应启动到虚拟控制台 1 的控制台登录,该控制台在显示器上标识为 tty1。现在您知道如何更改默认目标,请使用为此目的设计的命令将其更改回 graphical.target。
首先,检查当前默认目标
[root@testvm1 ~]# systemctl get-default
multi-user.target
[root@testvm1 ~]# systemctl set-default graphical.target
Removed /etc/systemd/system/default.target.
Created symlink /etc/systemd/system/default.target → /usr/lib/systemd/system/graphical.target.
[root@testvm1 ~]#
输入以下命令直接转到 graphical.target 和显示管理器登录页面,而无需重启
[root@testvm1 system]# systemctl isolate default.target
我不知道 systemd 的开发人员为什么为这个子命令选择“isolate”这个词。我的研究表明,它可能指的是运行指定的目标,但“隔离”和终止所有不支持该目标的其他目标。但是,效果是将目标从一个运行目标切换到另一个运行目标—在本例中,从多用户目标切换到图形目标。上面的命令等效于 SystemV 启动脚本和 init 程序中的旧 init 5 命令。
登录到 GUI 桌面,并验证它是否按预期工作。
总结
本文探讨了 Linux systemd 启动序列,并开始探索两个重要的 systemd 工具 systemctl 和 journalctl。它还解释了如何从一个目标切换到另一个目标以及如何更改默认目标。
本系列的下一篇文章将创建一个新的 systemd 单元,并将其配置为在启动期间运行。它还将研究一些配置选项,这些选项有助于确定特定单元将在序列中的哪个位置启动,例如,在网络启动并运行之后。
资源
互联网上有大量关于 systemd 的信息,但其中很多信息都很简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了关于 systemd 启动的更详细和可靠的信息。
- Fedora 项目有一个很好的实用指南 到 systemd。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
- Fedora 项目还有一个很好的速查表,其中交叉引用了旧的 SystemV 命令和可比较的 systemd 命令。
- 有关 systemd 的详细技术信息以及创建 systemd 的原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧。
Lennart Poettering(systemd 的设计者和主要开发者)还为 Linux 系统管理员编写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在仍然像当时一样具有相关性。关于 systemd 及其生态系统的大部分其他优秀作品都基于这些论文。
3 条评论