跳至内容

实验室 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 目标 (运行级别)

systemd 定义并依赖许多不同的目标来管理系统。在此练习中,我们将只关注 5 个主要目标。本节中探索的 5 个主要目标在此列出:

  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 basic.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 “Wants” 的内容。输入:

    [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 “Wants” 的其他服务或资源。

    问题

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

  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 用户身份登录时,列出所有类型为 service 的 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 条 journal 行/条目/日志。

  6. 查看 crond.service 的状态,并抑制显示任何 journal 行。输入:

    [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 status 命令的输出中,crond 的 PID 是多少?

  4. 同样,再次使用 pgrep 查看 crond 进程是否现在出现在进程列表中。比较 pgrep 显示的 PID 与上一个 systemctl status 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 都会不同,这是为什么?

    技巧

    旧的经典 service 命令的功能已被移植到 systemd 管理的系统上,可以无缝工作。您可以使用如下的 service 命令来停止、启动、重启和查看 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 已启动、正在运行并已启用自动启动。

作者:Wale Soyinka

贡献者:Steven Spencer, Ganna Zhyrnova