分类 系统运维 下的文章

在最小化服务器安装中,设置互联网或网络是非常容易的。在本指南中,我们将解释如何在 CentOS、RHEL、Rocky Linux 最小安装中设置互联网或网络。

当你刚刚完成任何服务器发行版的最小化安装时,你没有任何图形界面或桌面环境可以用于设置你的网络或互联网。因此,当你只能使用终端时,了解如何设置联网是很重要的。NetworkManager 以及 systemd 服务为完成这项工作提供了必要的工具。以下是具体使用方法。

在 CentOS、RHEL、Rocky Linux 最小化安装中设置互联网

完成安装后,启动服务器终端。理想情况下,你应该会看到提示符。使用 root 或 admin 账户登录。

然后,首先尝试使用 nmcli 检查网络接口的状态和细节。nmcli 是一个控制 NetworkManager 服务的命令行工具。使用以下命令进行检查。

nmcli device status

这将显示设备名称、状态等。

nmcli device status

运行工具 nmtui 来配置网络接口。nmtui 是 NetworkManager 工具的一部分,它为你提供了一个漂亮的用户界面来配置网络。这是 NetworkManager-tui 包的一部分,当你完成最小服务器的安装时它应该默认安装。

nmtui

nmtui 窗口中点击编辑一个连接。

nmtui – Select options

选择网口名称:

Select Interface to Edit

在编辑连接窗口,为 IPv4 和 IPv6 选择自动。并选择自动连接。完成后按 “OK”。

nmtui – Edit Connection

通过使用如下 systemd systemctl 命令,重新启动 NetworkManager 服务。

systemctl restart NetworkManager

如果一切顺利,在 CentOS、RHEL、Rocky Linux 服务器的最小化安装中你应该可以连接到网络和互联网了,前提是你的网络有互联网连接。你可以用 ping 来验证它是否正常。

setup internet minimal server – CentOS Rocky Linux RHEL

额外技巧:在最小化服务器中设置静态 IP

当你把网络配置设置为自动,当你连接到互联网时,网口会动态地分配 IP。在某些情况下,当你建立一个局域网 (LAN) 时,你可能想给你的网口分配静态 IP。这超级简单。

打开你的网络的网络配置脚本。根据你的设备修改高亮部分:

vi /etc/sysconfig/network-scripts/ifcfg-ens3

在上面的文件中,用 IPADDR 属性添加你想要的 IP 地址。保存该文件。

IPADDR=192.168.0.55

/etc/sysconfig/network 中为你的网络添加网关:

NETWORKING=yes
HOSTNAME=debugpoint
GATEWAY=10.1.1.1

/etc/resolv.confresolv.conf 中添加任意公共 DNS 服务器:

nameserver 8.8.8.8
nameserver 8.8.4.4

并重新启动网络服务:

systemctl restart NetworkManager

这样就完成了静态 IP 的设置。你也可以使用 ip addr 命令检查详细的 IP 信息。

我希望这个指南能帮助你在你的最小化服务器中设置网络、互联网和静态 IP。如果你有任何问题,请在评论区告诉我。


via: https://www.debugpoint.com/2021/06/setup-internet-minimal-install-server/

作者:Arindam 选题:lujun9972 译者:geekpi 校对:turbokernel

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

systemd 提供定时器有一段时间了,定时器替代了 cron 功能,这一特性值得看看。本文将向你介绍在系统启动后如何使用 systemd 中的定时器来运行任务,并在此后重复运行。这不是对 systemd 的全面讨论,只是对此特性的一个介绍。

快速回顾:cron、anacron 与 systemd

cron 可以以几分钟到几个月或更长时间的粒度调度运行一个任务。设置起来相对简单,它只需要一个配置文件。虽然配置过程有些深奥,但一般用户也可以使用。

然而,如果你的系统在需要执行的时间没有运行,那么 cron 会失败。

anacron 克服了“系统没有运行”的问题。它确保任务将在你的系统再次启动时执行。虽然它旨在给管理员使用,但有些系统允许普通用户访问 anacron。

但是,anacron 的执行频率不能低于每天一次。

cron 和 anacron 都存在执行上下文一致性的问题。必须注意任务运行时有效的环境与测试时使用的环境完全相同。必须提供相同的 shell、环境变量和路径。这意味着测试和调试有时会很困难。

systemd 定时器提供了 cron 和 anacron 二者的优点,允许调度到分钟粒度。确保在系统再次运行时执行任务,即使在预期的执行时间内系统处于关闭状态。它对所有用户都可用。你可以在它将要运行的环境中测试和调试执行。

但是,它的配置更加复杂,至少需要两个配置文件。

如果你的 cron 和 anacron 配置可以很好地为你服务,那么可能没有理由改变。但是 systemd 至少值得研究,因为它可以简化任何当前的 cron/anacron 工作方式。

配置

systemd 定时器执行功能至少需要两个文件。这两个是“ 定时器单元 timer unit ”和“ 服务单元 service unit ”。(其执行的)“动作”不仅仅是简单的命令,你还需要一个“作业”文件或脚本来执行必要的功能。

定时器单元文件定义调度表,而服务单元文件定义执行的任务。有关的更多详细信息请参考 man systemd.timer 中提供的 .timer 单元。服务单元的详细信息可在 man systemd.service 中找到。

单元文件存放在几个位置(在手册页中有列出)。然而,对于普通用户来说,最容易找到的位置可能是 ~/.config/systemd/user。请注意,这里的 user 是字符串 user

示例

此示例是一个创建用户调度作业而不是(以 root 用户身份运行的)系统调度作业的简单示例。它将消息、日期和时间打印到文件中。

1、首先创建一个执行任务的 shell 脚本。在你的本地 bin 目录中创建它,例如在 ~/bin/schedule-test.sh 中。

创建文件:

touch ~/bin/schedule-test.sh

然后将以下内容添加到你刚刚创建的文件中:

#!/bin/sh
echo "This is only a test: $(date)" >> "$HOME/schedule-test-output.txt"

记住赋予你的 shell 脚本执行权限。

2、创建 .service 单元调用上面的脚本。在以下位置创建目录与文件:~/.config/systemd/user/schedule-test.service

[Unit]
Description=A job to test the systemd scheduler

[Service]
Type=simple
ExecStart=/home/<user>/bin/schedule-test.sh

[Install]
WantedBy=default.target

请注意 <user> 应该是你的家目录地址,但是单元文件路径名中的 user 实际上是字符串 user

ExecStart 应该提供一个没有变量的绝对地址。例外情况是,对于用户单元文件,你可以用 %h 替换 $HOME。换句话说,你可以使用:

ExecStart=%h/bin/schedule-test.sh

这仅用于用户单元文件,而不适用于系统服务,因为在系统环境中运行时 %h 总是返回 /root。其他特殊符号可在 man systemd.unitSPECIFIERS 中找到。因为它超出了本文的范围,所以这就是我们目前需要了解的关于特殊符号的全部内容。

3、创建一个 .timer 单元文件,该文件实际上调度你创建的 .service 单元文件。在 .service 单元文件相同位置创建它:~/.config/systemd/user/schedule-test.timer。请注意,文件名仅在扩展名上有所不同,例如一个是 .service,一个是 .timer

[Unit]
Description=Schedule a message every 1 minute
RefuseManualStart=no  # Allow manual starts
RefuseManualStop=no   # Allow manual stops

[Timer]
#Execute job if it missed a run due to machine being off
Persistent=true
#Run 120 seconds after boot for the first time
OnBootSec=120
#Run every 1 minute thereafter
OnUnitActiveSec=60
#File describing job to execute
Unit=schedule-test.service

[Install]
WantedBy=timers.target

请注意,这个 .timer 单元文件使用了 OnUnitActiveSec 来指定调度表。OnCalendar 选项更加灵活。例如:

# run on the minute of every minute every hour of every day
 OnCalendar=*-*-* *:*:00
# run on the hour of every hour of every day
 OnCalendar=*-*-* *:00:00
# run every day
 OnCalendar=*-*-* 00:00:00
# run 11:12:13 of the first or fifth day of any month of the year
# 2012, but only if that day is a Thursday or Friday
 OnCalendar=Thu,Fri 2012-*-1,5 11:12:13

有关 OnCalendar 的更多信息参见 这里

4、所有的部件都已就位,但你应该进行测试,以确保一切正常。首先,启用该用户服务:

$ systemctl --user enable schedule-test.service

这将导致类似如下的输出:

Created symlink /home/<user>/.config/systemd/user/default.target.wants/schedule-test.service → /home/<user>/.config/systemd/user/schedule-test.service.

现在执行测试工作:

$ systemctl --user start schedule-test.service

检查你的输出文件($HOME/schedule-test-output.txt),确保你的脚本运行正常。应该只有一个条目,因为我们还没有启动定时器。必要时进行调试。如果你需要更改 .service 单元文件,而不是更改它调用的 shell 脚本,请不要忘记再次启用该服务。

5、一旦作业正常运行,通过为服务启用、启动用户定时器来实时调度作业:

$ systemctl --user enable schedule-test.timer
$ systemctl --user start schedule-test.timer

请注意,你已经在上面的步骤 4 中启动、启用了服务,因此只需要为它启用、启动定时器。

enable 命令会产生如下输出:

Created symlink /home/<user>/.config/systemd/user/timers.target.wants/schedule-test.timer → /home/<user>/.config/systemd/user/schedule-test.timer.

start 命令将只是返回命令行界面提示符。

其他操作

你可以检查和监控服务。如果你从系统服务收到错误,下面的第一个命令特别有用:

$ systemctl --user status schedule-test
$ systemctl --user list-unit-files

手动停止服务:

$ systemctl --user stop schedule-test.service

永久停止并禁用定时器和服务,重新加载守护程序配置并重置任何失败通知:

$ systemctl --user stop schedule-test.timer
$ systemctl --user disable schedule-test.timer
$ systemctl --user stop schedule-test.service
$ systemctl --user disable schedule-test.service
$ systemctl --user daemon-reload
$ systemctl --user reset-failed

总结

本文以 systemd 定时器为出发点,但是 systemd 的内容远不止于此。这篇文章应该为你提供一个基础。你可以从 Fedora Magazine systemd 系列 开始探索更多。

参考

更多阅读:


via: https://fedoramagazine.org/systemd-timers-for-scheduling-tasks/

作者:Richard England 选题:lujun9972 译者:dcoliversun 校对:wxy

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

虽然 systemd 并非真正的故障定位工具,但其输出中的信息为解决问题指明了方向。

 title=

没有人会认为 systemd 是一个故障定位工具,但当我的 web 服务器遇到问题时,我对 systemd 和它的一些功能的不断了解帮助我找到并规避了问题。

我遇到的问题是这样,我的服务器 yorktown 为我的家庭办公网络提供名称服务 、DHCP、NTP、HTTPD 和 SendMail 邮件服务,它在正常启动时未能启动 Apache HTTPD 守护程序。在我意识到它没有运行之后,我不得不手动启动它。这个问题已经持续了一段时间,我最近才开始尝试去解决它。

你们中的一些人会说,systemd 本身就是这个问题的原因,根据我现在了解的情况,我同意你们的看法。然而,我在使用 SystemV 时也遇到了类似的问题。(在本系列文章的 第一篇 中,我探讨了围绕 systemd 作为旧有 SystemV 启动程序和启动脚本的替代品所产生的争议。如果你有兴趣了解更多关于 systemd 的信息,也可以阅读 第二篇第三篇 文章。)没有完美的软件,systemd 和 SystemV 也不例外,但 systemd 为解决问题提供的信息远远多于 SystemV。

确定问题所在

找到这个问题根源的第一步是确定 httpd 服务的状态:

[root@yorktown ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
   Active: failed (Result: exit-code) since Thu 2020-04-16 11:54:37 EDT; 15min ago
     Docs: man:httpd.service(8)
  Process: 1101 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE)
 Main PID: 1101 (code=exited, status=1/FAILURE)
   Status: "Reading configuration..."
      CPU: 60ms

Apr 16 11:54:35 yorktown.both.org systemd[1]: Starting The Apache HTTP Server...
Apr 16 11:54:37 yorktown.both.org httpd[1101]: (99)Cannot assign requested address: AH00072: make_sock: could not bind to address 192.168.0.52:80
Apr 16 11:54:37 yorktown.both.org httpd[1101]: no listening sockets available, shutting down
Apr 16 11:54:37 yorktown.both.org httpd[1101]: AH00015: Unable to open logs
Apr 16 11:54:37 yorktown.both.org systemd[1]: httpd.service: Main process exited, code=exited, status=1/FAILURE
Apr 16 11:54:37 yorktown.both.org systemd[1]: httpd.service: Failed with result 'exit-code'.
Apr 16 11:54:37 yorktown.both.org systemd[1]: Failed to start The Apache HTTP Server.
[root@yorktown ~]#

这种状态信息是 systemd 的功能之一,我觉得比 SystemV 提供的任何功能都要有用。这里的大量有用信息使我很容易得出逻辑性的结论,让我找到正确的方向。我从旧的 chkconfig 命令中得到的是服务是否在运行,以及如果它在运行的话,进程 ID(PID)是多少。这可没多大帮助。

该状态报告中的关键条目显示,HTTPD 不能与 IP 地址绑定,这意味着它不能接受传入的请求。这表明网络启动速度不够快,因为 IP 地址还没有设置好,所以 HTTPD 服务还没有准备好与 IP 地址绑定。这是不应该发生的,所以我查看了我的网络服务的 systemd 启动配置文件;在正确的 afterrequires 语句下,所有这些似乎都没问题。下面是我服务器上的 /lib/systemd/system/httpd.service 文件:

# Modifying this file in-place is not recommended, because changes 
# will be overwritten during package upgrades.  To customize the 
# behaviour, run "systemctl edit httpd" to create an override unit.

# For example, to pass additional options (such as -D definitions) to 
# the httpd binary at startup, create an override unit (as is done by                             
# systemctl edit) and enter the following:                                           

#    [Service]
#    Environment=OPTIONS=-DMY_DEFINE             

[Unit]                                               
Description=The Apache HTTP Server
Wants=httpd-init.service
After=network.target remote-fs.target nss-lookup.target httpd-init.service
Documentation=man:httpd.service(8)

[Service]
Type=notify
Environment=LANG=C

ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
# Send SIGWINCH for graceful stop
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

httpd.service 单元文件明确规定,它应该在 network.targethttpd-init.service(以及其他)之后加载。我试着用 systemctl list-units 命令找到所有这些服务,并在结果数据流中搜索它们。所有这些服务都存在,应该可以确保在设置网络 IP 地址之前,httpd 服务没有加载。

第一个解决方案

在互联网上搜索了一下,证实其他人在 httpd 和其他服务也遇到了类似的问题。这似乎是由于其中一个所需的服务向 systemd 表示它已经完成了启动,但实际上它却启动了一个尚未完成的子进程。通过更多搜索,我想到了一个规避方法。

我搞不清楚为什么花了这么久才把 IP 地址分配给网卡。所以我想,如果我可以将 HTTPD 服务的启动推迟合理的一段时间,那么 IP 地址就会在那个时候分配。

幸运的是,上面的 /lib/systemd/system/httpd.service 文件提供了一些方向。虽然它说不要修改它,但是它还是指出了如何操作:使用 systemctl edit httpd 命令,它会自动创建一个新文件(/etc/systemd/system/httpd.service.d/override.conf)并打开 GNU Nano 编辑器(如果你对 Nano 不熟悉,一定要看一下 Nano 界面底部的提示)。

在新文件中加入以下代码并保存:

[root@yorktown ~]# cd /etc/systemd/system/httpd.service.d/
[root@yorktown httpd.service.d]# ll
total 4
-rw-r--r-- 1 root root 243 Apr 16 11:43 override.conf
[root@yorktown httpd.service.d]# cat override.conf
# Trying to delay the startup of httpd so that the network is
# fully up and running so that httpd can bind to the correct
# IP address
#
# By David Both, 2020-04-16

[Service]
ExecStartPre=/bin/sleep 30

这个覆盖文件的 [Service] 段有一行代码,将 HTTPD 服务的启动时间推迟了 30 秒。下面的状态命令显示了等待时间里的服务状态:

[root@yorktown ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/httpd.service.d
           └─override.conf
           /usr/lib/systemd/system/httpd.service.d
           └─php-fpm.conf
   Active: activating (start-pre) since Thu 2020-04-16 12:14:29 EDT; 28s ago
     Docs: man:httpd.service(8)
Cntrl PID: 1102 (sleep)
    Tasks: 1 (limit: 38363)
   Memory: 260.0K
      CPU: 2ms
   CGroup: /system.slice/httpd.service
           └─1102 /bin/sleep 30

Apr 16 12:14:29 yorktown.both.org systemd[1]: Starting The Apache HTTP Server...
Apr 16 12:15:01 yorktown.both.org systemd[1]: Started The Apache HTTP Server.
[root@yorktown ~]#

这个命令显示了 30 秒延迟过后 HTTPD 服务的状态。该服务已经启动并正常运行。

[root@yorktown ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
   Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/httpd.service.d
           └─override.conf
           /usr/lib/systemd/system/httpd.service.d
           └─php-fpm.conf
   Active: active (running) since Thu 2020-04-16 12:15:01 EDT; 1min 18s ago
     Docs: man:httpd.service(8)
  Process: 1102 ExecStartPre=/bin/sleep 30 (code=exited, status=0/SUCCESS)
 Main PID: 1567 (httpd)
   Status: "Total requests: 0; Idle/Busy workers 100/0;Requests/sec: 0; Bytes served/sec:   0 B/sec"
    Tasks: 213 (limit: 38363)
   Memory: 21.8M
      CPU: 82ms
   CGroup: /system.slice/httpd.service
           ├─1567 /usr/sbin/httpd -DFOREGROUND
           ├─1569 /usr/sbin/httpd -DFOREGROUND
           ├─1570 /usr/sbin/httpd -DFOREGROUND
           ├─1571 /usr/sbin/httpd -DFOREGROUND
           └─1572 /usr/sbin/httpd -DFOREGROUND

Apr 16 12:14:29 yorktown.both.org systemd[1]: Starting The Apache HTTP Server...
Apr 16 12:15:01 yorktown.both.org systemd[1]: Started The Apache HTTP Server.

我本来可以实验下更短的延迟时间是否也能奏效,但是我的系统并不用那么严格,所以我觉得不这样做。目前系统的工作状态很可靠,所以我很高兴。

因为我收集了所有这些信息,我将其作为 Bug1825554 报告给红帽 Bugzilla。我相信报告 Bug 比抱怨 Bug 更有有用。

更好的解决方案

把这个问题作为 bug 上报几天后,我收到了回复,表示 systemd 只是一个管理工具,如果 httpd 需要在满足某些要求之后被拉起,需要在单元文件中表达出来。这个回复指引我去查阅 httpd.service 的手册页。我希望我能早点发现这个,因为它是比我自己想出的更优秀的解决方案。这种方案明确的针对了前置目标单元,而不仅仅是随机延迟。

来自 httpd.service 手册页:

在启动时开启服务

httpd.servicehttpd.socket 单元默认是 禁用 的。为了在启动阶段开启 httpd 服务,执行:systemctl enable httpd.service。在默认配置中,httpd 守护进程会接受任何配置好的 IPv4 或 IPv6 地址的 80 口上的连接(如果安装了 mod\_ssl,就会接受 443 端口上的 TLS 连接)。

如果 httpd 被配置成依赖任一特定的 IP 地址(比如使用 Listen 指令),该地址可能只在启动阶段可用,又或者 httpd 依赖其他服务(比如数据库守护进程),那么必须配置该服务,以确保正确的启动顺序。

例如,为了确保 httpd 在所有配置的网络接口配置完成之后再运行,可以创建一个带有以下代码段的 drop-in 文件(如上述):

[Unit]
After=network-online.target
Wants=network-online.target

我仍然觉得这是个 bug,因为在 httpd.conf 配置文件中使用 Listen 指令是很常见的,至少在我的经验中。我一直在使用 Listen 指令,即使在只有一个 IP 地址的主机上,在多个网卡和 IP 地址的机器上这显然也是有必要的。在 /usr/lib/systemd/system/httpd.service 默认配置文件中加入上述几行,对不使用 Listen 指令的不会造成问题,对使用 Listen 指令的则会规避这个问题。

同时,我将使用建议的方法。

下一步

本文描述了一个我在服务器上启动 Apache HTTPD 服务时遇到的一个问题。它指引你了解我在解决这个问题上的思路,并说明了我是如何使用 systemd 来协助解决问题。我也介绍了我用 systemd 实现的规避方法,以及我按照我的 bug 报告得到的更好的解决方案。

如我在开头处提到的那样,这有很大可能是一个 systemd 的问题,特别是 httpd 启动的配置问题。尽管如此,systemd 还是提供了工具让我找到了问题的可能来源,并制定和实现了规避方案。两种方案都没有真正令我满意地解决问题。目前,这个问题根源依旧存在,必须要解决。如果只是在 /usr/lib/systemd/system/httpd.service 文件中添加推荐的代码,那对我来说是可行的。

在这个过程中我发现了一件事,我需要了解更多关于定义服务启动顺序的知识。我会在下一篇文章中探索这个领域,即本系列的第五篇。

资源

网上有大量的关于 systemd 的参考资料,但是大部分都有点简略、晦涩甚至有误导性。除了本文中提到的资料,下列的网页提供了跟多可靠且详细的 systemd 入门信息。

  • Fedora 项目有一篇切实好用的 systemd 入门,它囊括了几乎所有你需要知道的关于如何使用 systemd 配置、管理和维护 Fedora 计算机的信息。
  • Fedora 项目也有一个不错的 备忘录,交叉引用了过去 SystemV 命令和 systemd 命令做对比。
  • 关于 systemd 的技术细节和创建这个项目的原因,请查看 Freedesktop.org 上的 systemd 描述
  • Linux.com 的“更多 systemd 的乐趣”栏目提供了更多高级的 systemd 信息和技巧

此外,还有一系列深度的技术文章,是由 systemd 的设计者和主要开发者 Lennart Poettering 为 Linux 系统管理员撰写的。这些文章写于 2010 年 4 月至 2011 年 9 月间,但它们现在和当时一样具有现实意义。关于 systemd 及其生态的许多其他好文章都是基于这些文章:


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

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

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

在企业互联网场景中,一般情况下最广泛使用的基于 Linux 的操作系统是 Red Hat Enterprise Linux(RHEL),它主要用于服务器,但也可以用作工作站。Fedora linux 其实也是工作站系统的一个很好的选择,它提供了许多在企业环境中工作的特性,使管理成为一项简单的任务。

当你的工作网络中有许多机器时,你需要一种以集中方式管理用户和机器的方法。FreeIPA 活动目录 Active Directory 就是用于这个任务的技术。它们允许系统管理员使用网络中所有实体的目录来管理大量的机器。

Fedora 中的活动目录

活动目录在公司环境中非常常见。Fedora 和 RHEL 通过使用 SSSD ( 系统安全服务守护进程 System Security Services Daemon )与 FreeIPA 或活动目录等服务很好地集成。SSSD 是一种访问远程目录和身份验证机制的系统服务。使用此软件的计算机能够使用远程凭据进行身份验证,并访问该目录网络中可用的其他服务。

要加入域网络,你需要域管理员的权限才能添加计算机。可以通过在域凭据上设置特殊权限或代表你对该计算机进行预配置。Fedora Linux 有一个在安装时配置机器的选项,叫做 企业登录 Enterprise Login 。如果你的计算机网络自动配置为企业域网络,那么你可以直接使用域凭据登录。

如果你的配置不是自动的,或者你已经安装了 Fedora Linux,你可以通过以下几个配置步骤加入一个活动目录域:

  1. 设置此计算机的 DNS。要连接到目录服务,首先需要能够解析目录域名。如果你的网络使用 DHCP 设置正确的 DNS,则可以跳过此步骤。
  2. 更改你的计算机名称,以反映它将是新域的一部分。编辑文件 /etc/hostname,并将机器名更改为 machinename.my_domain
  3. 通过执行以下命令加入域:sudo realm join my_domain -v( 用域名称替换 my_domain)。

运行此命令后,系统将请求允许加入该域中新计算机的用户的凭据。如果进程中没有错误,则机器将成为域的一部分。

现在,此计算机已成为你的域的一部分,你可以:

  • 使用域用户名登录到计算机
  • 获取 kerberos 票据以访问域网络中的不同服务
  • 访问其他服务,具体取决于域的配置方式

使用 Fleet Commander 管理 Fedora Linux

现在这台计算机已经是你的域的一部分了,你可以使用活动目录的域管理员工具来管理它。由于你的计算机没有运行 Windows,因此你只能进行身份验证以及访问网络和目录服务。无法在此计算机上设置与桌面相关的配置。

幸运的是,Fedora 有个工具叫 Fleet Commander

创建配置

Fleet Commander 是一个管理工具,允许你为网络中的所有 Fedora Linux 机器设置桌面配置文件。

这意味着,你可以简单地为 GNOME 桌面、Firefox、Chrome、LibreOffice 和其他支持的软件设置任何配置,然后在登录到选定的用户/组/计算机时以细粒度的方式应用该配置。

要使用这个工具首先安装 fleet-commander-admin 软件包:

sudo dnf install fleet-commander-admin

然后,用浏览器访问 http://localhost:9090 来登录。在左边的菜单中,点击 “Fleet Commander”。

Fleet Commander 有一个工具,可以使用“实时会话”机制直观地设置配置概要文件。它运行一个虚拟机,作为基本机器的模板。你需要手动进行所需的配置更改。然后检查所有配置更改,选择要添加到配置文件中的更改,然后部署它。

管理客户端

在每个 Fedora Linux 或 RHEL 机器中,你都需要安装 Fleet Commander 客户端服务。此服务在用户登录时激活。它在域中搜索应用于当前用户/计算机的配置文件,并应用这个配置。

安装 fleet-commander-client

sudo dnf install fleet-commander-client

软件将自动检测机器是否是域的一部分。当用户登录时,它将使用应用于该用户的配置文件来设置会话。


via: https://fedoramagazine.org/join-fedora-linux-enterprise-domain/

作者:ogutierrez 选题:lujun9972 译者:Chao-zhi 校对:wxy

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

你想在你的 Ubuntu 服务器上安装 GUI 吗?大部分情况下你是可以安装的,在本教程中我会详细介绍安装的步骤。

在正式开始之前,我来告诉你为什么服务器版的 Ubuntu 不带 GUI,以及在什么情况下你可以在服务器上安装 GUI。

为什么 Ubuntu 服务器没有 GUI?

你对比过 Ubuntu 的桌面版和服务器版会发现,两者的主要区别是服务器版缺少 GUI(比如 桌面环境)。Ubuntu 服务器基本上就是桌面版去掉图形模块后的降级版本。

这是刻意为之的。Linux 服务器需要占用系统资源来运行服务。图形化桌面环境会消耗大量的系统资源,因此服务器操作系统默认不包含桌面环境。

你可以在只有 512 MB RAM 的机器上使用 Ubuntu 服务器,但是 Ubuntu 桌面需要至少 2 GB 的 RAM 才能提供正常的功能。在服务器运行桌面环境被认为是浪费资源。

作为一个服务器使用者(或系统管理员),你应该通过命令行来使用和管理你的系统。为了达到这个水平,你需要掌握丰富的 Linux 命令相关的知识。

Typically, you have to manage a server from the command line

你是否真正需要在你的服务器上安装 GUI?

有些用户可能不太习惯在终端下使用命令行来完成工作。毕竟大部分用户是有条件通过图形界面操作计算机的。

你可能会在你的服务器上安装桌面环境并使用图形界面。大部分人不会这么干,但这是可行的。

但是这只有在你可以直接操作服务器时才行得通。假设你是在物理机器上运行它,比如服务器、台式机或笔记本电脑,抑或类似树莓派的设备。如果你可以直接操作宿主机系统,那么你还可以在运行在虚拟机上的服务器上安装。

如果你是通过 云服务器提供商如 Linode、DigitalOcean 或 AWS 部署的服务器,那么安装 GUI 就行不通了。如果你想通过图形界面来管理你的远程服务器,你可以使用 Webmin 或 Cockpit 等工具。你可以在 Web 浏览器中通过这些工具使用和管理你的服务器。相比于成熟的桌面环境,它能大大降低资源消耗。

Tools like Cockpit allow managing Linux servers graphically

如何在 Ubuntu 服务器上安装 GUI?

当你了解了基础知识后,我们一起来看看在 Ubuntu 服务器上安装桌面环境的步骤。

你需要做以下准备:

  • 已经配置好 Ubuntu 服务器,且 RAM 至少 2 GB
  • 管理员权限(你需要用 sudo 执行命令)
  • 网络连接正常(你需要下载和安装新包)

我是在虚拟机上安装的 Ubuntu 服务器,并且我可以直接操作宿主机器。我使用同样的方法在树莓派上安装了 Ubuntu 服务器

注意!

如果你是出于学习和调研等实验性的目的,那么你可以进行这些操作。请不要在生产环境的服务器上添加 GUI。后续删除 GUI 时可能会导致依赖问题,有些情况会破坏系统。

准备系统

首先,因为你将要做一些系统级的修改,因此先进行更新和升级以确保我们系统的包是最新的:

sudo apt update && sudo apt upgrade

安装桌面环境

更新结束后,你就可以安装桌面环境了。

有两种方法:

  • 使用 apt 来安装包
  • 使用一个名为 tasksel 的 Debian 工具,这个工具可以通过一条龙处理(任务)方式来安装多个包

任何一种方法都可以用完整包的方式来安装完整的桌面环境,就跟你从头安装桌面版本一样。我的意思是你可以得到跟桌面版本一样的所有的默认应用程序和工具。

如果你想使用 tasksel,需要先用下面的命令安装它:

sudo apt install tasksel

执行结束后,你就可以用 tasksel 来安装桌面环境(也叫 DE)了。

你可能知道有 很多可用的桌面环境。你可以选择自己喜欢的一个。有些桌面环境对系统资源占用得多(像 GNOME),有些占用得少(像 Xfce、MATE 等等)。

你可以自己决定使用哪个 DE。我会安装 GNOME 桌面,因为它是 Ubuntu 默认的桌面。之后我也会介绍其他桌面的安装。

如果你使用的是 tasksel,执行下面这条命令:

sudo tasksel install ubuntu-desktop

如果你使用 apt,执行下面这条命令:

sudo apt install ubuntu-desktop

这个过程可能会持续几分钟到一个小时,执行速度取决于你的网速和硬件。

我想提醒下,上面两个命令执行后都会安装完整的 GNOME 桌面环境。在本文中我两个命令都会执行,两个命令的结果是一样的。

安装和配置显示管理器

安装完成后,你需要一个名为 显示管理器 或“登录管理器”的组件。这个工具的功能是在管理用户对话和鉴权时启动 显示服务器 并加载桌面。

GNOME 桌面默认使用 GDM3 作为显示管理器,但从资源角度考虑它有点重。你可以使用更轻量级和资源友好的管理器。这里我们使用一个平台无关的显示管理器 lightdm。使用 apt 安装它:

sudo apt install lightdm

安装 lightdm 时系统会让我们选择默认的显示管理器,因为即使你可以安装多个管理器,也只能运行一个。

Use the arrow key to select an option and then use the tab key to select  and press enter

选择列表中的 “lightdm” 并点击 “”。这应该用不了几分钟。完成后你可以用下面的命令启动显示管理器并加载 GUI:

sudo service lightdm start

你可以使用下面的命令来检查当前的显示管理器:

cat /etc/X11/default-display-manager

运行后得到的结果类似这样:

Checking the default Display Manager

如果一切顺利,你现在会来到欢迎界面。

Greetings screen of GNOME Desktop with LightDM on an Ubuntu server

输入你的凭证,你的桌面就运行起来了。

GNOME Desktop fully loaded on Ubutnu server

如果你想关闭 GUI,那么打开一个终端并输入:

sudo service lightdm stop

安装其他的桌面环境(可选)

前面我说过我们可以选择不同的桌面。我们一起来看看一些其他的选项:

MATE

MATE 是基于 GNOME2 源码的轻量级桌面,它完全开源,是一个不错的选项。

用下面的命令来安装 MATE:

sudo tasksel install ubuntu-mate-core

sudo apt install ubuntu-mate-core
Lubuntu / LXDE/LXQT

如果你的系统资源有限或者电脑很旧,那么我推荐另一个轻量级的 Lubuntu。使用下面的命令安装它:

sudo tasksel install lubuntu-core

sudo apt install lubuntu-core
Xubuntu / Xfce

Xubuntu 是基于 Xfce 的 Ubuntu 衍生版,轻量、简单、稳定但可高度定制。如果你想使用它,执行下面的命令:

sudo tasksel install xubuntu-core

sudo apt install xubuntu-core

还有一些桌面没有列出来,像 KDECinnamonBudgie,不代表它们不好,它们也都是非常卓越的,你可以自己尝试安装它们。

如何从 Ubuntu 服务器上删除 GUI?

如果你觉得桌面环境占用了太多的计算资源,你可以把之前安装的包删除掉。

请注意在某些情况下删除 GUI 可能会带来依赖问题,因此请备份好重要数据或创建一个系统快照。

sudo apt remove ubuntu-desktop
sudo apt remove lightdm
sudo apt autoremove
sudo service lightdm stop

现在重启你的系统。你应该回到了正常的命令行登录。

结语

在大多数场景下是可以安装桌面 GUI 的。如果你不适应命令行,那么请使用类似 YunoHost 的发行版的服务器,YunoHost 基于 Debian 系统,你可以通过 GUI 来管理服务器。

上面说了,如果你是从头安装系统,那么我建议你使用桌面版本以避免后续的步骤。

如果你有任何问题,请在评论区留言。你会在服务器上使用 GUI 吗?参照本文后你遇到了什么问题吗?


via: https://itsfoss.com/install-gui-ubuntu-server/

作者:Chris Patrick Carias Stas 选题:lujun9972 译者:lxbwolf 校对:wxy

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

了解 systemd 是怎样决定服务启动顺序,即使它本质上是个并行系统。

 title=

最近在设置 Linux 系统时,我想知道如何确保服务和其他单元的依赖关系在这些依赖于它们的服务和单元启动之前就已经启动并运行了。我需要更多 systemd 如何管理启动程序的相关知识,特别是在本质上是一个并行的系统中如何是决定服务启动顺序的。

你可能知道 SystemV(systemd 的前身,我在这个系列的 第一篇文章 中解释过)通过 Sxx 前缀命名启动脚本来决定启动顺序,xx 是一个 00-99 的数字。然后 SystemV 利用文件名来排序,然后按照所需的运行级别执行队列中每个启动脚本。

但是 systemd 使用单元文件来定义子程序,单元文件可由系统管理员创建或编辑,这些文件不仅可以用于初始化时也可以用于常规操作。在这个系列的 第三篇文章 中,我解释了如何创建一个挂载单元文件。在第五篇文章中,我解释了如何创建一种不同的单元文件 —— 在启动时执行一个程序的服务单元文件。你也可以修改单元文件中某些配置,然后通过 systemd 日志去查看你的修改在启动序列中的位置。

准备工作

先确认你已经在 /etc/default/grub 文件中的 GRUB_CMDLINE_LINUX= 这行移除了 rhgbquiet,如同我在这个系列的 第二篇文章 中展示的那样。这让你能够查看 Linux 启动信息流,你在这篇文章中部分实验中需要用到。

程序

在本教程中,你会创建一个简单的程序让你能够在主控台和后续的 systemd 日志中查看启动时的信息。

创建一个 shell 程序 /usr/local/bin/hello.sh 然后添加下述内容。你要确保执行结果在启动时是可见的,可以轻松的在 systemd 日志中找到它。你会使用一版携带一些方格的 “Hello world” 程序,这样它会非常显眼。为了确保这个文件是可执行的,且为了安全起见,它需要 root 的用户和组所有权和 700 权限

#!/usr/bin/bash
# Simple program to use for testing startup configurations
# with systemd.
# By David Both
# Licensed under GPL V2
#
echo "###############################"
echo "######### Hello World! ########"
echo "###############################"

在命令行中执行这个程序来检查它能否正常运行。

[root@testvm1 ~]# hello.sh
###############################
######### Hello World! ########
###############################
[root@testvm1 ~]#

这个程序可以用任意脚本或编译语言实现。hello.sh 程序可以被放在 Linux 文件系统层级结构(FHS)上的任意位置。我把它放在 /usr/local/bin 目录下,这样它可以直接在命令行中执行而不必在打命令的时候前面带上路径。我发现我创建的很多 shell 程序需要从命令行和其他工具(如 systemd)运行。

服务单元文件

创建服务单元文件 /etc/systemd/system/hello.service,写入下述内容。这个文件不一定是要可执行的,但是为了安全起见,它需要 root 的用户和组所有权和 644640 权限。

# Simple service unit file to use for testing
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh

[Install]
WantedBy=multi-user.target

通过查看服务状态来确认服务单元文件能如期运行。如有任何语法问题,这里会显示错误。

[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)
[root@testvm1 ~]#

你可以运行这类 “oneshot”(单发)类型的服务多次而不会有问题。此类服务适用于服务单元文件启动的程序是主进程,必须在 systemd 启动任何依赖进程之前完成的服务。

共有 7 种服务类型,你可以在 systemd.service(5) 的手册页上找到每一种(以及服务单元文件的其他部分)的详细解释。(你也可以在文章末尾的 资料 中找到更多信息。)

出于好奇,我想看看错误是什么样子的。所以我从 Type=oneshot 这行删了字母 “o”,现在它看起来是这样 Type=neshot,现在再次执行命令:

[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 06 08:50:09 testvm1.both.org systemd[1]: /etc/systemd/system/hello.service:12: Failed to parse service type, ignoring: neshot
[root@testvm1 ~]#

执行结果明确地告诉我错误在哪,这样解决错误变得十分容易。

需要注意的是即使在你将 hello.service 文件保存为它原来的形式之后,错误依然存在。虽然重启机器能消除这个错误,但你不必这么做,所以我去找了一个清理这类持久性错误的方法。我曾遇到有些错误需要 systemctl daemon-reload 命令来重置错误状态,但是在这个例子里不起作用。可以用这个命令修复的错误似乎总是有一个这样的声明,所以你知道要运行它。

然而,每次修改或新建一个单元文件之后执行 systemctl daemon-reload 确实是值得推荐的做法。它提醒 systemd 有修改发生,而且它可以防止某些与管理服务或单元相关的问题。所以继续去执行这条命令吧。

在修改完服务单元文件中的拼写错误后,一个简单的 systemctl restart hello.service 命令就可以清除错误。实验一下,通过添加一些其他的错误至 hello.service 文件来看看会得到怎样的结果。

启动服务

现在你已经准备好启动这个新服务,通过检查状态来查看结果。尽管你可能之前已经重启过,你仍然可以启动或重启这个单发服务任意次,因为它只运行一次就退出了。

继续启动这个服务(如下所示),然后检查状态。你的结果可能和我的有区别,取决于你做了多少试错实验。

[root@testvm1 ~]# systemctl start hello.service
[root@testvm1 ~]# systemctl status hello.service
● hello.service - My hello shell script
     Loaded: loaded (/etc/systemd/system/hello.service; disabled; vendor preset: disabled)
     Active: inactive (dead)

May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

从状态检查命令的输出中我们可以看到,systemd 日志表明 hello.sh 启动然后服务结束了。你也可以看到脚本的输出。该输出是根据服务的最近调用的日志记录生成的,试试看多启动几次这个服务,然后再看状态命令的输出就能理解我所说的。

你也应该直接查看日志内容,有很多种方法可以实现。一种办法是指定记录类型标识符,在这个例子中就是 shell 脚本的名字。它会展示前几次重启和当前会话的日志记录。如你所见,我已经为这篇文章做了挺长一段时间的研究测试了。

[root@testvm1 ~]# journalctl -t hello.sh
<剪去>
-- Reboot --
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
May 08 15:55:47 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 15:55:47 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
May 08 16:01:51 testvm1.both.org hello.sh[840]: ######### Hello World! ########
May 08 16:01:51 testvm1.both.org hello.sh[840]: ###############################
-- Reboot --
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

为了定位 hello.service 单元的 systemd 记录,你可以在 systemd 中搜索。你可以使用 G+Enter 来翻页到日志记录 记录的末尾,然后用回滚来找到你感兴趣的日志。使用 -b 选项仅展示最近启动的记录。

[root@testvm1 ~]# journalctl -b -t systemd
<剪去>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:50 testvm1.both.org systemd[1]: Starting D-Bus System Message Bus...
May 10 10:37:50 testvm1.both.org systemd[1]: Started D-Bus System Message Bus.

我拷贝了一些其他的日志记录,让你对你可能找到的东西有所了解。这条命令喷出了所有属于 systemd 的日志内容 —— 当我写这篇时是 109183 行。这是一个需要整理的大量数据。你可以使用页面的搜索功能,通常是 less 或者你可以使用内置的 grep 特性。-g( 或 --grep=)选项可以使用兼容 Perl 的正则表达式。

[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
[root@testvm1 ~]# journalctl -b -t systemd -g "hello"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:01:01 EDT. --
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
[root@testvm1 ~]#

你可以使用标准的 GNU grep 命令,但是这不会展示日志首行的元数据。

如果你只想看包含你的 hello 服务的日志记录,你可以指定时间来缩小范围。举个例子,我将在我的测试虚拟机上以 10:54:00 为开始时间,这是上述的日志记录开始的分钟数。注意 --since= 的选项必须加引号,这个选项也可以写成 -S "某个时间"

日期和时间可能在你的机器上有所不同,所以确保使用能匹配你日志中的时间的时间戳。

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:00"
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=54 op=LOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd"'
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/"'
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <error> [1589122560.0633] dhcp4 (enp0s3): error -113 dispatching events
May 10 10:56:00 testvm1.both.org NetworkManager[840]: <info>  [1589122560.0634] dhcp4 (enp0s3): state changed bound -> fail
<剪去>

since 选项跳过了指定时间点的所有记录,但在此时间点之后仍有大量你不需要的记录。你也可以使用 until 选项来裁剪掉你感兴趣的时间之后的记录。我想要事件发生时附近的一分钟,其他的都不用:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:04:59 EDT. --
May 10 10:54:35 testvm1.both.org systemd[1]: Reloading.
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=27 op=UNLOAD
May 10 10:54:35 testvm1.both.org audit: BPF prog-id=26 op=UNLOAD
<剪去>
ay 10 10:54:35 testvm1.both.org audit: BPF prog-id=55 op=LOAD
May 10 10:54:45 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:54:45 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>
May 10 10:54:45 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
lines 1-46/46 (END)

如果在这个时间段中仍然有大量的活动的话,你可以使用这些选项组合来进一步缩小结果数据流:

[root@testvm1 ~]# journalctl --since="2020-05-10 10:54:35" --until="2020-05-10 10:55:00" -t "hello.sh"
-- Logs begin at Tue 2020-05-05 18:11:49 EDT, end at Sun 2020-05-10 11:10:41 EDT. --
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ######### Hello World! ########
May 10 10:54:45 testvm1.both.org hello.sh[1380]: ###############################
[root@testvm1 ~]#

你的结果应该与我的相似。你可以从这一系列的实验中看出,这个服务运行的很正常。

重启 —— 还是走到这一步

到目前为止,你还没有重启过安装了服务的机器。所以现在重启吧,因为毕竟这个教程是关于启动阶段程序运行的情况。首先,你需要在启动序列中启用这个服务。

[root@testvm1 ~]# systemctl enable hello.service
Created symlink /etc/systemd/system/multi-user.target.wants/hello.service → /etc/systemd/system/hello.service.
[root@testvm1 ~]#

注意到这个软链接是被创建在 /etc/systemd/system/multi-user.target.wants 目录下的。这是因为服务单元文件指定了服务是被 multi-user.target 所“需要”的。

重启机器,确保能在启动阶段观察数据流,这样你能看到 “Hello world” 信息。等等……你看见了么?嗯,我看见了。尽管它很快被刷过去了,但是我确实看到 systemd 的信息显示它启动了 hello.service 服务。

看看上次系统启动后的日志。你可以使用页面搜索工具 less 来找到 “Hello” 或 “hello”。我裁剪了很多数据,但是留下了附近的日志记录,这样你就能感受到和你服务有关的日志记录在本地是什么样子的:

[root@testvm1 ~]# journalctl -b
<剪去>
May 10 10:37:49 testvm1.both.org systemd[1]: Listening on SSSD Kerberos Cache Manager responder socket.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Sockets.
May 10 10:37:49 testvm1.both.org systemd[1]: Reached target Basic System.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Modem Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Network Manager...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Avahi mDNS/DNS-SD Stack...
May 10 10:37:49 testvm1.both.org systemd[1]: Condition check resulted in Secure Boot DBX (blacklist) updater being skipped.
May 10 10:37:49 testvm1.both.org systemd[1]: Starting My hello shell script...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
May 10 10:37:49 testvm1.both.org systemd[1]: Started irqbalance daemon.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=irqbalance comm="systemd" exe="/usr/lib/sy>"'
May 10 10:37:49 testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Starting Hardware Monitoring Sensors...
<剪去>
May 10 10:37:49 testvm1.both.org systemd[1]: Starting NTP client/server...
May 10 10:37:49 testvm1.both.org systemd[1]: Starting SYSV: Late init script for live image....
May 10 10:37:49 testvm1.both.org systemd[1]: Started SYSV: Late init script for live image..
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=livesys-late comm="systemd" exe="/usr/lib/>"'
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org hello.sh[842]: ######### Hello World! ########
May 10 10:37:49 testvm1.both.org hello.sh[842]: ###############################
May 10 10:37:49 testvm1.both.org systemd[1]: hello.service: Succeeded.
May 10 10:37:49 testvm1.both.org systemd[1]: Finished My hello shell script.
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd>"'
May 10 10:37:49 testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/>
May 10 10:37:50 testvm1.both.org audit: BPF prog-id=28 op=LOAD
<剪去>

你可以看到 systemd 启动了 hello.service 单元,它执行了 hello.sh 脚本并将输出记录在日志中。如果你能在启动阶段抓到它,你也应该能看见,systemd 信息表明了它正在启动这个脚本,另外一条信息表明了服务成功。通过观察上面数据流中第一条 systemd 消息,你会发现 systemd 在到达基本的系统目标后很快就启动了你的服务。

但是我想看见信息在启动阶段也被打印出来。有一种方法可以做到:在 hello.service 文件的 [Service] 段中加入下述行:

StandardOutput=journal+console

现在 hello.service 文件看起来像这样:

# Simple service unit file to use for testing
# startup configurations with systemd.
# By David Both
# Licensed under GPL V2
#

[Unit]
Description=My hello shell script

[Service]
Type=oneshot
ExecStart=/usr/local/bin/hello.sh
StandardOutput=journal+console

[Install]
WantedBy=multi-user.target

加上这一行后,重启系统,并在启动过程中观察显示屏上滚动的数据流。你应该在它的小方框中看到信息。在启动序列完成后,你可以查看最近的启动日志,然后定位到你新服务的日志记录。

修改次序

现在你的服务已经可用了,你可以看看它在启动序列中哪个位置启动的,尝试下修改它。需要牢记的是 systemd 倾向于在每个主要目标(basic.targetmulti-user.targetgraphical.**target)中并行启动尽可能多的服务和其他的单元类型。你应该刚刚看过最近一次开机的日志记录,它应该和上面我的日志看上去类似。

注意,systemd 在它到达到基本系统目标(basic.target)后不久就启动了你的测试服务。这正是你在在服务单元文件的 WantedBy 行中指定的,所以它是对的。在你做出修改之前,列出 /etc/systemd/system/multi-user.target.wants 目录下的内容,你会看到一个指向服务单元文件的软链接。服务单元文件的 [Install] 段指定了哪一个目标会启动这个服务,执行 systemctl enable hello.service 命令会在适当的 targets.wants 路径下创建软链接。

hello.service -> /etc/systemd/system/hello.service

某些服务需要在 basic.target 阶段启动,其他则没这个必要,除非系统正在启动 graphical.target。这个实验中的服务不会在 basic.target 期间启动 —— 假设你直到 graphical.target 阶段才需要它启动。那么修改 WantedBy 这一行:

WantedBy=graphical.target

一定要先禁用 hello.service 再重新启用它,这样可以删除旧链接并且在 graphical.targets.wants 目录下创建一个新的链接。我注意到如果我在修改服务需要的目标之前忘记禁用该服务,我可以运行 systemctl disable 命令,链接将从两个 targets.wants 目录中删除。之后我只需要重新启用这个服务然后重启电脑。

启动 graphical.target 下的服务有个需要注意的地方,如果电脑启动到 multi-user.target 阶段,这个服务不会自动启动。如果这个服务需要 GUI 桌面接口,这或许是你想要的,但是它同样可能不是你想要的。

-o short-monotonic 选项来查看 graphical.targetmulti-user.target 的日志,展示内核启动几秒后的日志,精度为微秒级别:

[root@testvm1 ~]# journalctl -b -o short-monotonic

multi-user.target 的部分日志:

[   17.264730] testvm1.both.org systemd[1]: Starting My hello shell script...
[   17.265561] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<剪去>
[   19.478468] testvm1.both.org systemd[1]: Starting LSB: Init script for live image....
[   19.507359] testvm1.both.org iptables.init[844]: iptables: Applying firewall rules: [  OK  ]
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
[   19.507835] testvm1.both.org hello.sh[843]: ######### Hello World! ########
[   19.507835] testvm1.both.org hello.sh[843]: ###############################
<剪去>
[   21.482481] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   21.482550] testvm1.both.org smartd[856]: Opened configuration file /etc/smartmontools/smartd.conf
[   21.482605] testvm1.both.org systemd[1]: Finished My hello shell script.

还有部分 graphical.target 的日志:

[   19.436815] testvm1.both.org systemd[1]: Starting My hello shell script...
[   19.437070] testvm1.both.org systemd[1]: Starting IPv4 firewall with iptables...
<剪去>
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.612614] testvm1.both.org hello.sh[841]: ######### Hello World! ########
[   19.612614] testvm1.both.org hello.sh[841]: ###############################
[   19.629455] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629569] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   19.629682] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   19.629782] testvm1.both.org systemd[1]: Finished My hello shell script.

尽管单元文件的 WantedBy 部分包含了 graphical.targethello.service 单元在启动后大约 19.5 或 19.6 秒后运行。但是 hello.servicemulti-user.target 中开始于 17.24 秒,在 graphical target 中开始于 19.43 秒。

这意味着什么呢?看看 /etc/systemd/system/default.target 这个链接。文件内容显示 systemd 先启动了默认目标 graphical.target,然后 graphical.target 触发了 multi-user.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 还是 multi-user.target 启动服务,hello.service 单元都在启动后的 19.5 或 19.6 秒后启动。基于这个事实和日志结果(特别是使用单调输出的日志),你就知道这些目标是在并行启动。再看看日志中另外一件事:

[   28.397330] testvm1.both.org systemd[1]: Reached target Multi-User System.
[   28.397431] testvm1.both.org systemd[1]: Reached target Graphical Interface.

两个目标几乎是同时完成的。这是和理论一致的,因为 graphical.target 触发了 multi-user.target,在 multi-user.target 到达(即完成)之前它是不会完成的。但是 hello.service 比这个完成的早的多。

这一切表明,这两个目标几乎是并行启动的。如果你查看日志,你会发现各种目标和来自这类主要目标的服务大多是平行启动的。很明显,multi-user.target 没有必要在 graphical.target 启动前完成。所以,简单的使用这些主要目标来并不能很好地排序启动序列,尽管它在保证单元只在它们被 graphical.target 需要时启动这方面很有用。

在继续之前,把 hello.service 单元文件回滚至 WantedBy=multi-user.target(如果还没做的话)。

确保一个服务在网络运行后启动

一个常见的启动问题是保证一个单元在网络启动运行后再启动。Freedesktop.org 的文章《在网络启动后运行服务》中提到,目前没有一个真正的关于网络何时算作“启动”的共识。然而,这篇文章提供了三个选项,满足完全可用网络需求的是 network-online.target。需要注意的是 network.target 是在关机阶段使用的而不是启动阶段,所以它对你做有序启动方面没什么帮助。

在做出任何改变之前,一定要检查下日志,确认 hello.service 单元在网络可用之前可以正确启动。你可以在日志中查找 network-online.target 来确认。

你的服务并不真的需要网络服务,但是你可以把它当作是需要网络的。

因为设置 WantedBy=graphical.target 并不能保证服务会在网络启动可用后启动,所以你需要其他的方法来做到这一点。幸运的是,有个简单的方法可以做到。将下面两行代码加入 hello.service 单元文件的 [Unit] 段:

After=network-online.target                                                                            
Wants=network-online.target

两个字段都需要才能生效。重启机器,在日志中找到服务的记录:

[   26.083121] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0293] device (enp0s3): Activation: successful, device activated.
[   26.083349] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0301] manager: NetworkManager state is now CONNECTED_GLOBAL
[   26.085818] testvm1.both.org NetworkManager[842]: <info>  [1589227764.0331] manager: startup complete
[   26.089911] testvm1.both.org systemd[1]: Finished Network Manager Wait Online.
[   26.090254] testvm1.both.org systemd[1]: Reached target Network is Online.
[   26.090399] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=NetworkManager-wait-online comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? termina>"'
[   26.091991] testvm1.both.org systemd[1]: Starting My hello shell script...
[   26.095864] testvm1.both.org sssd[be[implicit_files]][1007]: Starting up
[   26.290539] testvm1.both.org systemd[1]: Condition check resulted in Login and scanning of iSCSI devices being skipped.
[   26.291075] testvm1.both.org systemd[1]: Reached target Remote File Systems (Pre).
[   26.291154] testvm1.both.org systemd[1]: Reached target Remote File Systems.
[   26.292671] testvm1.both.org systemd[1]: Starting Notify NFS peers of a restart...
[   26.294897] testvm1.both.org systemd[1]: iscsi.service: Unit cannot be reloaded because it is inactive.
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.304682] testvm1.both.org hello.sh[1010]: ######### Hello World! ########
[   26.304682] testvm1.both.org hello.sh[1010]: ###############################
[   26.306569] testvm1.both.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306669] testvm1.both.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=hello comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[   26.306772] testvm1.both.org systemd[1]: hello.service: Succeeded.
[   26.306862] testvm1.both.org systemd[1]: Finished My hello shell script.
[   26.584966] testvm1.both.org sm-notify[1011]: Version 2.4.3 starting

这样证实了 hello.service 单元会在 network-online.target 之后启动。这正是你想要的。你可能也看见了 “Hello World” 消息在启动阶段出现。还需要注意的是,在启动时记录出现的时间戳比之前要晚了大约 6 秒。

定义启动序列的最好方法

本文章详细地探讨了 Linux 启动时 systemd 和单元文件以及日志的细节,并且发现了当错误被引入单元文件时候会发生什么。作为系统管理员,我发现这类实验有助于我理解程序或者服务出故障时的行为,并且在安全环境中有意破坏是一种学习的好方法。

文章中实验结果证明,仅将服务单元添加至 multi-user.target 或者 graphical.target 并不能确定它在启动序列中的位置。它仅仅决定了一个单元是否作为图形环境一部分启动。事实上,启动目标 multi-user.targetgraphical.target 和所有它们的 Wants 以及 Required 几乎是并行启动的。确保单元在特定位置启动的最好方法是确定它所依赖的单元,并将新单元配置成 WantAfter 它的依赖。

资源

网上有大量的关于 systemd 的参考资料,但是大部分都有点简略、晦涩甚至有误导性。除了本文中提到的资料,下列的网页提供了跟多可靠且详细的 systemd 入门信息。

Fedora 项目有一篇切实好用的 systemd 入门,它囊括了几乎所有你需要知道的关于如何使用 systemd 配置、管理和维护 Fedora 计算机的信息。

Fedora 项目也有一个不错的 备忘录,交叉引用了过去 SystemV 命令和 systemd 命令做对比。

关于 systemd 的技术细节和创建这个项目的原因,请查看 Freedesktop.org 上的 systemd 描述。

Linux.com 的“更多 systemd 的乐趣”栏目提供了更多高级的 systemd 信息和技巧。

此外,还有一系列深度的技术文章,是由 systemd 的设计者和主要开发者 Lennart Poettering 为 Linux 系统管理员撰写的。这些文章写于 2010 年 4 月至 2011 年 9 月间,但它们现在和当时一样具有现实意义。关于 systemd 及其生态的许多其他好文章都是基于这些文章:


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

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

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