如何在RHEL/CentOS 7上自动启动服务?
想知道如何在后台或开机时管理服务?
管理和启动进程的机制已经改变。在RHEL/CentOS 6.x之前,你需要在/etc/init.d/目录下创建一个脚本,并使用chkconfig
命令来启用,但在RHEL 7上情况有所不同。
它被systemd
取代了。由于它在主要Linux版本上基本上是默认的进程管理器,熟悉其他发行版的人会感到非常亲切。在本文中,我们将探讨systemd
是什么,为什么要进行切换,以及如何使用systemd
来设置、运行和管理后台进程。
systemd是什么?
由于Linux中的每个进程都是透明可见的,让我们看看systemd
隐藏在哪里。在我的系统上,我得到了以下输出:
~$ ps -ef | grep systemd root 1 0 0 Nov11 ? 00:01:02 /lib/systemd/systemd --system --deserialize 22 message+ 768 1 0 Nov11 ? 00:05:46 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only root 805 1 0 Nov11 ? 00:10:22 /lib/systemd/systemd-logind ankush 1132 1 0 Nov11 ? 00:00:00 /lib/systemd/systemd --user ankush 1176 1132 0 Nov11 ? 00:04:50 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only ankush 9772 20029 0 21:11 pts/6 00:00:00 grep --color=auto systemd systemd+ 17298 1 0 Nov19 ? 00:00:12 /lib/systemd/systemd-resolved systemd+ 17303 1 0 Nov19 ? 00:00:00 /lib/systemd/systemd-timesyncd root 17307 1 0 Nov19 ? 00:00:02 /lib/systemd/systemd-journald root 18182 1 0 Nov19 ? 00:00:00 /lib/systemd/systemd-udevd
我敢打赌你立刻注意到了它。列表中的第一个进程是以用户root
启动的,进程ID为1。
毫无疑问,这是系统在启动时启动的第一个进程。欢迎来到systemd
。🙂
所以,简单来说,systemd
是在系统中启动、管理和终止其他进程的“母”进程,同时提供有关它们的日志、文件系统状态等信息。
不过,关于名称的说明。名称确实是systemd
,而不是System D或其他任何名称。这里的“d”代表daemon,即一个标准的Linux进程,它在后台运行而不附加到任何终端会话。
RHEL为什么切换到systemd?
正如我们已经讨论过的,systemd是一个系统和进程管理器,在RHEL 7中取代了著名的Upstart程序。为什么RHEL做出了这个决定?嗯,有很好的理由,让我们快速看一下。
并行服务初始化
与SysV的init
程序不同,systemd
能够并行启动服务。相比之下,init
程序是一个一个地启动它们的。在如今甚至移动设备都拥有多核CPU的时代,缺乏并行初始化是一个巨大的缺点。
动态(热)服务管理
如果你注意到之前的Fedora系统上需要显式挂载USB驱动器,而在Ubuntu和类似的发行版上它们会自动弹出,原因就是systemd
。它能够检测到硬件的实时变化,并根据需要终止/启动服务。有人可能会说这是不必要的,但对于许多人来说,减少认知负担的事情是非常受欢迎的。
延迟服务启动
systemd
使启动时间更短,因为它能够将服务的启动推迟到真正需要的时候。一个简单的例子是与网络文件系统相关的服务。如果没有可用的网络磁盘,启动和运行服务就没有意义。
更快的进程通信
systemd
的并行能力可以延伸到进程间通信。 systemd
能够并行访问套接字和系统总线,从而显著减少进程等待通信资源的时间。
自动重启
如果服务崩溃,systemd
可以检测到并尝试重新启动它。大多数情况下,只需要简单地重新启动应用程序,即可使其再次正常运行,除非存在更基本的问题。
无论如何,systemd
在这方面使系统管理员的工作更轻松。
RHEL7中的systemd-系统管理员有什么变化?
如果你有一种强烈的感觉,认为systemd
不会带来一切的便利,那么你是对的。有一些重要的不兼容性可能会让RHEL系统管理员感到意外。让我们来快速看一下。
有限的运行级别支持
systemd
对运行级别的识别和支持相当差劲。并非所有的运行级别都受支持,对于某些目标甚至可能没有任何运行级别。在这种情况下,systemd
对runlevel
命令的回应是“N”,表示它没有与该目标对应的运行级别。总的来说,Red Hat建议我们不要使用runlevel
命令。
没有自定义命令
这一点可能会让人感到困扰。SysV的一个重要优点是能够定义自定义命令,以提供更好的进程管理功能。而在systemd
中,没有这样的选项,只能使用start
、stop
、status
、restart
等命令。
仅限家族和非交互式
systemd
(当然)会跟踪它启动的进程并存储它们的PID。然而,挑战在于systemd
无法处理它没有启动的进程。此外,用户无法与由systemd
启动的进程进行交互。所有输出都会被重定向到/dev/null
,有效地阻止了你可能希望捕获输出的任何希望。
没有上下文
与init
服务不同,由systemd
启动的服务不会继承系统中任何用户的环境。换句话说,像PATH
和其他系统变量这样的信息是不可用的,每个新进程都在空的上下文中启动。
如果这个限制列表让你难过,那么你并不孤单。 systemd
在Linux世界中一直是一个有争议的力量,搜索“systemd sucks”会找到大量的阅读材料。
如何在服务停止时自动启动服务?
这是一个在部署中非常常见的用例。我们需要将一个没有长时间运行过程的程序守护化:PHP!假设我编写了一个处理传入的websocket连接的PHP脚本(毕竟我们构建了一个聊天应用),并将该脚本放置在/home/ankush/chat_server/index.php
。
由于websocket连接可以随时连接服务器,所以这个进程需要始终处于运行状态并监控传入的连接。我们无法使用传统的PHP生命周期,因为WebSockets是有状态的连接,如果脚本停止运行,连接也会断开。总之,关于WebSockets的内容就这么多,现在让我们看看如何通过systemd
将此脚本守护化。
所有的systemd
服务都位于/etc/systemd/system目录中,因此让我们在那里创建一个文件来描述我们的websocket服务器脚本。假设你以root用户身份登录。
# vi /etc/systemd/system/chat_server.service
然后需要添加以下内容。
保存该文件,下一步是重新加载systemd守护进程。
# systemctl daemon-reload
然后启动我们刚刚创建的服务:
# systemctl start chat_server
如果没有出现错误,就完成了!
让我们快速看一下文件中各个指令的含义:
– [Unit] 部分定义了一个新的systemd服务单元。在systemd的术语中,所有服务都被称为服务单元。
– After指令(预测)告诉systemd仅在网络服务启动后才启动该服务(否则,谁来处理低层的套接字连接?!)。
– Type=simple告诉systemd该服务不会分叉。换句话说,任何时候只会运行一个实例。
– User=ankush表示该服务将以用户“ankush”的身份运行。我们可以将其更改为“root”,但从安全的角度来看,这是非常不推荐的。
– ExecStart,正如你所看到的,是实际要运行的命令。
– Restart=on-abort表示该服务在中止时应重新启动。在PHP中,长时间运行的进程会泄露内存并最终崩溃,所以这是必需的。
– WantedBy指令告诉systemd该服务是哪个目标(类似于组)的一部分。这会导致在该目标内创建指向该服务的符号链接。
通常,使用systemd在RHEL 7中运行后台进程就足够了。
重新启动逻辑的更多选项
在上面的示例中,我配置了Restart=on-abort,但这并不是唯一的选项。还有更多选项,可以根据需求进行选择。
– on-failure – 在出现非正常退出代码或信号时重新启动
– always – 在发现服务停止时,无论是否为正常或非正常信号,都会重新启动
– on-abnormal – 非正常信号、看门狗或超时
– on-success – 仅在服务被干净的信号或退出代码停止时重新启动
配置服务在启动时启动
一旦你对脚本满意并确保它正常工作,下一步就是配置它在启动时触发并启动。
进入/etc/systemd/system并执行以下启用命令(不要忘记将.service文件名更改为你自己的)。
# systemctl enable chat_server.service
你会看到一个确认消息,说明它已经创建了一个符号链接。
Created symlink from /etc/systemd/system/multi-user.target.wants/chat_server.service to /etc/systemd/system/chat_server.service.
重新启动服务器,你应该看到服务在启动时启动。
这很简单!不是吗?
帮助!我对Upstart非常投入。 🙁
我知道你相信我,你的情况是正常的而不是例外。RHEL长时间使用Upstart,因此转换几乎感觉像是一种背叛。但是嘿,系统一直在变化,我们不应为琐事而争吵。Red Hat认识到许多人还停留在旧版本上,并创建了一个链接_3,你一定要参考一下。
在所有这些中唯一的拯救之处是,systemd与SysV init脚本兼容,因此在大多数情况下,你只需要移动文件并获得相同的服务运行。
有兴趣了解更多关于Linux管理和故障排除的知识吗?查看这个链接_4。