没有人会真的认为 systemd 是故障排除工具,但是当我在我的 Web 服务器上遇到问题时,我对 systemd 及其某些功能不断增长的了解帮助我定位并规避了问题。
问题是我的服务器 yorktown,它为我的家庭办公室网络提供名称服务、DHCP、NTP、HTTPD 和 SendMail 电子邮件服务,在正常启动期间未能启动 Apache HTTPD 守护程序。在我意识到它没有运行时,我不得不手动启动它。这个问题已经持续了一段时间,最近我才开始尝试修复它。
你们中的一些人会说 systemd 本身就是这个问题的原因,根据我现在所知道的,我同意你的看法。但是,我在 SystemV 中也遇到过类似类型的问题。(在本系列的第一篇文章中,我研究了围绕 systemd 作为旧的 SystemV init 程序和启动脚本的替代品的争议。如果您有兴趣了解更多关于 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 ~]#
此状态信息是我发现比 SystemV 提供的任何功能更有用的 systemd 功能之一。此处提供的大量有用的信息很容易引导我得出合乎逻辑的结论,从而使我朝着正确的方向前进。我从旧的 chkconfig 命令中获得的只是服务是否正在运行以及进程 ID (PID)(如果正在运行)。这并没有多大帮助。
此状态报告中的关键条目显示 HTTPD 无法绑定到 IP 地址,这意味着它无法接受传入的请求。这表明网络启动速度不够快,无法为 HTTPD 服务绑定到 IP 地址做好准备,因为 IP 地址尚未设置。这本不应该发生,因此我检查了我的网络服务 systemd 启动配置文件;所有文件看起来都是正确的,具有正确的“after”和“requires”语句。这是我的服务器上的 /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.target 和 httpd-init.service(以及其他服务)之后加载。我尝试使用 systemctl list-units 命令查找所有这些服务,并在结果数据流中搜索它们。所有服务都存在,并且应该确保 httpd 服务在网络 IP 地址设置之前不会加载。
第一种解决方案
在互联网上搜索了一下后,证实其他人也遇到了与 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.
我可以尝试看看更短的延迟是否也能起作用,但我的系统并没有那么关键,所以我决定不这样做。它现在可以可靠地工作,所以我很满意。
因为我收集了所有这些信息,所以我将其报告给 Red Hat Bugzilla,错误编号为 1825554。我认为报告错误比抱怨它们更有成效。
更好的解决方案
在将此问题报告为错误后的几天,我收到了回复,指出 systemd 只是管理器,如果 httpd 需要在满足某些要求后排序,则需要在单元文件中表达。回复将我指向了 httpd.service 手册页。我希望我能早点找到它,因为它比我想出的解决方案更好。此解决方案明确针对先决条件目标单元,而不是有点随机的延迟。
在启动时启动服务
默认情况下,httpd.service 和 httpd.socket 单元是禁用的。要在启动时启动 httpd 服务,请运行:systemctl enable httpd.service。在默认配置中,httpd 守护程序将接受端口 80 上的连接(如果安装了 mod_ssl,则接受端口 443 上的 TLS 连接),用于任何配置的 IPv4 或 IPv6 地址。
如果 httpd 配置为依赖于任何特定的 IP 地址(例如,使用“Listen”指令),该地址可能仅在启动期间可用,或者如果 httpd 依赖于其他服务(例如数据库守护程序),则必须配置该服务以确保正确的启动顺序。
例如,为了确保 httpd 仅在配置所有配置的网络接口后运行,请创建一个包含以下部分的 drop-in 文件(如上所述)
[Unit]
After=network-online.target
Wants=network-online.target
我仍然认为这是一个错误,因为它很常见——至少在我的经验中——在 httpd.conf 配置文件中使用 Listen 指令。我一直使用 Listen 指令,即使在只有一个 IP 地址的主机上也是如此,并且在具有多个网络接口卡 (NIC) 和互联网协议 (IP) 地址的主机上显然是必要的。将上述行添加到 /usr/lib/systemd/system/httpd.service 默认文件不会对不使用 Listen 指令的配置造成问题,并且可以防止那些使用 Listen 指令的配置出现此问题。
在此期间,我将使用建议的解决方案。
后续步骤
本文介绍了我在服务器上启动 Apache HTTPD 服务时遇到的问题。它引导您了解我采取的问题确定步骤,并展示了我如何使用 systemd 来提供帮助。我还介绍了我使用 systemd 实施的规避方法以及从我的错误报告中获得的更好的解决方案。
正如我在开始时提到的,这很可能是 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 信息和技巧。
Lennart Poettering(systemd 的设计者和主要开发者)还为 Linux 系统管理员编写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在仍然和当时一样具有现实意义。关于 systemd 及其生态系统的大部分优秀著作都基于这些论文。
2 条评论