证书目标5.03 GRUB 2与登录
本节对GRUB 2引导程序在找到内核之后的引导过程做简单介绍。理解在此期间发生的事情有助于我们对引导过程出现的问题进行诊断。与内核相关的信息让我们更好理解这期间的每一步操作。
Linux的加载依赖于一个临时文件系统,即所谓的初始RAM硬盘(Initial RAM Disk)。当引导过程完成后,则控制权就交给systemd,即所谓的第一进程。本节将通过配置单元和目标,详细介绍Upstart文件的内容。
实际经验
大部分Linux发行版(包括RHEL 7)都用新的systemd服务管理器取代了Upstart和SysVinit。
本节还将介绍重新引导系统和正常关闭系统的命令。
实际经验
在systemd中,可将Unix中的理念(“一切都是文件”)重新表述为“一切都是单元”。单元是systemd的基本构成模块。
5.3.1 内核与初始RAM磁盘
从GRUB 2配置菜单选择了一个内核后,借助于初始RAM磁盘(Initial RAM Disk), Linux把引导任务交给内核。初始RAM磁盘实际上是一个文件系统,这可以从它在/boot目录中的文件名(initramfs)看出。
在引导过程中,Linux会把该临时文件系统加载到RAM中。然后,Linux加载硬件驱动程序,并启动第一个进程systemd。
接下来,systemd为initrd.target激活所有系统单元,并将根文件系统挂载到/sysroot下。最后,systemd在新的根目录中重新启动自己,并激活默认目标的所有单元(下一节将更详细地介绍单元和目标)。
为了解更多内容,首先在GRUB配置文件中禁用目标内核的quiet指令。引导系统。观察在屏幕上快速翻卷的消息。登录后,也可以在/var/log/dmesg文件中检查这些消息或者执行dmesg命令。
在systemd日志中可看到更多日志信息。使用journalctl命令显示其内容。我们实际看到的消息与本地系统的硬件和配置有关,关键消息有:
● 内核的版本号。
● SELinux的状态(假如它已激活)。默认情况下,SELinux第一次是以许可模式启动的,直到在引导过程快要完成时系统载入设定的策略(强制模式)为止。
● 可识别内存的大小(这个值不必与系统实际内存的大小相匹配)。
● CPU。
● 内核命令行,指定逻辑卷或根文件系统。
● 释放初始RAM磁盘(initramfs)占用的内存。
● 硬盘驱动器和分区(由它们的设备文件名定义,如/dev/sda或/dev/vda1)。
● 活动的文件系统。
● 交换分区。
这个日志文件还包含一些有用的信息。当系统载入错误的内核时,在这个文件中可看到这个信息。如果Linux没有使用我们配置好的分区,则这个文件也有这方面的信息(间接的)。如果SELinux无法正确载入,我们也会从该文件末尾的消息看出来。
考试提示
记住,Red Hat考试不是硬件考试。如果发现一个重要硬件配件(如网卡)出现了一个问题无法用Linux命令解决,要通知你的指导老师或监考人员。但如果他回答这不是一个硬件问题,也不要大惊小怪。
5.3.2 第一个进程、目标和单元
Linux内核通过调用第一个进程systemd继续此引导过程。在RHEL 7中,使用systemd的符号链接来配置遗留的init进程。
单元是systemd的基本组成模块。最常见的是服务单元,它们的扩展名为.service,负责激活某个系统服务。执行下面的命令可显示所有服务单元的一个列表:
# systemctl list-units --type=service --all
--all标志包含所有单元,而不只是活动的单元。还有其他类型的单元,如挂载单元和自动挂载单元,它们管理挂载点;路径单元,当文件系统路径发生变化时(如spool目录),它们激活服务;套接字单元,只有当客户端建立连接时,它们才启动服务(如果使用了xinetd守护进程,这类似于xinetd根据需要启动服务);除此之外还有其他许多单元。
目标单元是一种特殊类型的单元,用于将其他系统单元分组到一起,以及将系统切换到另一个状态。执行下面的命令可显示所有目标单元:
# systemctl list-units --type=target --all
表5-1说明了最重要的目标单元。
表5-1 systemd目标单元
在systemd中,目标的功能与以前的RHEL发行版中的运行级相同。在RHEL 6中,有7个运行级(从0到6)。Linux服务是按运行级进行组织的。每个运行级对应一个功能级。
例如,在运行级1中,只允许一个用户登录到该Linux系统。X11模式也称为运行级5,如果已经安装了相应的程序包,则它把Linux启动到GUI登录屏幕。表5-2对systemd目标和RHEL 6中定义的运行级做了一个比较。
表5-2 RHEL 6的运行级和RHEL 7的systemd目标
执行下面的命令:
# ls -l /usr/lib/systemd/system/runlevel? .target
注意输出中的符号链接。观察runlevel0.target、runlevel1.target等文件如何链接到systemd目标,如poweroff.target和rescue.target。这些链接提供了与原来的SysV运行级向后兼容的能力。可以用runlevel5.target表示graphical.target,用runlevel3.target表示multi-user.target。
目标受单元控制,并被组织为单元文件。虽然默认目标定义在/etc/systemd/system中,但是在引导过程中可以使用GRUB 2菜单覆盖默认目标。
每个目标可能关联着多个systemd单元。每个单元可启动或停止Linux服务,如打印(cupsd)、调度(crond)、Apache Web服务器(httpd)、Samba文件服务器(smbd)等。完成配置后,引导进程将启动和停止我们选择的systemd单元。这些单元称为依赖项。执行下面的命令可列出默认的graphical.target单元的所有依赖项:
# systemctl list-dependencies graphical.target
默认目标被指定为从/etc/systemd/system/default.target文件到multi-user.target或graphical. target的符号链接。还可以使用systemctl命令获取当前的默认目标或者修改当前的设置,如下所示:
# systemctl get-default graphical.target # systemctl set-default multi-user.target rm '/etc/systemd/system/default.target' ln -s '/usr/lib/systemd/system/multi-user.target'↲ '/etc/systemd/system/default.target'
从输出中可以看到,systemctl set-default multi-user.target命令创建了/etc/systemd/system/default.target的一个符号链接。
5.3.3 目标之间的切换
既然我们已经讨论了RHEL 7中各种不同的目标,现在来讨论目标之间如何切换。在RHEL的早期版本中,这在功能上等效于运行级的切换。首先,用下面的命令建立默认目标:
# systemctl get-default graphical.target
RHEL 7通常引导到graphical.target或multi-user.target。在作为管理员用户登录后,可以使用systemctl isolate命令移动到不同的目标。例如,下面的命令将系统移动到多用户目标:
# systemctl isolate multi-user.target
执行该命令后,重新运行systemctl get-default命令。输出确认默认目标没有改变:
graphical.target
现在尝试其他操作。执行下面的命令后,你认为会发生什么情况?
# systemctl isolate poweroff.target
5.3.4 重新启动和正常关闭系统
重新启动和关闭系统所需的命令十分直观。如前一节所述,下面的命令分别提供了关闭和重新启动系统的方法:
# systemctl poweroff
# systemctl reboot
考虑到遗留系统,Red Hat创建了从下面的命令到systemctl的符号链接。这些命令的使用与在RHEL的先前版本中相同。
# shutdown # reboot
5.3.5 systemd取代了Upstart和SysVInit
systemd是在引导时第一个启动的进程,它负责激活所有服务。systemd取代了传统的init守护进程和Upstart系统,后者取代了init,是RHEL 6中的默认init守护进程。Upstart的设计和理念非常类似于原来的SysVinit系统,依赖于init脚本来激活服务,也依赖于运行级的概念(前面已经介绍过)。
与之相对,systemd引入了许多新工具,可以实现的功能也更多,同时保留了与SysVinit的兼容性。systemd的设计基于最优效率。首先,在引导时,systemd仅激活严格需要的服务,而其他服务则根据需要启动。例如,只有向/var/spool/cups队列发送了打印作业后,systemd才会启动CUPS打印服务。另外,systemd会并行处理服务的初始化。
其结果是,使用systemd后的引导过程变得更快。执行下面的命令可显示系统引导所需的时间:
# systemd-analyze time Startup finished in 506ms(kernel)+ 1.144s↲ (initrd)+ 6.441s(userspace)= 8.092s.
输出显示了初始化内核所需的时间,以及加载初始RAM磁盘(initrd)的时间和激活systemd单元(userspace)的时间。总时间为8.092秒。但是不止如此。通过运行systemd-analyze blame命令,还可以显示激活每个systemd单元所需的详细时间。图5-7给出了一个例子。
图5-7 systemd单元的初始化时间
图5-7中的数字与systemdanalyze time报告的总userspace时间不相等。这是因为systemd会同时启动多个服务。
RHCSA考试没有要求深入理解systemd的所有功能,但是它的一些功能可被系统管理员利用。
一些Linux开发人员认为,systemd做的工作太多,破坏了Unix中的程序编写理念:“只做一件事并把它做好。”但是,如今大部分主流Linux发行版都已经采用了systemd。
1.日志记录
systemd进程包含了一个强大的日志系统。使用journalctl命令可以显示收集到的所有日志。默认情况下,日志文件临时存储在RAM中,或者/run/log/journal目录的环形缓冲区中。执行下面的命令后,Linux将把日志文件持久写入硬盘:
# mkdir /var/log/journal # chgrp systemd-journal /var/log/journal # chmod 2775 /var/log/journal # systemctl restart systemd-journald.service
一旦启用了持久日志,就可以使用-b开关选项显示特定一次引导中的日志消息:journalctl -b 0显示自上次引导以来的日志消息,journalctl -b 1显示上次引导之前的一次引导的日志消息,依此类推。journalctl会自动聚合当前日志文件和所有轮转日志文件中的可用数据,所以我们不需要在不同的日志文件中切换。
使用-p命令选项,可根据日志消息的优先级对其进行过滤。例如,journalctl -p warning显示优先级为“警告”或更高的所有消息。“警告”优先级的日志消息以粗体字符显示,“错误”或更高优先级的消息则显示为红色。
2. cgroups
控制组(cgroups)是Linux内核的一项功能,可将进程分组到一起,并控制或限制它们的资源使用(如CPU、内存等)。在systemd中,cgroups主要用于跟踪进程,确保当一个服务停止时,属于该服务的所有进程也被终止。
在传统的SysVinit系统中,难以确认与进程关联的服务。事实上,服务常常启动多个进程。当停止一个SysVinit服务时,该服务可能无法终止所有依赖的(子)进程。此时要么手动停止所有依赖服务(使用ps和kill命令),要么接受系统中在下次重新引导之前,存在状态未知的孤立进程。
为解决这种限制,systemd使用cgroup来标签与服务关联的进程。这样一来,如有必要,systemd会使用cgroups来杀死组中的所有进程。
systemd-cgls命令以树状格式显示cgroups的层次结构,如图5-8所示。在图5-8显示的片段中,可以看到rsyslog.service和avahi-daemon.service等cgroups,以及它们派生的进程。注意,cgroups和systemd服务单元之间存在一对一对应关系。
图5-8 cgoups的层次结构
3.依赖项
传统的SysVinit系统按顺序启动服务。与之不同,systemd通过跟踪单元之间的全部依赖关系,并行地激活服务。systemctl list-dependencies命令以树的形式显示单元之间的所有依赖关系,图5-9是其输出的一个节选。
图5-9 systemd单元之间的依赖关系
可以显示任意可用单元的依赖项。必须先启动依赖单元。例如,下面的命令显示了在启动rsyslog服务之前必须先启动的单元:
# systemctl list-dependencies rsyslog.service
5.3.6 systemd单元
systemd是第一个进程,该进程使用不同的配置文件来启动其他进程。这些配置文件保存在下面的目录中:/etc/systemd/system和/usr/lib/systemd/system。
默认配置文件存储在/usr/lib/systemd/system目录中。存储在/etc/systemd/system中的自定义文件可以覆盖这些文件。不要修改/usr/lib/systemd/system目录中的文件。任何软件更新都可能覆盖这些文件。
我们已经讨论了服务和目标单元,但是还有更多单元。表5-3简要说明了所有可用的单元类型。
表5-3 systemd单元类型
查看/usr/lib/systemd/system目录的内容。每个文件都包含一个systemd单元的配置,其类型与文件扩展名匹配。例如,文件graphical.target定义了图形登录目标单元的配置,而文件rsyslog.service则包含了rsyslog服务单元的配置。
执行下面的命令可列出所有活动的systemd单元:
# systemctl list-units
list-units关键字是可选的,因为它是默认选项。如果想要保护非活动单元、维护单元和失败的单元,需要添加--all命令开关。图5-10显示了此命令的输出节选。
图5-10 systemd的单元
在输出中,第一列显示了单元名称,第二列显示了该单元是否被正确加载。第三列显示了单元的状态:活动、非活动、失败或维护。第四列包含了更多细节。最后一列简单描述了该单元。
systemctl list-units命令给出了每个单元的状态的运行时快照,下面的命令则显示了一个单元在启动时被启用还是禁用:
# systemctl list-unit-files
图5-11显示了该命令的输出。可以看到,单元可被“启用”(enabled)或“禁用”(disabled)。另外还有一个static状态,表示该单元已被启用且不能被手动修改。
图5-11 已安装的单元文件
5.3.7 虚拟终端与登录界面
在Linux中的登录终端通常是虚拟终端。大多数Linux系统(包括RHEL 7)都配置了6个标准的命令行虚拟终端。这些控制台用1~6数字表示。如果配置了一个GUI和一个登录管理器,RHEL 7将用图形登录界面取代第一个虚拟终端。
所有这一切意味着什么呢?在Linux中,用ALT+功能键可以在各个虚拟终端之间切换。例如,ALT+F2可以切换到第2个虚拟终端。按下ALT+右向方向键和ALT+左向方向键可以在相邻的虚拟终端之间进行切换。例如,从第2个虚拟终端切换到第3个虚拟终端,按下ALT+右向方向键。如果用户正处在GUI虚拟终端中,则增加一个CTRL键。因此在RHEL 7中,如果已经安装GUI而且当前正处于第一个虚拟终端中,要切换到第2个虚拟终端必须按下CTRL+ALT+F2。
如果我们登录到一个普通的虚拟终端,则Linux返回一个命令行shell。默认的shell定义在/etc/passwd文件中,这将在第6章介绍。当我们登录到一个GUI虚拟终端中,则Linux返回已配置的GUI桌面。有关Linux GUI的更多信息请阅读第8章。
在RHEL 6中,虚拟终端是在/etc/sysconfig/init和/etc/init目录的文件中配置的。因为systemd已经取代了Upstart,现在它们在/etc/systemd目录的logind.conf文件中定义。
虚拟终端使Linux的多用户功能起死回生。在工作中(或在Red Hat考试期间),我们可以在一个终端上浏览man文档,在另一个终端中编译一个程序,在第三个终端中编辑一个配置文件等。其他通过网络连接的用户也可以在同一个时刻做相同的事情。