跳至内容

实验3: 启动和启动过程

目标

完成本实验后,您将能够

  • 手动控制一些启动过程和服务
  • 自动控制服务

估计完成本实验所需时间: 50 分钟

启动过程概述

本实验中的练习将从启动过程开始,一直到用户登录。 这些步骤将检查并尝试自定义启动过程的部分内容。 启动过程中的高级步骤如下:

步骤总结

  1. 硬件加载、读取并执行引导扇区
  2. 执行引导加载程序 (大多数 Linux 发行版上的 GRUB)
  3. 内核解压缩并执行
  4. 内核初始化硬件
  5. 内核挂载根文件系统
  6. 内核执行 /usr/lib/systemd/systemd 作为 PID 1
  7. systemd 启动运行默认启动目标所需的单元和配置
  8. getty 程序在每个定义的终端上生成
  9. getty 提示登录
  10. getty 执行 /bin/login 以验证用户
  11. 登录启动 Shell

systemd

systemd 是 Linux 操作系统的系统和服务管理器。

systemd 单元

systemd 为各种实体提供了一个依赖系统,称为“单元”。 单元封装了系统启动和维护所需的各种对象。 大多数单元都在所谓的单元配置文件中进行配置 - 纯文本 ini 风格的文件。

systemd 单元类型

systemd 定义了以下 11 种单元类型:

服务单元 启动和控制守护进程及其包含的进程。

套接字单元 封装系统中的本地 IPC 或网络套接字,对于基于套接字的激活很有用。

目标单元 用于对其他单元进行分组。 它们在启动过程中提供众所周知的同步点

设备单元systemd 中公开内核设备,可用于实现基于设备的激活。

挂载单元 控制文件系统中的挂载点

自动挂载单元 提供自动挂载功能,用于按需挂载文件系统,以及并行启动。

计时器单元 用于基于计时器触发其他单元的激活。

交换单元 与挂载单元非常相似,并封装操作系统的内存交换分区或文件。

路径单元 当文件系统对象发生变化或被修改时,可以激活其他服务。

切片单元 可用于将管理系统进程 (如服务和范围单元) 的单元在层次结构树中进行分组,以进行资源管理。

范围单元 与服务单元类似,但管理外部进程,而不是启动它们。

练习1

/usr/lib/systemd/systemd | PID=1

历史上 init 被称为许多名称,并采取了许多形式。

无论其名称或实现如何,init (或其等效项) 通常被称为所有进程之母

“init” 的手册页将其称为所有进程的父进程。 按照惯例,内核执行的第一个程序或进程始终具有进程 ID 1。 一旦第一个进程运行,它就会继续启动其他服务、守护进程、进程、程序等等。

探索第一个系统进程

注意

在以下练习中,将 PID 替换为进程 ID 号。

  1. 以任何用户身份登录系统。查询 /proc/PID/comm 虚拟文件系统路径,并找出 ID 为 1 的进程的名称。键入

    [root@localhost ~]# cat /proc/1/comm
    
    systemd
    
  2. 运行 ls 命令以查看 /proc/PID/exe 虚拟文件系统路径,并查看 ID 为 1 的进程背后的可执行文件的名称和路径。键入

    [root@localhost ~]# ls -l /proc/1/exe
    
    lrwxrwxrwx 1 root root 0 Oct  5 23:56 /proc/1/exe -> /usr/lib/systemd/systemd
    
  3. 尝试使用 ps 命令找出 PID 背后的进程或程序的名称。键入

    [root@localhost ~]# ps -p 1 -o comm=
    
    systemd
    
  4. 使用 ps 命令查看 PID 1 背后的进程或程序的完整路径和任何命令行参数。键入

    [root@localhost ~]# ps -p  1 -o args=
    
    /usr/lib/systemd/systemd --switched-root --system --deserialize 16
    
  5. 要检查所有进程之母(传统上称为 init)实际上是否为 systemd,请使用 ls 确认 init 是指向 systemd 二进制文件的符号链接。键入

    [root@localhost ~]# ls -l /usr/sbin/init
    lrwxrwxrwx. 1 root root 22 Aug  8 15:33 /usr/sbin/init -> ../lib/systemd/systemd
    
  6. 使用 pstree 命令显示系统进程的树状视图。键入

    [root@localhost ~]# pstree --show-pids
    

练习 2

systemd 目标 (RUNLEVELS)

systemd 定义并依赖于许多不同的目标来管理系统。在本练习中,我们将重点介绍五个主要目标中的五个。本节中探讨的五个主要目标列出如下

  1. poweroff.target
  2. rescue.target
  3. multi-user.target - 以完整的多用户支持引导系统,没有图形环境
  4. graphical.target - 以网络、多用户支持和显示管理器引导系统
  5. reboot.target

提示

目标单元在经典的 SysV init 系统中替换 SysV 运行级别。

要管理 systemd 目标

  1. 列出服务器上所有(活动 + 非活动 + 失败)可用目标。

    [root@localhost ~]# systemctl list-units --type target --all
    
  2. 仅列出当前活动的目标。键入

    [root@localhost ~]# systemctl list-units -t target    
    
  3. 使用 systemctl 命令查看/获取系统配置为引导进入的默认目标的名称。键入

    [root@localhost ~]# systemctl get-default
    
    multi-user.target
    
  4. 查看默认目标 (multi-user.target) 的单元文件的內容。键入

    [root@localhost ~]# systemctl cat multi-user.target
    
    # /usr/lib/systemd/system/multi-user.target
    ........
    [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
    

    请注意 multi-user.target 单元中配置的一些属性及其值。例如 - Description、Documentation、Requires、After 等属性。

  5. basic.target 单元列为 multi-user.targetRequires 属性的值。查看 basic.target 的单元文件。键入

    [root@localhost ~]# systemctl cat multi-user.target
    # /usr/lib/systemd/system/basic.target
    [Unit]
    Description=Basic System
    Documentation=man:systemd.special(7)
    Requires=sysinit.target
    Wants=sockets.target timers.target paths.target slices.target
    After=sysinit.target sockets.target paths.target slices.target tmp.mount
    RequiresMountsFor=/var /var/tmp
    
  6. systemctl cat 命令只显示给定单元的部分属性和值。要查看目标单元所有属性和值的转储,请使用 show 子命令。show 命令还将显示底层属性。显示 multi-user.target 的所有属性,键入

    [root@localhost ~]# systemctl show  multi-user.target
    
  7. 从 multi-user.target 单元中长属性列表中过滤掉 Id、Requires 和 Description 属性。键入

    [root@localhost ~]# systemctl --no-pager show \
    --property  Id,Requires,Description  multi-user.target
    
    Id=multi-user.target
    Requires=basic.target
    Description=Multi-User System
    
  8. 查看 multi-user.target 启动时调用的服务和资源。换句话说,显示 multi-user.target “需要”什么。键入

    [root@localhost ~]# systemctl show --no-pager -p "Wants"  multi-user.target
    
    Wants=irqbalance.service sshd.service.....
    ...<SNIP>...
    
  9. 使用 lsfile 命令来了解传统的 init 程序与 systemd 程序的关系。键入

    [root@localhost ~]# ls -l /usr/sbin/init && file /usr/sbin/init
    
    lrwxrwxrwx. 1 root root 22 Aug  8 15:33 /usr/sbin/init -> ../lib/systemd/systemd
    /usr/sbin/init: symbolic link to ../lib/systemd/systemd
    

要更改默认引导目标

  1. 设置/更改系统引导进入的默认目标。使用 systemctl set-default 命令将默认目标更改为 graphical.target。键入

    [root@localhost ~]# systemctl set-default graphical.target
    
  2. 检查新设置的引导目标是否处于活动状态。键入

    [root@localhost ~]# systemctl is-active graphical.target
    
    inactive
    

    请注意,即使它被设置为默认值,输出显示目标也没有处于活动状态!

  3. 要强制系统立即切换到并使用给定的目标,您必须使用 isolate 子命令。键入

    [root@localhost ~]# systemctl isolate graphical.target
    

    警告

    如果使用不当,systemctl isolate 命令可能很危险。这是因为它将立即停止在新目标中未启用的进程,可能包括您当前使用的图形环境或终端!

  4. 再次检查 graphical.target 是否正在使用并且处于活动状态。

  5. 查询并查看 graphical.target “需要”的其他服务或资源。

    问题

    multi-user.target 和 graphical.target “需要”之间的主要区别是什么?

  6. 由于您的系统运行着服务器级操作系统发行版,其中完整的图形桌面环境可能不可取,因此将系统切换回更合适的 multi-user.target。键入

    [root@localhost ~]# systemctl isolate multi-user
    
  7. 将默认系统启动目标设置/更改回 multi-user.target。

  8. 运行一个快速(和额外的)手动检查,以查看 default.target 符号链接指向哪个目标,方法是运行

    [root@localhost ~]# ls -l /etc/systemd/system/default.target
    

练习 3

本节中的练习将向您展示如何配置可能需要随系统自动启动的系统/用户进程和守护进程(也称为服务)。

要查看服务状态

  1. 以 root 用户身份登录时,列出所有类型为服务的 systemd 单元。键入

    root@localhost ~]# systemctl list-units -t service -all
    

    这将显示活动和已加载但处于非活动状态的单元的完整列表。

  2. 查看具有服务类型的活动 systemd 单元列表。

    [root@localhost ~]# systemctl list-units --state=active --type service
    UNIT                LOAD   ACTIVE SUB     DESCRIPTION
    atd.service         loaded active running Job spooling tools
    auditd.service      loaded active running Security Auditing Service
    chronyd.service     loaded active running NTP client/server
    crond.service       loaded active running Command Scheduler
    dbus.service        loaded active running D-Bus System Message Bus
    firewalld.service   loaded active running firewalld - dynamic firewall daemon
    ...<SNIP>...
    
  3. 缩小范围并详细了解上一个输出中其中一个服务的配置,即 crond.service。键入

    [root@localhost ~]# systemctl cat crond.service
    
  4. 检查 crond.service 是否配置为在系统启动时自动启动。键入

    [root@localhost ~]# systemctl is-enabled  crond.service
    
    enabled
    
  5. 查看 crond.service 服务的实时状态。键入

    [root@localhost ~]# systemctl  status  crond.service  
    

    输出将默认包含最新的 10 个日志行/条目/日志。

  6. 查看 crond.service 的状态并抑制显示任何日志行。键入

    [root@localhost ~]# systemctl -n 0  status  crond.service  
    
  7. 查看 sshd.service 的状态。

    问题

    查看 firewalld.service 的状态。firewalld.service 单元是什么?

要停止服务

  1. 仍在以具有管理权限的用户身份登录时,使用 pgrep 命令查看 crond 进程是否出现在系统上运行的进程列表中。

    [root@localhost ~]# pgrep  -a crond
    
    313274 /usr/sbin/crond -n
    

    如果找到匹配的进程名称,pgrep 命令应该找到并列出 crond 的 PID。

  2. 使用 systemctl 停止 crond.service 单元。键入

    [root@localhost ~]# systemctl stop crond.service
    

    该命令应完成而没有任何输出。

  3. 使用 systemctl 查看 crond.service 的状态,以查看更改的效果。

  4. 再次使用 pgrep 查看 crond 进程是否仍出现在进程列表中。

要启动服务

  1. 以管理用户帐户登录。使用 pgrep 命令查看系统上运行的进程列表中是否出现 crond 进程。

    [root@localhost ~]# pgrep  -a crond
    

    如果 pgrep 找到匹配的进程名称,它将列出 crond 的 PID。

  2. 使用 systemctl 启动 crond.service 单元。键入

    [root@localhost ~]# systemctl start crond.service
    

    该命令应完成而没有任何输出或可见反馈。

  3. 使用 systemctl 查看 crond.service 的状态,以查看更改的效果。键入

    [root@localhost ~]# systemctl -n 0 status crond.service crond.service - Command Scheduler
    Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
    Active: active (running) since Mon 2023-10-16 11:38:04 EDT; 54s ago
    Main PID: 313451 (crond)
        Tasks: 1 (limit: 48282)
    Memory: 1000.0K
    CGroup: /system.slice/crond.service
            └─313451 /usr/sbin/crond -n
    

    问题

    从您系统上 systemctl 状态命令的输出中,crond 的 PID 是什么?

  4. 类似地再次使用 pgrep 查看 crond 进程是否现在出现在进程列表中。将 pgrep 显示的 PID 与之前的 systemctl 状态 crond.service 中显示的 PID 进行比较。

    [root@localhost ~]# systemctl is-enabled  crond.service
    
    enabled
    

要重新启动服务

对于许多服务/守护进程,每当对其底层配置文件进行更改时,都需要重新启动或重新加载正在运行的服务/守护进程。这样做是为了使给定的进程/服务/守护进程应用最新的配置更改。

  1. 查看 crond.service 的状态。键入

    [root@localhost ~]# systemctl -n 0 status crond.service
    

    在输出中,记下 crond 的 PID。

  2. 运行 systemctl restart 以重新启动 crond.service。键入

    [root@localhost ~]# systemctl -n 0 status crond.service
    

    该命令应完成而没有任何输出或可见反馈。

  3. 再次检查 crond.service 的状态。将最新的 PID 与您在步骤 1 中记下的 PID 进行比较。

  4. 使用 systemctl 检查 crond.service 当前是否处于活动状态。键入

    [root@localhost ~]# systemctl is-active crond.service
    active
    

    问题

    为什么您认为每次重新启动服务时 PID 都不同?

    提示

    旧式经典服务命令的功能已被移植到系统d 管理的系统上,以无缝工作。您可以使用以下服务命令来停止、启动、重新启动和查看 smartd 服务的状态。

    # service smartd status
    
    # service smartd stop
    
    # service smartd start
    
    # service smartd restart
    

要禁用服务

  1. 使用 systemctl 检查 crond.service 是否已启用以在系统启动时自动启动。键入

    [root@localhost ~]# systemctl is-enabled  crond.service
    
    enabled
    

    示例输出显示它是。

  2. 禁用 crond.service 的自动启动。键入

    [root@localhost ~]# systemctl disable crond.service
    Removed /etc/systemd/system/multi-user.target.wants/crond.service.
    
  3. 再次运行 systemctl is-enabled 命令以查看更改的效果。

    问题

    在您需要远程管理的服务器上,为什么要禁止像 sshd.service 这样的服务在系统启动时自动启动?

要确保禁用(屏蔽)服务

即使 systemctl disable 命令可用于禁用服务,如您在前面的练习中所见,其他 systemd 单元(进程、服务、守护进程等)可以在必要时偷偷地重新启用禁用的服务。当一个服务依赖于另一个(已禁用)服务时,就会发生这种情况。

您应该屏蔽该服务以确保禁用 systemd 服务单元并防止意外重新激活。

  1. 使用 systemctl 屏蔽 crond.service 并防止任何不希望的重新激活,键入

    [root@localhost ~]# systemctl mask crond.service
    
    Created symlink /etc/systemd/system/crond.service  /dev/null.
    
  2. 运行 systemctl is-enabled 命令以查看更改的效果。

    [root@localhost ~]# systemctl is-enabled  crond.service
    
    masked
    
  3. 要撤消更改并取消屏蔽 crond.service,请使用 systemctl unmask 命令,方法是运行

    [root@localhost ~]# systemctl unmask crond.service
    
    Removed /etc/systemd/system/crond.service.
    

要启用服务

  1. 使用 systemctl 检查 crond.service 单元的状态。键入

    [root@localhost ~]# systemctl status crond.service
    

    该服务应仍处于停止状态。

  2. 使用 systemctl enable 命令启用 crond.service 以进行自动启动。键入

    [root@localhost ~]# systemctl enable crond.service
    
    Created symlink /etc/systemd/system/multi-user.target.wants/crond.service  /usr/lib/systemd/system/crond.service.
    
  3. 再次使用 systemctl 检查 crond.service 是否处于活动状态。键入

    [root@localhost ~]# systemctl is-active crond.service
    inactive
    

    问题

    您刚刚启用了 crond.service。为什么它没有运行或在之前的命令中没有列为活动状态?

  4. 使用 systemctl enable 命令的稍微不同的变体来启用 crond.service 并立即启动运行的守护进程。键入

    [root@localhost ~]# systemctl --now enable crond.service
    
  5. 检查 crond.service 是否现在处于活动状态。键入

    [root@localhost ~]# systemctl is-active crond.service
    active
    
  6. 使用 systemctl 确保 crond.service 已启动、正在运行并已启用以进行自动启动。

作者:瓦莱·索因卡

贡献者:史蒂文·斯宾塞、甘娜·日尔诺娃