David Both 发布的文章

几乎所有的事情都可以从 Linux 命令行完成,包括对 Xfce4 进行远程配置。

 title=

与专有操作系统相比,我很欣赏 Linux 的一个特点是,几乎所有的东西都可以从命令行中进行管理和配置。意味着几乎所有的事情都可以在本地或者通过 SSH 远程登录进行管理。虽然有时候需要花费一点时间在互联网上搜索,但是你能想到的任务,是有可能从命令行完成的。

问题

有时候需要使用命令行对桌面进行远程配置。在这种特殊情况下,我需要响应远程用户的请求将在 Xfce 控制板上的工作区从四个减少到三个。这种配置只需要在互联网上搜索约 20 分钟就找到了。

xfwm4 的默认工作区数量和许多其他设置可以在 /usr/share/xfwm4/defaults 这个文件中找到和修改。因此将 workspace_count=2 设置为 workspace_count=4 就改变了主机上所有用户的默认值。同时,非 root 用户可以执行 xfconf-query 命令来查询和设置 xfwm4 窗口管理器的各种属性。它应该由需要改变设置的用户使用,而不是由 root 使用。

在下面的例子中,首先我验证了当前工作区数量为 4 ,然后将数量改为 2,最后确认了新设置。

[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
4
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count -s 2
[user@test1 ~]# xfconf-query -c xfwm4 -p /general/workspace_count
2
[user@test1 ~]#

此更改会立即生效,用户可以马上看到,无需重新启动,甚至无需注销并重新登录。我曾在我的工作站上玩过这个游戏,当我输入设置不同数量的工作空间的命令时,可以观察到工作空间切换器的变化。我在哪儿都能找到乐子。;- )

更多探索

现在我解决了这个问题,我决深入了解一下 xfconf-query 命令。不幸的是,该工具没有手册或信息页,/usr/share 中也没有任何文档。退而求其次,使用 -h 选项获取一些帮助信息。

$ xfconf-query -h
 Usage:
   xfconf-query [OPTION…] - Xfconf commandline utility
 Help Options:
   -h, --help            显示帮助选项
 Application Options:
   -V, --version         版本信息
   -c, --channel         查询/修改通道
   -p, --property        查询/修改属性
   -s, --set             更新权限的值
   -l, --list            罗列属性(或者通道,如果没有用 -c 指定)
   -v, --verbose         详细输出
   -n, --create          当新属性不存在,则创建它
   -t, --type            指定属性值类型
   -r, --reset           重置属性
   -R, --recursive       递归(与 -r 一起使用)
   -a, --force-array     即使只有一个元素也强制采用数组
   -T, --toggle          反转现有的布尔属性
   -m, --monitor         监视属性更改的通道

这没有多大帮助,但我们还是可以从中找出一些有用的东西。首先,通道 是可以修的属性的分组。我对 general 通道下的 workspace_count 属性进行了更改。让我们看看完整的通道列表:

$ xfconf-query -l
Channels:
  xfwm4
  xfce4-keyboard-shortcuts
  xfce4-notifyd
  xsettings
  xfdashboard
  thunar
  parole
  xfce4-panel
  xfce4-appfinder
  xfce4-settings-editor
  xfce4-power-manager
  xfce4-session
  keyboards
  displays
  keyboard-layout
  ristretto
  xfcethemer
  xfce4-desktop
  pointers
  xfce4-settings-manager
  xfce4-mixer

给定通道的属性也可以用下列的命令来查看。我使用 less 分页器,因为结果是一长串数据。我对下面的列表进行了裁剪,但留下了足够多的条目,你可以看到这些条目的类型。

$ xfconf-query -c xfwm4 -l | less
/general/activate_action
/general/borderless_maximize
/general/box_move
/general/box_resize
/general/button_layout
/general/button_offset
<裁剪>
/general/workspace_count
/general/workspace_names
/general/wrap_cycle
/general/wrap_layout
/general/wrap_resistance
/general/wrap_windows
/general/wrap_workspaces
/general/zoom_desktop
(END)

你可以用这种方式探索所有的通道。我发现通道通常对应“设置管理器”中的各种设置。这些属性是你在这些对话框中设置的。请注意,并非你在“设置管理器”对话窗口中找到的所有设置都是 Xfce 桌面的一部分,因此它们没有对应的通道。屏幕保护程序就是一个例子,因为它是通用的 GNU 屏幕保护程序,并不是 Xfce 独有的。“设置管理器” 是 Xfce 定位这些配置工具的一个很好的中心位置。

文档

综上所述,xconf-query 命令似乎没有任何手册或信息页,并且我在网上发现了很多不正确的、记录不全的信息。我发现对 Xfce4 来说最好的文档是 Xfce 网站,关于 xconf-query 的一些具体信息可以在这里找到。


via: https://opensource.com/article/21/1/remote-configuration-xfce4

作者:David Both 选题:lujun9972 译者:Donkey-Hao 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Vim 是我最喜爱的编辑器。对于那些默认使用其他编辑器的程序,我对系统所做的这些改变可以使得 Vim 成为它们默认编辑器。

 title=

我使用 Linux 大概有 25 年了,在那之前我还使用了几年的 Unix。在这段时间里,我对一些日常使用的工具形成了偏好。Vim 是我使用的最重要的工具之一。

我在 90 年代初学习 Solaris 时,就开始使用 Vi 了,因为有人告诉我,它在任何系统上都能使用。从我的经验来看,确实是这样。我也试过其他编辑器,它们都能够胜任工作。但是,对于我来说,Vim 的使用效果最好。我经常使用它,以至于形成了肌肉记忆,甚至我在使用其他编辑器时也会下意识地去按 Vim 的快捷键。

另外,我只是单纯地喜欢 Vim 而已。

许多配置文件使用的名字是 Vi 而不是 Vim,你可以运行 vi 命令。不过,vi 命令其实是 vim 命令的一个链接。

许多 Linux 工具使用的编辑器都是在模拟或是直接调用的 NanoEmacs 或者 Vim。其他的一些工具允许用户(比如那些有着明确偏好的用户)使用他们喜欢的编辑器。举两个对我影响最大的例子,一个是 Bash 命令行,它默认使用 Emacs;另一个是 Alpine 文本模式的邮件客户端,它默认使用 Pico。事实上,Pico 是专门为 Pine 邮件客户端编写的,而 Pine 是 Alpine 的前身。

并非所有使用外部编辑器的程序都是可配置的。有些程序只使用开发者指定的编辑器。对于那些可配置的应用程序,有不同的方法来选择你喜欢的编辑器。

在 Linux 命令行中编辑

除了实际编辑文本文件外,另一个我经常使用,且和编辑密切相关的工具是 Bash shell。Bash 的默认编辑器是 Emacs。虽然我也用过 Emacs,但我肯定更喜欢 Vim。所以很多年前,我把 Bash 命令行的默认编辑器从 Emacs 换成了 Vim,这对我来说更舒服。

有很多种方法可以配置 Bash。你可以使用一个本地配置文件,比如 /home/yourhomedirectory/.bashrc,它只对你的用户账户进行默认修改,而不对同一系统的其他用户进行修改。我个人倾向于让这些改变成为全局性的,基本上就是我的个人账户和 root。如果你也想全局配置,你可以创建你自己的配置文件,并把它放在 /etc/profile.d 目录中。

我在 /etc/profile.d 中添加了一个名为 myBashConfig.sh 的文件。/etc/profile.d 目录中存放了所有已安装的 shell 的启动文件。在启动终端会话时,每个 shell 仅会根据文件名的扩展名,读取为其准备的启动文件。例如,Bash shell 只读取扩展名为 .sh 的文件。

<截断>
alias vim='vim -c "colorscheme desert" '
# 把 vi 设置为 Bash 的默认编辑器
set -o vi
# 为所有检查 $EDITOR 变量的程序设置默认编辑器为 vi
EDITOR=vi
<截断>

在这个全局 Bash 配置文件段中,set -o vi 将 Vi 设置为默认编辑器。这个 set 命令中的 -o 选项将 vi 定义为编辑器。为使配置生效,你需要关闭所有正在运行的 Bash 会话,并打开新的会话。

现在,你现在可以使用所有你熟悉的 Vim 命令,包括光标移动。只要按下 Esc 键就可以进入 Vim 编辑模式。我特别喜欢多次使用 b 将光标移回多个字的功能。

将 Vim 设置为其他程序的默认值

一些 Linux 命令行工具和程序会检查 $EDITOR 环境变量来决定使用哪个编辑器。你可以用下面的命令检查这个变量的当前值。我在一个新安装的虚拟机上运行过该命令,以查看默认的编辑器到底是什么。

# echo $EDITOR
/usr/bin/nano
#

默认情况下,检查 $EDITOR 环境变量的 Fedora 程序会使用 Nano 编辑器。在 myBashConfig.sh 中添加一行 EDITOR=vi(如上面的片段所示),可以将默认值改为 Vi(Vim)编辑器。然而,不是所有使用外部编辑器的命令行程序都会检查这个环境变量。

在 Alpine 中编辑电子邮件

几周前,我认为 Pico 不太适合作为我的电子邮件编辑器。我可以使用它,而且在从 Thunderbird 转到 Alpine 之后的一段时间内我也用了一段时间。但我发现,Pico 妨碍了我,我总是习惯使用 Vim 按键序列,这影响了我的工作效率。

我在 Alpine 的用户帮助中看到,默认编辑器是可以修改的。我决定把它改成 Vim。实际上这很容易做到。

在 Alpine 主菜单上,按 S 键进入设置,然后按 C 键进行配置。在 “ 编辑器设置 Composer Preferences ” 部分,按 X 选择 “ 启用外部编辑器命令 Enable Alternate Editor Command ” 和 “ 隐式启用外部编辑器 Enable Alternate Editor Implicitly ” 项目。在往下滚动几页的 “ 高级用户设置 Advanced User Preferences ” 部分,找到 `Editor 那一行。如果它还没有被修改的话,它应该是这样的:

Editor    = <No Value Set>

用光标栏突出显示 Editor 这一行,然后按回车键来编辑。将 <No Value Set> 改为 vim,再按回车键,然后按 E 键退出,最后按 Y 键保存修改。

要用 Vim 编辑电子邮件,只需进入电子邮件正文,Vim 就会自动启动,就像 Pico 那样。所有我喜欢的编辑功能都还在,因为它实际上是在使用 Vim。甚至退出 Vim 的 Esc :wq 序列也是一样的。

总结

与其他编辑器相比,我更喜欢 Vim,对我的系统进行的这些改动后,那些默认使用其他编辑器的应用程序,将使用 Vim 来替代它们的默认编辑器。有些程序使用 $EDITOR 环境变量,因此你只需要做一次修改就够了。其他有用户配置选项的程序,如 Alpine,则必须为每个程序单独设置。

这种可以选择你喜欢的外部编辑器的能力,非常符合 Unix 哲学的宗旨:“每个程序都只做一件事,而且要做得出色”。既然已经有几个优秀的编辑器,为什么还要再写一个呢?而且它也符合 Linux 哲学的宗旨:“使用你最喜欢的编辑器”。

当然,你可以把你的默认文本编辑器改为 Nano、Pico、Emacs 或任何其他你喜欢的编辑器。


via: https://opensource.com/article/22/2/configure-vim-default-editor

作者:David Both 选题:lujun9972 译者:lkxed 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

用 systemd-analyze 洞悉并解决 Linux 启动性能问题。

 title=

系统管理员的一部分工作就是分析系统性能,发现并解决引起性能不佳、启动时间长的问题。系统管理员也需要去检查 systemd 的配置和使用的其它方面。

systemd 初始化系统提供了 systemd-analyze 工具,可以帮助发现性能问题和其他重要的 systemd 信息。在以前的文章《分析 systemd 日历和时间跨度》里,我用了 systemd-analyze 去分析 systemd 里的时间戳和时间跨度,但是这个工具还有很多其他用法,这个文章里我将再揭示一些。

(LCTT 译注:systemd 是目前主流 Linux 发行版采用的系统管理系统)

(LCTT 译注:为了区分英文的 “boot” 和 “startup” 的不同涵义,此处将 “boot” 翻译为“引导”,“startup” 翻译为“启动”。)

概述启动

Linux 启动过程是值得学习关注的地方,因为 systemd-analyze 工具很多功能聚焦在 启动 startup 过程。但是首先,要理解 引导 boot 启动 startup 。引导阶段从 BIOS 加电自检(POST)开始,结束于内核完成加载并控制主机系统,然后是开始了启动过程,也是 systemd 日志的开始点。

这个系列的第二篇文章《理解 Linux 启动时的 systemd》中,我详细讨论了启动阶段的内容和过程。在这篇文章里,我想研究一下启动过程,看看需要多少时间和大部分时间花费在哪里。

下面我将展示的结果来自我的主要工作站,这比虚拟机的结果要有趣得多。这个工作站包括一块 华硕 TUF X299 Mark 2 主板、一个英特尔 i9-7960X CPU(16 核 32 线程),64 G 内存。下面的一些命令非 root 用户也可以使用,但是我在这篇文章里使用了 root 用户,以避免在用户之间切换。

检查启动过程有几种方法,最简单的 systemd-analyze 命令显示了启动的几个主要部分耗费的时间,包括内核启动、装载运行 initrd(即初始 ramdisk,这是一个用来初始化一些硬件、挂载 / 根文件系统的临时系统镜像),还有用户空间(加载所有使主机达到可用状态的程序和守护程序)。如果没有像该命令传递子命令,默认是 systemd-analyze time

[root@david ~]$ systemd-analyze
Startup finished in 53.921s (firmware) + 2.643s (loader) + 2.236s (kernel) + 4.348s (initrd) + 10.082s (userspace) = 1min 13.233s
graphical.target reached after 10.071s in userspace
[root@david ~]#

这个输出中最值得注意的数据是在固件(BIOS)中花费的时间:几乎 54 秒。这是一个不太正常的时间,我的其他物理系统都没有花费这么长的时间来通过 BIOS。

我的 System76 Oryx Pro 笔记本在 BIOS 阶段只花了 8.506 秒,我家里所有的系统都在 10 秒以内。在线搜索一阵之后,我发现这块主板以其超长的 BIOS 引导时间而闻名。我的主板从不“马上启动”,总是挂起,我需要关机再开机,BIOS 报错,按 F1 进入 BIOS 设置,选择要引导的驱动器完成引导,多花费的时间就是这样用掉的。

不是所有主机都会显示固件数据(LCTT 译注:固件引导中不涉及 systemd)。我的不科学的实验使我相信,这个数据只显示给英特尔 9 代或以上的处理器。但这可能是不正确的。

这个关于引导、启动的概述提供了很好的(虽然有限)的信息,但是还有很多关于启动的信息,我将在下面描述。

分配责任

你可以用 systemd-analyze blame 来发现哪个 systemd 单元的初始化时间最长。其结果按照初始化时间长短排序,从多到少:

[root@david ~]$ systemd-analyze blame  
       5.417s NetworkManager-wait-online.service
       3.423s dracut-initqueue.service
       2.715s systemd-udev-settle.service
       2.519s fstrim.service
       1.275s udisks2.service
       1.271s smartd.service
        996ms upower.service
        637ms lvm2-monitor.service
        533ms lvm2-pvscan@8:17.service
        520ms dmraid-activation.service
        460ms vboxdrv.service
        396ms initrd-switch-root.service
<截断:删去了好多时间不长的条目>

因为很多服务是并行开始的,在 BIOS 之后所有单元加在一起的总数大大超过了 systemd-analyze time 汇总数。很多都是小数,不能显著的节省时间。

这个命令提供的数据指明了改善启动时间的办法。无用的服务可以禁用(disable)。在这个启动过程中,似乎没有任何一个服务需要花费过长的时间。你可能会在每次启动时看到不同的结果。(LCTT 译注:并行启动服务的原因)

关键链

就像项目管理中的关键路径一样,关键链显示了在启动过程中发生的时间关键的事件链(LCTT 译注:systemd 可以定义服务间的依赖,构成关键链)。如果启动缓慢,这些是你想查看的 systemd 单元,因为它们是导致延迟的单元。这个工具不会显示所有启动的单元,只显示这个关键事件链中的单元。(LCTT 译注:相当于最短路径。并不显示依赖不在关键链上的服务单元)

[root@david ~]# systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.

graphical.target @10.071s
└─lxdm.service @10.071s
  └─plymouth-quit.service @10.047s +22ms
    └─systemd-user-sessions.service @10.031s +7ms
      └─remote-fs.target @10.026s
        └─remote-fs-pre.target @10.025s
          └─nfs-client.target @4.636s
            └─gssproxy.service @4.607s +28ms
              └─network.target @4.604s
                └─NetworkManager.service @4.383s +219ms
                  └─dbus-broker.service @4.434s +136ms
                    └─dbus.socket @4.369s
                      └─sysinit.target @4.354s
                        └─systemd-update-utmp.service @4.345s +9ms
                          └─auditd.service @4.301s +42ms
                            └─systemd-tmpfiles-setup.service @4.254s +42ms
                              └─import-state.service @4.233s +19ms
                                └─local-fs.target @4.229s
                                  └─Virtual.mount @4.019s +209ms
                                    └─systemd-fsck@dev-mapper-vg_david2\x2dVirtual.service @3.742s +274ms
                                      └─local-fs-pre.target @3.726s
                                        └─lvm2-monitor.service @356ms +637ms
                                          └─dm-event.socket @319ms
                                            └─-.mount
                                              └─system.slice
                                                └─-.slice
[root@david ~]#

前面有 @ 的数字表示单元激活开始启动所使用的绝对秒数。前面有 + 的数字显示单元启动所需的时间。

系统状态

有时候你需要确定系统的当前状态,systemd-analyze dump 命令转储了当前系统状态的大量数据。有主要的启动时间戳,一个每个 systemd 单元的列表,并对每个单元状态进行了完整描述:

[root@david ~]# systemd-analyze dump
Timestamp firmware: 1min 7.983523s
Timestamp loader: 3.872325s
Timestamp kernel: Wed 2020-08-26 12:33:35 EDT
Timestamp initrd: Wed 2020-08-26 12:33:38 EDT
Timestamp userspace: Wed 2020-08-26 12:33:42 EDT
Timestamp finish: Wed 2020-08-26 16:33:56 EDT
Timestamp security-start: Wed 2020-08-26 12:33:42 EDT
Timestamp security-finish: Wed 2020-08-26 12:33:42 EDT
Timestamp generators-start: Wed 2020-08-26 16:33:42 EDT
Timestamp generators-finish: Wed 2020-08-26 16:33:43 EDT
Timestamp units-load-start: Wed 2020-08-26 16:33:43 EDT
Timestamp units-load-finish: Wed 2020-08-26 16:33:43 EDT
Timestamp initrd-security-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-security-finish: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-generators-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-generators-finish: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-units-load-start: Wed 2020-08-26 12:33:38 EDT
Timestamp initrd-units-load-finish: Wed 2020-08-26 12:33:38 EDT
-> Unit system.slice:
        Description: System Slice
        Instance: n/a
        Unit Load State: loaded
        Unit Active State: active
        State Change Timestamp: Wed 2020-08-26 12:33:38 EDT
        Inactive Exit Timestamp: Wed 2020-08-26 12:33:38 EDT
        Active Enter Timestamp: Wed 2020-08-26 12:33:38 EDT
        Active Exit Timestamp: n/a
        Inactive Enter Timestamp: n/a
        May GC: no
<截断:删除了大量的输出行>

在我的主工作站上,这个命令生成了 49680 行输出,大概 1.66MB,这个命令非常快,不需要等待。

我很喜欢为各种连接设备(如存储设备)提供的大量细节。每个 systemd 单元有一个部分,包括各种运行时、缓存、日志目录的模式、启动单元的命令行、PID、开始时间戳,以及内存和文件限制等细节。

systemd-analyze 的手册页里展示了 systemd-analyze --user dump 选项,目的是显示用户管理器的内部状态。但这个选项对我来说是失败的,互联网搜索之后表明它可能有一些问题。在 systemd 里,--user 实例用来管理和控制处理器给每个用户的进程资源。处理能力按分给每个用户的进程都属于一个控制组,我将在以后的文章中介绍。

分析图表

大多数啥都不懂的猥琐老板(PHB)和许多优秀的管理者都发现漂亮的图表比我通常喜欢的基于文本的系统性能数据更容易阅读和理解。但有时,即使是我也喜欢一个好的图表,systemd-analyze 提供了显示引导/启动数据的 SVG 矢量图表。

下面的命令生成一个矢量图文件,来显示在引导和启动过程发生的事件。生成这个文件只需要几秒:

[root@david ~]# systemd-analyze plot > /tmp/bootup.svg

这个命令创建了一个 SVG 文件,SVG 是一个定义了一系列图形矢量的文本文件,包括 Image Viewer、Ristretto、Okular、Eye of Mate、LibreOffice Draw 在内的这些可以生成图形的应用,可以用 SVG 来创建图像。

我用 LibreOffice Draw(LCTT 译注:一个办公文档软件)来渲染一幅图形。这张图形很大,你需要放到很大才能看清细节。这里是它的一小部分:

 title=

图中时间轴上零点(0)的左边是引导阶段,零点的右边是启动阶段。这一小部分显示了内核、initrd 和 initrd 启动的进程。

这张图一目了然地显示了什么时候启动,启动需要多少时间,以及主要的依赖项。关键路径用红色高亮显示。

另外一个生成图形输出的命令是 systemd-analyze plot,它生成了 DOT) 格式的文本依赖图。产生的数据流通过 dot 工具进行处理,这是一组用来从多种类型数据中生成矢量图文件的程序。这些 SVG 文件也能被上面列出的工具处理。

首先,生成文件,在我的主工作站花了 9 分钟:

[root@david ~]# time systemd-analyze dot | dot -Tsvg > /tmp/test.svg
   Color legend: black     = Requires
                 dark blue = Requisite
                 dark grey = Wants
                 red       = Conflicts
                 green     = After

real    8m37.544s
user    8m35.375s
sys     0m0.070s
[root@david ~]#

我不会在这里重现输出,因为产生的图形就像一大堆意大利面条。但是你应该试试,看看我想让你看到的结果。

条件

在阅读 systemd-analyze(1) 的手册页时,我发现了一个更有趣的功能,但又有点通用,就是条件子命令。(是的,我确实在读手册页,而且我神奇地通过这种方式学到了很多东西!)。这个 condition 子命令能用来测试 systemd 单元文件中的条件和断言。

它也可以在脚本中用来评估一个或多个条件 —— 如果所有条件都满足,则返回 0;如果有条件不满足,则返回 1。在其它情况下,它都会输出其结果文本。

下面的例子来自手册页,稍微有点复杂。它测试了内核版本是否在 4.0 和 5.1 之间,主机是否使用交流电供电,系统结构是否是 ARM,以及 /etc/os-release 目录是否存在。我添加了 echo $? 来打印返回值。

[root@david ~]# systemd-analyze condition 'ConditionKernelVersion = ! <4.0' \
                    'ConditionKernelVersion = >=5.1' \
                    'ConditionACPower=|false' \
                    'ConditionArchitecture=|!arm' \
                    'AssertPathExists=/etc/os-release' ; \
echo $?
test.service: AssertPathExists=/etc/os-release succeeded.
Asserts succeeded.
test.service: ConditionArchitecture=|!arm succeeded.
test.service: ConditionACPower=|false failed.
test.service: ConditionKernelVersion=>=5.1 succeeded.
test.service: ConditionKernelVersion=!<4.0 succeeded.
Conditions succeeded.
0
[root@david ~]#

条件和断言的列表大约从 systemd.unit(5) 手册页的第 600 行左右开始。

列出配置文件

systemd-analyze 工具提供了一种将各种配置文件的内容发送到 STDOUT 的方法,如图所示。其基本目录是 /etc/

[root@david ~]# systemd-analyze cat-config systemd/system/display-manager.service
# /etc/systemd/system/display-manager.service
[Unit]
Description=LXDM (Lightweight X11 Display Manager)
#Documentation=man:lxdm(8)
[email protected]
After=systemd-user-sessions.service [email protected] plymouth-quit.service livesys-late.service
#Conflicts=plymouth-quit.service

[Service]
ExecStart=/usr/sbin/lxdm
Restart=always
IgnoreSIGPIPE=no
#BusName=org.freedesktop.lxdm

[Install]
Alias=display-manager.service
[root@david ~]#

打了这么多字却和标准的 cat 命令做的差不多。我发现下一条命令小有帮助,它能在标准的 systemd 所在的位置搜索具有指定模式的内容:

[root@david ~]# systemctl cat backup*
# /etc/systemd/system/backup.timer
# This timer unit runs the local backup program
# (C) David Both
# Licensed under GPL V2
#

[Unit]
Description=Perform system backups
Requires=backup.service

[Timer]
Unit=backup.service
OnCalendar=*-*-* 00:15:30

[Install]
WantedBy=timers.target


# /etc/systemd/system/backup.service
# This service unit runs the rsbu backup program
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=Backup services using rsbu
Wants=backup.timer

[Service]
Type=oneshot
Environment="HOME=/root"
ExecStart=/usr/local/bin/rsbu -bvd1
ExecStart=/usr/local/bin/rsbu -buvd2

[Install]
WantedBy=multi-user.target

[root@david ~]#

这两个命令在每个文件的内容前面都有一个注释行,包含文件的完整路径和名称。

单元文件检查

当创建了一个新的单元文件,可以利用 verify 子命令帮助检查语法是否正确。它能指出来不正确的拼写,并列出缺失的服务单元。

[root@david ~]# systemd-analyze verify /etc/systemd/system/backup.service

秉承 Unix/Linux 的“沉默是金”的宗旨,没有输出意味着扫描的文件中没有错误。

安全性

security 子命令检查指定服务的安全级别。它只能针对服务单元,其他类型的单元文件不起作用:

[root@david ~]# systemd-analyze security display-manager
  NAME                                                        DESCRIPTION                                                     >
✗ PrivateNetwork=                                             Service has access to the host's network                        >
✗ User=/DynamicUser=                                          Service runs as root user                                       >
✗ CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)                Service may change UID/GID identities/capabilities              >
✗ CapabilityBoundingSet=~CAP_SYS_ADMIN                        Service has administrator privileges                            >
✗ CapabilityBoundingSet=~CAP_SYS_PTRACE                       Service has ptrace() debugging abilities                        >
✗ RestrictAddressFamilies=~AF_(INET|INET6)                    Service may allocate Internet sockets                           >
✗ RestrictNamespaces=~CLONE_NEWUSER                           Service may create user namespaces                              >
✗ RestrictAddressFamilies=~…                                  Service may allocate exotic sockets                             >
✗ CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)           Service may change file ownership/access mode/capabilities unres>
✗ CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)         Service may override UNIX file/IPC permission checks            >
✗ CapabilityBoundingSet=~CAP_NET_ADMIN                        Service has network configuration privileges                    >
✗ CapabilityBoundingSet=~CAP_SYS_MODULE                       Service may load kernel modules
<截断>
✗ CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG                   Service may issue vhangup()                                     >
✗ CapabilityBoundingSet=~CAP_WAKE_ALARM                       Service may program timers that wake up the system              >
✗ RestrictAddressFamilies=~AF_UNIX                            Service may allocate local sockets                              >

→ Overall exposure level for backup.service: 9.6 UNSAFE ?
lines 34-81/81 (END)

是的,表情符是输出的一部分。但是,当然,许多服务需要几乎完全访问所有的东西,以便完成它们的工作。我针对几个服务运行了这个程序,包括我自己的备份服务;结果可能有所不同,但最底下一行似乎大多是一样的。

这个工具对于在严格的安全环境检查和修复用户空间的服务单元是很有用的。我不认为我们的大多数都能用到它。

最后总结

这个强力的工具提供了一些有趣而惊人的有用选项。本文探讨的大部分内容是关于使用 systemd-analyze 来深入了解 Linux 使用 systemd 的启动性能。它还可以分析 systemd 的其他方面。

其中有些工具的作用有限,有几个应该完全忘记。但在解决启动和其他 systemd 功能的问题时,大多数都能起到很好的作用。

资源

互联网上关于 systemd 有很多信息,但是很多过于简略、晦涩,甚至是误导。除了这篇文章中提到的资源外,以下网页提供了关于systemd启动的更详细和可靠的信息。这个列表在我开始写这一系列文章后有所增长,以反映我所做的研究。

  • systemd.unit(5) 手册页 包含了一份单元文件部分及其配置选项的清单,并对每个部分进行了简明的描述。
  • Fedora 项目有一个很好的实用 systemd 指南。它包含了配置、管理和维护使用 systemd 的 Fedora 计算机所需的几乎所有知识。
  • Fedora 项目还有一份很好的 备忘录,将旧的 SystemV 命令与 systemd 命令进行了对照。
  • Red Hat 文档包含了对 单元文件结构 的详细描述和其他重要的信息。
  • 关于 systemd 技术的细节和创建它的原因,可以去看 Freedesktop.org systemd 详述
  • Linux.com 的“更多 systemd 乐趣”提供了很多高级的 systemd 信息和技巧

此外,systemd 设计者和主要开发者 Lennart Poettering 也为 Linux 系统管理员撰写了一系列深度技术文档,尽管这些文章写于 2010 年 4 月到 2011 年 9 月,现在看也是非常适应时宜。关于 systemd 及其生态系统的其他好文章,大部分都是基于这些文章的。


via: https://opensource.com/article/20/9/systemd-startup-configuration

作者:David Both 选题:lujun9972 译者:jiamn 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

使用这个简单的方法来迁移一个网站以及管理防火墙配置。

 title=

你有过把一个 WordPress 网站迁移到一台新主机上的需求吗?我曾经迁移过好多次,迁移过程相当简单。当然,的的市场时候我都不会用通用的推荐方法,这次也不例外 —— 我用更简单的方法,这才是我推荐的方法。

这个迁移方法没有破坏性,因此如果出于某些原因你需要还原到原来的服务器上,很容易可以实现。

一个 WordPress 网站的组成部分

运行一个基于 WordPress 的网站有三个重要组成部分:WordPress 本身,一个 web 服务器,如 Apache(我正在用),以及 MariaDB。MariaDB 是 MySQL 的一个分支,功能相似。

业界有大量的 Web 服务器,由于我使用了 Apache 很长时间,因此我推荐用 Apache。你可能需要把 Apache 的配置方法改成你用的 Web 服务器的方法。

初始配置

我使用一台 Linux 主机作为防火墙和网络路由。在我的网络中 Web 服务器是另一台主机。我的内部网络使用的是 C 类私有网络地址范围,按 无类别域间路由 Classless Internet Domain Routing (CIDR)方式简单地记作 192.168.0.0/24。

对于防火墙,相比于更复杂的 firewalld,我更喜欢用非常简单的 IPTables。这份防火墙配置中的一行会把 80 端口(HTTP)接收到的包发送给 Web 服务器。在 /etc/sysconfig/iptables 文件中,你可以在注释中看到,我添加了规则,把其他入站服务器连接转发到同一台服务器上合适的端口。

# Reroute ports for inbound connections to the appropriate web/email/etc server.
# HTTPD goes to 192.168.0.75
-A PREROUTING -d 45.20.209.41/255.255.255.248 -p tcp -m tcp --dport 80 \

  -j DNAT --to-destination 192.168.0.75:80

我使用 命名虚拟主机 named virtual host 来配置原来的 Apache Web 服务器,因为我在这个 HTTPD 实例上运行着多个网站。使用命名虚拟主机配置是个不错的方法,因为(像我一样)未来你可能会在运行其他的网站,这个方法可以使其变得容易。

/etc/httpd/conf/httpd.conf 中需要迁移的虚拟主机的网站相关部分请参考下面代码。这个片段中不涉及到 IP 地址的修改,因此在新服务器上使用时不需要修改。

<VirtualHost *:80>
   ServerName www.website1.org
   ServerAlias server.org

DocumentRoot "/var/website1/html"
   ErrorLog "logs/error_log"
   ServerAdmin [email protected]
 
<Directory "/var/website1/html">
      Options Indexes FollowSymLinks
 
AllowOverride None
      Require all granted
 
</Directory>
</VirtualHost>

在迁移之前,你需要在 httpd.conf 的最顶端附近找到 Listen 声明并修改成类似下面这样。这个地址是服务器的真实私有 IP 地址,不是公开 IP 地址。

Listen 192.168.0.75:80

你需要修改新主机上 Listen 的 IP 地址。

前期工作

准备工作分为以下三步:

  • 安装服务
  • 配置防火墙
  • 配置 web 服务器

安装 Apache 和 MariaDB

如果你的新服务器上还没有 Apache 和 MariaDB,那么就安装它们。WordPress 的安装不是必要的。

dnf -y install httpd mariadb

新服务器防火墙配置

确认下新服务器上的防火墙允许访问 80 端口。你\_每台\_电脑上都有一个防火墙,对吗?大部分现代发行版使用的初始化配置包含的防火墙会阻止所有进来的网络流量,以此来提高安全等级。

下面片段的第一行内容可能已经在你的 IPTables 或其他基于防火墙的网络过滤器中存在了。它标识已经被识别为来自可接受来源的入站包,并绕过后面的其它 INPUT 过滤规则,这样可以节省时间和 CPU 周期。片段中最后一行标识并放行 80 端口新进来的请求到 HTTPD 的连接。

-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
<删节>
# HTTP
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

下面的示例 /etc/sysconfig/iptables 文件是 IPTables 最少规则的例子,可以允许 SSH(端口 22)和 HTTPD(端口 80)连接。

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
# SSHD
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
# HTTP
-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT

# Final disposition for unmatched packets
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

在新服务器主机上我需要做的就是在 /etc/sysconfig/iptables 文件的防火墙规则里添加上面片段的最后一行,然后重新加载修改后的规则集。

iptables-restore /etc/sysconfig/iptables

大部分基于红帽的发行版本,如 Fedora,使用的是 firewalld。我发现对于它的适用场景(如家用、小到中型企业)而言,它过于复杂,因此我不用它。我建议你参照 firewalld 网页 来向 firewalld 添加入站端口 80。

你的防火墙及其配置可能跟这个有些差异,但最终的目的是允许新 Web 服务器 80 端口接收 HTTPD 连接。

HTTPD 配置

/etc/httpd/conf/httpd.conf 文件中配置 HTTPD。像下面一样在 Listen 片段中设置 IP 地址。我的新 Web 服务器 IP 地址是 192.168.0.125

Listen 192.168.0.125:80

复制(对应要迁移的网站的) VirtualHost 片段,粘贴到新服务器上 httpd.conf 文件的末尾。

迁移过程

只有两组数据需要迁移到新服务器 —— 数据库本身和网站目录结构。把两个目录打包成 tar 文档。

cd /var ; tar -cvf /tmp/website.tar website1/
cd /var/lib ; tar -cvf /tmp/database.tar mysql/

把两个 tar 文件复制到新服务器。我通常会把这类文件放到 /tmp 下,这个目录就是用来做这种事的。在新服务器上运行下面的命令,把 tar 文档解压到正确的目录。

cd /var ; tar -xvf /tmp/website.tar
cd /var/lib ; tar -xvf /tmp/database.tar

WordPress 的所有文件都在 /var/website1 下,因此不需要在新服务器上安装它。新服务器上不需要执行 WordPress 安装过程。

这个目录就是需要迁移到新服务器上的全部内容。

最后一步是启动(或重启)mysqldhttpd 服务守护进程。WrodPress 不是一个服务,因此不使用守护进程的方式来启动。

systemctl start mysqld ; systemctl start httpd

启动之后,你应该检查下这些服务的状态。

systemctl status mysqld
● mariadb.service - MariaDB 10.5 database server
    Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)
    Active: active (running) since Sat 2021-08-21 14:03:44 EDT; 4 days ago
        Docs: man:mariadbd(8)

https://mariadb.com/kb/en/library/systemd/
   Process: 251783 ExecStartPre=/usr/libexec/mariadb-check-socket (code=exited, status=0/SUCCESS)
   Process: 251805 ExecStartPre=/usr/libexec/mariadb-prepare-db-dir mariadb.service (code=exited, status=0/SUCCESS)
   Process: 251856 ExecStartPost=/usr/libexec/mariadb-check-upgrade (code=exited, status=0/SUCCESS)
 Main PID: 251841 (mariadbd)
      Status: "Taking your SQL requests now..."
      Tasks: 15 (limit: 19003)
    Memory: 131.8M
        CPU: 1min 31.793s
    CGroup: /system.slice/mariadb.service
└─251841 /usr/libexec/mariadbd --basedir=/usr

Aug 21 14:03:43 simba.stmarks-ral.org systemd[1]: Starting MariaDB 10.5 database server...
Aug 21 14:03:43 simba.stmarks-ral.org mariadb-prepare-db-dir[251805]: Database MariaDB is probably initialized in /var/lib/mysql already, n>
Aug 21 14:03:43 simba.stmarks-ral.org mariadb-prepare-db-dir[251805]: If this is not the case, make sure the /var/lib/mysql is empty before>
Aug 21 14:03:44 simba.stmarks-ral.org mariadbd[251841]: 2021-08-21 14:03:44 0 [Note] /usr/libexec/mariadbd (mysqld 10.5.11-MariaDB) startin>
Aug 21 14:03:44 simba.stmarks-ral.org systemd[1]: Started MariaDB 10.5 database server.

systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Drop-In: /usr/lib/systemd/system/httpd.service.d
└─php-fpm.conf
      Active: active (running) since Sat 2021-08-21 14:08:39 EDT; 4 days ago
        Docs: man:httpd.service(8)
   Main PID: 252458 (httpd)
      Status: "Total requests: 10340; Idle/Busy workers 100/0;Requests/sec: 0.0294; Bytes served/sec: 616 B/sec"
        Tasks: 278 (limit: 19003)
      Memory: 44.7M
        CPU: 2min 31.603s
   CGroup: /system.slice/httpd.service
├─252458 /usr/sbin/httpd -DFOREGROUND
├─252459 /usr/sbin/httpd -DFOREGROUND
├─252460 /usr/sbin/httpd -DFOREGROUND
├─252461 /usr/sbin/httpd -DFOREGROUND
├─252462 /usr/sbin/httpd -DFOREGROUND
└─252676 /usr/sbin/httpd -DFOREGROUND

Aug 21 14:08:39 simba.stmarks-ral.org systemd[1]: Starting The Apache HTTP Server...
Aug 21 14:08:39 simba.stmarks-ral.org httpd[252458]: AH00112: Warning: DocumentRoot [/var/teststmarks-ral/html] does not exist
Aug 21 14:08:39 simba.stmarks-ral.org httpd[252458]: Server configured, listening on: port 80
Aug 21 14:08:39 simba.stmarks-ral.org systemd[1]: Started The Apache HTTP Server.

最终的修改

现在所需的服务都已经运行了,你可以把 /etc/sysconfig/iptables 文件中 HTTDP 的防火墙规则改成下面的样子:

-A PREROUTING -d 45.20.209.41/255.255.255.248 -p tcp -m tcp --dport 80 \
  -j DNAT --to-destination 192.168.0.125:80

然后重新加载设置的 IPTables 规则。

iptables-restore /etc/sysconfig/iptables

由于防火墙规则是在防火墙主机上,因此不需要把外部 DNS 入口改成指向新服务器。如果你使用的是内部 DNS 服务器,那么你需要把 IP 地址改成内部 DNS 数据库里的 A 记录。如果你没有用内部 DNS 服务器,那么请确保主机 /etc/hosts 文件里新服务器地址设置得没有问题。

测试和清理

请确保对新配置进行测试。首先,停止旧服务器上的 mysqldhttpd 服务。然后通过浏览器访问网站。如果一切符合预期,那么你可以关掉旧服务器上的 mysqldhttpd。如果有失败,你可以把 IPTables 的路由规则改回去到旧服务器上,直到问题解决。

之后我把 MySQL 和 HTTPD 从旧服务器上删除了,这样来确保它们不会意外地被启动。

总结

就是这么简单。不需要执行数据库导出和导入的过程,因为 mysql 目录下所有需要的东西都已经复制过去了。需要执行导出/导入过程的场景是:有网站自己的数据库之外的数据库;MariaDB 实例上还有其他网站,而你不想把这些网站复制到新服务器上。

迁移旧服务器上的其他网站也很容易。其他网站依赖的所有数据库都已经随着 MariaDB 的迁移被转移到了新服务器上。你只需要把 /var/website 目录迁移到新服务器,添加合适的虚拟主机片段,然后重启 HTTPD。

我遵循这个过程把很多个网站从一个服务器迁移到另一个服务器,每次都没有问题。


via: https://opensource.com/article/21/9/migrate-wordpress

作者:David Both 选题:lujun9972 译者:lxbwolf 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

控制组可以按照应用管理资源,而不是按照组成应用的单个进程。

 title=

作为一个系统管理员,没有事情比意外地耗尽计算资源让我更觉得沮丧。我曾不止一次填满了一个分区的所有可用磁盘空间、耗尽内存、以及没有足够的 CPU 时间在合理的时间内处理我的任务。资源管理是系统管理员最重要的工作之一。

资源管理的关键是保证所有的进程能够相对公平的访问需要的系统资源。资源管理还包括确保在需要时添加内存、硬盘驱动器空间、还有 CPU 处理能力;或者在无法添加时限制资源的使用。此外,应该阻止独占系统资源的用户,无论其是否有意。

系统管理员可以通过一些工具监控和管理不同的系统资源。例如,top) 和类似的工具允许你监控内存、I/O、存储(磁盘、SSD 等)、网络、交换空间、CPU 的用量等。这些工具,尤其是那些以 CPU 为中心的工具,大部分基于以运行的进程为基本单位进行控制的模型。它们最多只是提供了一种方式来调整 nice 数字,从而修改优先级,或者杀死一个运行的进程。(要了解 nice 数字的信息,查看 使用 Glances 监控 Linux 和 Windows 主机)。

SystemV 环境中基于传统的资源管理的其他工具,由 /etc/security/limits.conf 文件和 /etc/security/limits.d 中的本地配置文件控制。资源可以按照用户或组以一种相对粗糙但实用的方式限制。可以管理的资源包括内存的各个方面、每日的总 CPU 时间、数据总量、优先级、nice 数字、并发登录的数量、进程数、文件大小的最大值等。

使用控制组管理进程

systemd 和 SystemV 之间的一个主要差异是管理进程的方式。SystemV 将每个进程视作一个独立的实体。systemd 将相关的进程集中到一个控制组,简写做 cgroup,并将控制组作为一个整体管理系统资源。这意味着资源能够基于应用管理,而不是由组成应用的各个进程来管理。

控制组的控制单元称作 切片单元 slice unit 。切片是允许 systemd 以树状格式控制程序次序,从而简化管理的概念化。

查看控制组

我将从一些允许你查看不同类型控制组信息的命令开始。 systemctl status <service> 命令显示一个特定服务的切片信息,包括服务的切片。这个例子展示了 at 守护进程:

[root@testvm1 ~]# systemctl status atd.service
● atd.service - Deferred execution scheduler
     Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2020-09-23 12:18:24 EDT; 1 day 3h ago
       Docs: man:atd(8)
   Main PID: 1010 (atd)
      Tasks: 1 (limit: 14760)
     Memory: 440.0K
        CPU: 5ms
     CGroup: /system.slice/atd.service
             └─1010 /usr/sbin/atd -f

Sep 23 12:18:24 testvm1.both.org systemd[1]: Started Deferred execution scheduler.
[root@testvm1 ~]#

这是一个我感到 systemd 比 SystemV 和旧的初始化程序更好用的原因的绝佳示例。这里的信息远比 SystemV 能够提供的丰富。CGroup 项包括的层级结构中,system.slice 是 systemd(PID 1),atd.service 在下一层,是 system.slice 的一部分。CGroup 项的第二行还显示了进程 ID(PID)和启动守护进程使用的命令。

systemctl 命令可以列出多个控制组项,--all 参数列出所有的切片,包括当前没有激活的切片:

[root@testvm1 ~]# systemctl -t slice --all
  UNIT                             LOAD   ACTIVE   SUB    DESCRIPTION                    
  -.slice                          loaded active   active Root Slice                      
  system-getty.slice               loaded active   active system-getty.slice              
  system-lvm2\x2dpvscan.slice      loaded active   active system-lvm2\x2dpvscan.slice    
  system-modprobe.slice            loaded active   active system-modprobe.slice          
  system-sshd\x2dkeygen.slice      loaded active   active system-sshd\x2dkeygen.slice    
  system-systemd\x2dcoredump.slice loaded inactive dead   system-systemd\x2dcoredump.slice
  system-systemd\x2dfsck.slice     loaded active   active system-systemd\x2dfsck.slice    
  system.slice                     loaded active   active System Slice                    
  user-0.slice                     loaded active   active User Slice of UID 0            
  user-1000.slice                  loaded active   active User Slice of UID 1000          
  user.slice                       loaded active   active User and Session Slice          

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.

11 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
[root@testvm1 ~]#

关于这个数据,第一个需要注意的是数据显示了 UID 0(root)和 UID 1000 的用户切片,UID 1000 是我登录的用户。这里列出了组成每个切片的切片部分,而不是服务。还说明了每个用户登录时都会为其创建一个切片,这为将一个用户的所有任务作为单个控制组项进行管理提供了一种方式。

探索控制组的层次结构

目前为止一切顺利,但是控制组是分层的,所有的服务单元作为其中一个控制组的成员运行。要查看这个层次结构很简单,使用一个旧命令和 systemd 的一个新命令即可。

ps 命令可以用于映射进程的和其所处的控制组层次。注意使用 ps 命令时需要指明想要的数据列。我大幅削减了下面命令的输出数量,但是试图保留足够的数据,以便你能够对自己系统上的输出有所感受:

[root@testvm1 ~]# ps xawf -eo pid,user,cgroup,args
    PID USER     CGROUP                      COMMAND
      2 root     -                           [kthreadd]
      3 root     -                            \_ [rcu_gp]
      4 root     -                            \_ [rcu_par_gp]
      6 root     -                            \_ [kworker/0:0H-kblockd]
      9 root     -                            \_ [mm_percpu_wq]
     10 root     -                            \_ [ksoftirqd/0]
     11 root     -                            \_ [rcu_sched]
     12 root     -                            \_ [migration/0]
     13 root     -                            \_ [cpuhp/0]
     14 root     -                            \_ [cpuhp/1]
<删节>
 625406 root     -                            \_ [kworker/3:0-ata_sff]
 625409 root     -                            \_ [kworker/u8:0-events_unbound]
      1 root     0::/init.scope              /usr/lib/systemd/systemd --switched-root --system --deserialize 30
    588 root     0::/system.slice/systemd-jo /usr/lib/systemd/systemd-journald
    599 root     0::/system.slice/systemd-ud /usr/lib/systemd/systemd-udevd
    741 root     0::/system.slice/auditd.ser /sbin/auditd
    743 root     0::/system.slice/auditd.ser  \_ /usr/sbin/sedispatch
    764 root     0::/system.slice/ModemManag /usr/sbin/ModemManager
    765 root     0::/system.slice/NetworkMan /usr/sbin/NetworkManager --no-daemon
    767 root     0::/system.slice/irqbalance /usr/sbin/irqbalance --foreground
    779 root     0::/system.slice/mcelog.ser /usr/sbin/mcelog --ignorenodev --daemon --foreground
    781 root     0::/system.slice/rngd.servi /sbin/rngd -f
    782 root     0::/system.slice/rsyslog.se /usr/sbin/rsyslogd -n
<删节>
    893 root     0::/system.slice/sshd.servi sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
   1130 root     0::/user.slice/user-0.slice  \_ sshd: root [priv]
   1147 root     0::/user.slice/user-0.slice  |   \_ sshd: root@pts/0
   1148 root     0::/user.slice/user-0.slice  |       \_ -bash
   1321 root     0::/user.slice/user-0.slice  |           \_ screen
   1322 root     0::/user.slice/user-0.slice  |               \_ SCREEN
   1323 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 498801 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.resource-control
 498813 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1351 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 123293 root     0::/user.slice/user-0.slice  |                   |   \_ man systemd.slice
 123305 root     0::/user.slice/user-0.slice  |                   |       \_ less
   1380 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625412 root     0::/user.slice/user-0.slice  |                   |   \_ ps xawf -eo pid,user,cgroup,args
 625413 root     0::/user.slice/user-0.slice  |                   |   \_ less
 246795 root     0::/user.slice/user-0.slice  |                   \_ /bin/bash
 625338 root     0::/user.slice/user-0.slice  |                       \_ /usr/bin/mc -P /var/tmp/mc-root/mc.pwd.246795
 625340 root     0::/user.slice/user-0.slice  |                           \_ bash -rcfile .bashrc
   1218 root     0::/user.slice/user-1000.sl  \_ sshd: dboth [priv]
   1233 dboth    0::/user.slice/user-1000.sl      \_ sshd: dboth@pts/1
   1235 dboth    0::/user.slice/user-1000.sl          \_ -bash
<删节>
   1010 root     0::/system.slice/atd.servic /usr/sbin/atd -f
   1011 root     0::/system.slice/crond.serv /usr/sbin/crond -n
   1098 root     0::/system.slice/lxdm.servi /usr/sbin/lxdm-binary
   1106 root     0::/system.slice/lxdm.servi  \_ /usr/libexec/Xorg -background none :0 vt01 -nolisten tcp -novtswitch -auth /var/run/lxdm/lxdm-:0.auth
 370621 root     0::/user.slice/user-1000.sl  \_ /usr/libexec/lxdm-session
 370631 dboth    0::/user.slice/user-1000.sl      \_ xfce4-session
 370841 dboth    0::/user.slice/user-1000.sl          \_ /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
 370911 dboth    0::/user.slice/user-1000.sl          \_ xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
 370930 dboth    0::/user.slice/user-1000.sl          \_ xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
 370942 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libsystray.so 6 23068680 systr
ay Notification Area Area where notification icons appear
 370943 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libpulseaudio-plugin.so 8 2306
8681 pulseaudio PulseAudio Plugin Adjust the audio volume of the PulseAudio sound system
 370944 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libxfce4powermanager.so 9 2306
8682 power-manager-plugin Power Manager Plugin Display the battery levels of your devices and control the brightness of your display
 370945 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libnotification-plugin.so 10 2
3068683 notification-plugin Notification Plugin Notification plugin for the Xfce panel
 370948 dboth    0::/user.slice/user-1000.sl          |   \_ /usr/lib64/xfce4/panel/wrapper-2.0 /usr/lib64/xfce4/panel/plugins/libactions.so 14 23068684 acti
ons Action Buttons Log out, lock or other system actions
 370934 dboth    0::/user.slice/user-1000.sl          \_ Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
 370939 dboth    0::/user.slice/user-1000.sl          \_ xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
 370962 dboth    0::/user.slice/user-1000.sl          \_ nm-applet
<删节>

你可以使用 systemd-cgls 命令查看整个层次结构,这个命令不需要任何的复杂参数,更加简单。

我也大幅缩短了这个树状结构,但是保留了足够多的输出,以便你能够了解在自己的系统上执行这个命令时应该看到的数据总量和条目类型。我在我的一个虚拟机上执行了这个命令,输出大概有 200 行;我的主要工作站的输出大概有 250 行。

[root@testvm1 ~]# systemd-cgls
Control group /:
-.slice
├─user.slice
│ ├─user-0.slice
│ │ ├─session-1.scope
│ │ │ ├─  1130 sshd: root [priv]
│ │ │ ├─  1147 sshd: root@pts/0
│ │ │ ├─  1148 -bash
│ │ │ ├─  1321 screen
│ │ │ ├─  1322 SCREEN
│ │ │ ├─  1323 /bin/bash
│ │ │ ├─  1351 /bin/bash
│ │ │ ├─  1380 /bin/bash
│ │ │ ├─123293 man systemd.slice
│ │ │ ├─123305 less
│ │ │ ├─246795 /bin/bash
│ │ │ ├─371371 man systemd-cgls
│ │ │ ├─371383 less
│ │ │ ├─371469 systemd-cgls
│ │ │ └─371470 less
│ │ └─[email protected] …
│ │   ├─dbus-broker.service
│ │   │ ├─1170 /usr/bin/dbus-broker-launch --scope user
│ │   │ └─1171 dbus-broker --log 4 --controller 12 --machine-id 3bccd1140fca488187f8a1439c832f07 --max-bytes 100000000000000 --max-fds 25000000000000 --max->
│ │   ├─gvfs-daemon.service
│ │   │ └─1173 /usr/libexec/gvfsd
│ │   └─init.scope
│ │     ├─1137 /usr/lib/systemd/systemd --user
│ │     └─1138 (sd-pam)
│ └─user-1000.slice
│   ├─[email protected] …
│   │ ├─dbus\x2d:1.2\x2dorg.xfce.Xfconf.slice
│   │ │ └─dbus-:[email protected]
│   │ │   └─370748 /usr/lib64/xfce4/xfconf/xfconfd
│   │ ├─dbus\x2d:1.2\x2dca.desrt.dconf.slice
│   │ │ └─dbus-:[email protected]
│   │ │   └─371262 /usr/libexec/dconf-service
│   │ ├─dbus-broker.service
│   │ │ ├─1260 /usr/bin/dbus-broker-launch --scope user
│   │ │ └─1261 dbus-broker --log 4 --controller 11 --machine-id
<删节>
│   │ └─gvfs-mtp-volume-monitor.service
│   │   └─370987 /usr/libexec/gvfs-mtp-volume-monitor
│   ├─session-3.scope
│   │ ├─1218 sshd: dboth [priv]
│   │ ├─1233 sshd: dboth@pts/1
│   │ └─1235 -bash
│   └─session-7.scope
│     ├─370621 /usr/libexec/lxdm-session
│     ├─370631 xfce4-session
│     ├─370805 /usr/bin/VBoxClient --clipboard
│     ├─370806 /usr/bin/VBoxClient --clipboard
│     ├─370817 /usr/bin/VBoxClient --seamless
│     ├─370818 /usr/bin/VBoxClient --seamless
│     ├─370824 /usr/bin/VBoxClient --draganddrop
│     ├─370825 /usr/bin/VBoxClient --draganddrop
│     ├─370841 /usr/bin/ssh-agent /bin/sh -c exec -l bash -c "/usr/bin/startxfce4"
│     ├─370910 /bin/gpg-agent --sh --daemon --write-env-file /home/dboth/.cache/gpg-agent-info
│     ├─370911 xfwm4 --display :0.0 --sm-client-id 2dead44ab-0b4d-4101-bca4-e6771f4a8ac2
│     ├─370923 xfsettingsd --display :0.0 --sm-client-id 261b4a437-3029-461c-9551-68c2c42f4fef
│     ├─370930 xfce4-panel --display :0.0 --sm-client-id 2ce38b8ef-86fd-4189-ace5-deec1d0e0952
│     ├─370934 Thunar --sm-client-id 2cfc809d8-4e1d-497a-a5c5-6e4fa509c3fb --daemon
│     ├─370939 xfdesktop --display :0.0 --sm-client-id 299be0608-4dca-4055-b4d6-55ec6e73a324
<删节>
└─system.slice
  ├─rngd.service
  │ └─1650 /sbin/rngd -f
  ├─irqbalance.service
  │ └─1631 /usr/sbin/irqbalance --foreground
  ├─fprintd.service
  │ └─303383 /usr/libexec/fprintd
  ├─systemd-udevd.service
  │ └─956 /usr/lib/systemd/systemd-udevd
<删节>
  ├─systemd-journald.service
  │ └─588 /usr/lib/systemd/systemd-journald
  ├─atd.service
  │ └─1010 /usr/sbin/atd -f
  ├─system-dbus\x2d:1.10\x2dorg.freedesktop.problems.slice
  │ └─dbus-:[email protected]
  │   └─371197 /usr/sbin/abrt-dbus -t133
  ├─sshd.service
  │ └─893 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
  ├─vboxservice.service
  │ └─802 /usr/sbin/VBoxService -f
  ├─crond.service
  │ └─1011 /usr/sbin/crond -n
  ├─NetworkManager.service
  │ └─765 /usr/sbin/NetworkManager --no-daemon
  ├─switcheroo-control.service
  │ └─787 /usr/libexec/switcheroo-control
 <删节>

这个树状视图显示了所有的用户和系统切片,以及每个控制组内正在运行的服务和程序。注意叫作 scope(范围)的单元,它将相关的程序组成一个管理单元,在上面列出的结果中就是 user-1000.sliceuser-1000.slice/session-7.scope 控制组包含了 GUI 桌面程序层次结构,以 LXDM 显示管理器会话和其所有的子任务开始,包括像 Bash 命令行解释器和 Thunar GUI 文件管理器之类的程序。

配置文件中不定义范围单元,而是作为启动相关程序组的结果程序化生成的。范围单元不创建或启动作为控制组的组成部分运行的进程。范围内的所有进程都是平等的,没有内部的层次结构。一个范围的生命周期在第一个进程创建时开始,在最后一个进程销毁时结束。

在你的桌面打开多个窗口,比如终端模拟器、LibreOffice、或者任何你想打开的,然后切换到一个可用的虚拟控制台,启动类似 topMidnight Commander 的程序。在主机运行 systemd-cgls 命令,留意整体的层次结构和范围单元。

systemd-cgls 命令提供的控制组层次结构表示(以及组成控制组单元的细节),比我见过的其他任何指令都要完整。和 ps 命令提供的输出相比,我喜欢 systemd-cgls 命令更简洁的树形表示。

来自朋友们的一点帮助

介绍完这些基础知识后,我曾计划过深入研究控制组的更多细节,以及如何使用,但是我在 Opensource.com 的姐妹网站 Enable Sysadmin 上发现了一系列四篇优秀文章,由 Red Hat 公司的 Steve Ovens 所作。与其从头重写 Steve 的文章,我觉得倒不如通过链接到这些文章,利用他的控制组专业知识:

  1. 一个 Linux 系统管理员对控制组的介绍
  2. 如何用 CPUShares 管理控制组
  3. 用更难的方式,手动管理控制组
  4. 用 systemd 管理控制组

像我一样享受这些文章并从中汲取知识吧。

其他资源

互联网上充斥着大量关于 systemd 的信息,但大部分都简短生硬、愚钝、甚至令人误解。除了本文提到的资源,下面的网页提供了关于 systemd 启动更详细可靠的信息。自从我开始这一系列的文章来反映我所做的研究以来,这个的列表已经变长了。

还有一系列针对系统管理员的深度技术文章,由 systemd 的设计者和主要开发者 Lennart Poettering 所作。这些文章写于 2010 年 4 月到 2011 年 9 月之间,但在当下仍然像当时一样有 价值。关于 systemd 及其生态的许多其他优秀的作品都是基于这些文章的。


via: https://opensource.com/article/20/10/cgroups

作者:David Both 选题:lujun9972 译者:YungeG 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

systemd 启动过程提供的重要线索可以在问题出现时助你一臂之力。

 title=

在本系列的第一篇文章《学着爱上 systemd》,我考察了 systemd 的功能和架构,以及围绕 systemd 作为古老的 SystemV 初始化程序和启动脚本的替代品的争论。在这第二篇文章中,我将开始探索管理 Linux 启动序列的文件和工具。我会解释 systemd 启动序列、如何更改默认的启动目标(即 SystemV 术语中的运行级别)、以及在不重启的情况下如何手动切换到不同的目标。

我还将考察两个重要的 systemd 工具。第一个 systemctl 命令是和 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 ,但是这个文件在更新内核版本时会被覆盖,你不会想修改它的。相反,应该修改用于改变 grub.cfg 默认设置的 /etc/default/grub 文件。

首先看一下当前未修改的 /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 菜单倒计时的秒数 GRUB_TIMEOUT,从 5 改成 10,以便在倒计时达到 0 之前有更多的时间响应 GRUB 菜单。
  • GRUB_CMDLINE_LINUX 列出了引导阶段传递给内核的命令行参数,我删除了其中的最后两个参数。其中的一个参数 rhgb 代表 “ 红帽图形化引导 Red Hat Graphical Boot ”,在内核初始化阶段显示一个小小的 Fedora 图标动画,而不是显示引导阶段的信息。另一个参数 quiet,屏蔽显示记录了启动进度和发生错误的消息。系统管理员需要这些信息,因此我删除了 rhgbquiet。如果引导阶段发生了错误,屏幕上显示的信息可以指向故障的原因。

更改之后,你的 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 开机动画之下的启动信息。但是如果你没有关闭开机动画,又需要查看启动信息的话又该如何操作?或者你关闭了开机动画,而消息流过的速度太快,无法阅读怎么办?(实际情况如此。)

有两个解决方案,都涉及到日志文件和 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 ([email protected]) (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 并转交控制权。

引导 boot 阶段到此结束,此时 Linux 内核和 systemd 正在运行,但是无法为用户执行任何生产性任务,因为其他的程序都没有执行,没有命令行解释器提供命令行,没有后台进程管理网络和其他的通信链接,也没有任何东西能够控制计算机执行生产功能。

现在 systemd 可以加载所需的功能性单元以便将系统启动到选择的目标运行状态。

目标

一个 systemd 目标 target 代表一个 Linux 系统当前的或期望的运行状态。与 SystemV 启动脚本十分类似,目标定义了系统运行必须存在的服务,以及处于目标状态下必须激活的服务。图表 1 展示了使用 systemd 的 Linux 系统可能的运行状态目标。就像在本系列的第一篇文章以及 systemd 启动的手册页(man bootup)所看到的一样,有一些开启不同必要服务的其他中间目标,包括 swap.targettimers.targetlocal-fs.target 等。一些目标(像 basic.target)作为检查点使用,在移动到下一个更高级的目标之前保证所有需要的服务已经启动并运行。

除非开机时在 GRUB 菜单进行更改,systemd 总是启动 default.targetdefault.target 文件是指向真实的目标文件的符号链接。对于桌面工作站,default.target 通常是 graphical.target,等同于 SystemV 的运行等级 5。对于服务器,默认目标多半是 multi-user.target,就像 SystemV 的运行等级 3。emergency.target 文件类似单用户模式。目标和 服务 service 都是一种 systemd 单元。

下面的图表,包含在本系列的上一篇文章中,比较了 systemd 目标和古老的 SystemV 启动运行等级。为了向后兼容,systemd 提供了 systemd 目标别名,允许脚本和系统管理员使用像 init 3 一样的 SystemV 命令改变运行等级。当然,SystemV 命令被转发给 systemd 进行解释和执行。

systemd 目标SystemV 运行级别目标别名描述
default.target 这个目标通常是一个符号链接,作为 multi-user.targetgraphical.target 的别名。systemd 总是用 default.target 启动系统。default.target** 不能作为halt.targetpoweroff.targetreboot.target` 的别名。
graphical.target5runlevel5.target带有 GUI 的 multi-user.target
4runlevel4.target未使用。运行等级 4 和 SystemV 的运行等级 3 一致,可以创建这个目标并进行定制,用于启动本地服务,而不必更改默认的 multi-user.target
multi-user.target3runlevel3.target运行所有的服务,但是只有命令行界面(CLI) 。
2runlevel2.target多用户,没有 NFS,但是运行其他所有的非 GUI 服务
rescue.target1runlevel1.target一个基本的系统,包括挂载文件系统,但是只运行最基础的服务,以及一个主控制台上的用于救援的命令行解释器。
emergency.targetS 单用户模式 —— 没有服务运行;文件系统没有挂载。这是最基础级的操作模式,只有一个运行在主控制台的用于紧急情况的命令行解释器,供用户和系统交互。
halt.target 不断电的情况下停止系统
reboot.target6runlevel6.target重启
poweroff.target0runlevel0.target停止系统并关闭电源

每个目标在配置文件中都描述了一组依赖关系。systemd 启动需要的依赖,即 Linux 主机运行在特定功能级别所需的服务。加载目标配置文件中列出的所有依赖并运行后,系统就运行在那个目标等级。如果愿意,你可以在本系列的第一篇文章《学着爱上 systemd》中回顾 systemd 的启动序列和运行时目标。

探索当前的目标

许多 Linux 发行版默认安装一个 GUI 桌面界面,以便安装的系统可以像工作站一样使用。我总是从 Fedora Live USB 引导驱动器安装 Xfce 或 LXDE 桌面。即使是安装一个服务器或者其他基础类型的主机(比如用于路由器和防火墙的主机),我也使用 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(意思是 None),表示主机启动后没有修改过运行等级。数字 5 是当前的目标,正如古老的 SystemV 术语中的定义:

[root@testvm1 ~]# runlevel
N 5
[root@testvm1 ~]#

注意,runlevel 的手册页指出运行等级已经被淘汰,并提供了一个转换表。

你也可以使用 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.targetmulti-user.targetmulti-user.target 需要在 graphical.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 桌面接口。使用你的测试主机的根用户,切换到保存 systemd 配置的目录,执行一次快速列出操作:

[root@testvm1 ~]# cd /etc/systemd/system/ ; ll
drwxr-xr-x. 2 root root 4096 Apr 25  2018  basic.target.wants
&lt;snip&gt;
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
&lt;snip&gt;
[root@testvm1 system]#

为了强调一些有助于解释 systemd 如何管理启动过程的重要事项,我缩短了这个列表。你应该可以在虚拟机看到完整的目录和链接列表。

default.target 项是指向目录 /lib/systemd/system/graphical.target 的符号链接(软链接),列出那个目录查看目录中的其他内容:

[root@testvm1 system]# ll /lib/systemd/system/ | less

你应该在这个列表中看到文件、目录、以及更多链接,但是专门寻找一下 multi-user.targetgraphical.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 -&gt; /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 的控制台登录,虚拟控制台 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 工具 systemctljournalctl,还说明了如何从一个目标切换到另一个目标,以及如何修改默认目标。

本系列的下一篇文章中将会创建一个新的 systemd 单元,并配置为启动阶段运行。下一篇文章还会查看一些配置选项,可以帮助确定某个特定的单元在序列中启动的位置,比如在网络启动运行后。

资源

关于 systemd 网络上有大量的信息,但大部分都简短生硬、愚钝、甚至令人误解。除了本文提到的资源,下面的网页提供了关于 systemd 启动更详细可靠的信息。

  • Fedora 项目有一个优质实用的 systemd 指南,几乎有你使用 systemd 配置、管理、维护一个 Fedora 计算机需要知道的一切。
  • Fedora 项目还有一个好用的 速查表,交叉引用了古老的 SystemV 命令和对应的 systemd 命令。
  • 要获取 systemd 的详细技术信息和创立的原因,查看 Freedesktop.orgsystemd 描述
  • Linux.com 上“systemd 的更多乐趣”提供了更高级的 systemd 信息和提示

还有一系列针对系统管理员的深层技术文章,由 systemd 的设计者和主要开发者 Lennart Poettering 所作。这些文章写于 2010 年 4 月到 2011 年 9 月之间,但在当下仍然像当时一样有价值。关于 systemd 及其生态的许多其他优秀的作品都是基于这些文章的。


via: https://opensource.com/article/20/5/systemd-startup

作者:David Both 选题:lujun9972 译者:YungeG 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出