Linux systemd服务详解(新手必看)
systemd 最初是一个 init 系统,是 initd 的替代品,但现在它是一个功能强大的主管,包括日志记录、网络配置和网络时间同步等功能。它提供了一种灵活、可移植的方式来定义守护进程及其依赖项,并提供了一个统一的接口来控制配置。
几乎所有当前的 Linux 发行版都在使用 systemd,包括自 2011 年 5 月起的 Fedora、自 2012 年 9 月起的 openSUSE、自 2014 年 4 月起的 CentOS、自 2014 年 6 月起的 RHEL、自 2014 年 10 月起的 SUSE Linux、自 2015 年 4 月起的 Debian 和 Ubuntu。
特别是,systemd 通过执行以下操作解决了以前 init 系统的缺点:
此外,init 在初始化时按顺序(即按字母数字顺序)启动服务,而 systemd 可以启动任何满足其依赖项的服务,从而有可能加快启动时间。
我们可以通过单元来告诉 systemd 运行什么、何时运行、如何运行。
systemd:根据目标资源区分多个单元:
其他不太重要的单元类型包括以下内容:
为了被 systemd 所知晓,一个单元需要被序列化为一个文件。systemd 在多个位置寻找单元文件。最重要的三个文件路径如下:
定义了 systemd 的基本工作单元(不是双关语)后,让我们继续讨论如何通过命令行控制它。
请注意,systemctl 提供的命令还有很多,从管理和查询依赖项到控制整个系统(例如 reboot)。
systemd 生态系统还有一些其他的命令行工具,你可能会觉得很方便,至少应该了解一下。这包括但不限于以下内容:
说了这么多理论,让我们来看看 systemd 的运行情况。作为一个简单的用例,我们假设要每小时启动一次 greeter 程序。
首先,我们定义一个 service 类型的 systemd 单元文件。这将告诉 systemd 如何启动 greeter 程序,将以下内容保存在一个名为 greeter.service 的文件中(在任何目录下,可以是一个临时目录)。
接下来,我们定义一个定时器单元,每小时启动一次 greeter 服务。将以下内容存储在一个名为 greeter.timer 的文件中:
现在我们把这两个单元文件复制到 /run/systemd/system/,以便 systemd 能识别它们:
基于 Debian 的系统,如 Ubuntu,默认启用并启动服务单元。如果没有明确的 systemctl start greeter.timer,Red Hat 系统的系统就不会启动服务。在启动时启用服务也是如此,基于 Debian 的发行版默认启用服务,而 Red Hat 发行版需要以 systemctl enable 的形式明确确认。
让我们查看 greeter 计时器的状态:
几乎所有当前的 Linux 发行版都在使用 systemd,包括自 2011 年 5 月起的 Fedora、自 2012 年 9 月起的 openSUSE、自 2014 年 4 月起的 CentOS、自 2014 年 6 月起的 RHEL、自 2014 年 10 月起的 SUSE Linux、自 2015 年 4 月起的 Debian 和 Ubuntu。
特别是,systemd 通过执行以下操作解决了以前 init 系统的缺点:
- 提供统一的方式来管理跨发行版的启动;
- 实施更快、更易于理解的服务配置;
- 提供现代管理套件,包括监控、资源使用控制(通过 cgroups)和内置审计。
此外,init 在初始化时按顺序(即按字母数字顺序)启动服务,而 systemd 可以启动任何满足其依赖项的服务,从而有可能加快启动时间。
我们可以通过单元来告诉 systemd 运行什么、何时运行、如何运行。
Linux systemd 中的单元
systemd 中的单元是具有不同语义的逻辑分组,具体取决于其功能或其目标资源。systemd:根据目标资源区分多个单元:
- service 单元:描述如何管理服务或应用程序;
- target 单元:捕获依赖项;
- mount 单元:定义挂载点;
- timer 单元:为 cron 作业等定义定时器。
其他不太重要的单元类型包括以下内容:
- socket字:描述了一个网络或 IPC 套接字。
- device:用于 udev 或 sysfs 文件系统。
- automount:配置自动挂载点。
- swap:描述交换空间。
- path:用于基于路径的激活。
- snapshot:允许在变化后重建系统的当前状态。
- slice:与 cgroups 相关联。
- scope:管理外部创建的系统进程集。
为了被 systemd 所知晓,一个单元需要被序列化为一个文件。systemd 在多个位置寻找单元文件。最重要的三个文件路径如下:
- /lib/systemd/system:包中安装的单元;
- /etc/systemd/system:系统管理员配置的单元;
- /run/systemd/system:非持久性运行时修改。
定义了 systemd 的基本工作单元(不是双关语)后,让我们继续讨论如何通过命令行控制它。
使用systemctl进行管理
用于与 systemd 交互以管理服务的工具是 systemctl。在下表中,我整理了一份经常使用的 systemctl 命令列表。命令 | 用例 |
---|---|
systemctl enable XXXXX.service | 启用该服务,准备启动 |
systemctl daemon-reload | 重新加载所有单元文件,重新创建整个依赖项树 |
systemctl start XXXXX.service | 启动该服务 |
systemctl stop XXXXX.service | 停止该服务 |
systemctl restart XXXXX.service | 停止然后启动该服务 |
systemctl reload XXXXX.service | 向服务发出 reload 命令,然后回到 restart 状态 |
systemctl kill XXXXX.service | 停止服务的执行 |
systemctl status XXXXX.service | 获取服务状态的简短摘要,包括一些日志 |
请注意,systemctl 提供的命令还有很多,从管理和查询依赖项到控制整个系统(例如 reboot)。
systemd 生态系统还有一些其他的命令行工具,你可能会觉得很方便,至少应该了解一下。这包括但不限于以下内容:
- bootctl:允许你检查引导加载程序状态并管理可用的引导加载程序;
- timedatectl:允许你设置和查看与时间和日期有关的信息;
- coredumpctl:使你能够处理已保存的核心转储。在你进行故障排除时可以考虑这个工具。
说了这么多理论,让我们来看看 systemd 的运行情况。作为一个简单的用例,我们假设要每小时启动一次 greeter 程序。
首先,我们定义一个 service 类型的 systemd 单元文件。这将告诉 systemd 如何启动 greeter 程序,将以下内容保存在一个名为 greeter.service 的文件中(在任何目录下,可以是一个临时目录)。
[Unit] Description=My Greeting Service ① [Service] Type=oneshot ExecStart=/home/mh9/greeter.sh ②
- ① 我们服务的描述,在使用 systemctl status 时显示。
- ② 我们的应用程序的位置。
接下来,我们定义一个定时器单元,每小时启动一次 greeter 服务。将以下内容存储在一个名为 greeter.timer 的文件中:
[Unit] Description=Runs Greeting service at the top of the hour [Timer] OnCalendar=hourly ①① 使用 systemd 的时间和日期格式定义时间表。
现在我们把这两个单元文件复制到 /run/systemd/system/,以便 systemd 能识别它们:
$ sudo ls -al /run/systemd/system/ total 8 drwxr-xr-x 2 root root 80 Sep 12 13:08 . drwxr-xr-x 21 root root 500 Sep 12 13:09 .. -rw-r--r-- 1 root root 117 Sep 12 13:08 greeter.service -rw-r--r-- 1 root root 107 Sep 12 13:08 greeter.timer我们现在可以使用 greeter 计时器了,因为 systemd 在我们计时器复制到相应的目录中时自动把它拿了出来。
基于 Debian 的系统,如 Ubuntu,默认启用并启动服务单元。如果没有明确的 systemctl start greeter.timer,Red Hat 系统的系统就不会启动服务。在启动时启用服务也是如此,基于 Debian 的发行版默认启用服务,而 Red Hat 发行版需要以 systemctl enable 的形式明确确认。
让我们查看 greeter 计时器的状态:
$ sudo systemctl status greeter.timer ● greeter.timer - Runs Greeting service at the top of the hour loaded (/run/systemd/system/greeter.timer; static; \ vendor preset: enabled) Active: active (waiting) since Sun 2021-09-12 13:10:35 IST; 2s ago Trigger: Sun 2021-09-12 14:00:00 IST; 49min left Sep 12 13:10:35 starlite systemd[1]: \ Started Runs Greeting service at the top of the hour.所以 systemd 确认它知道我们的 greeter,并且已经安排了运行。但你怎么知道它是否成功了呢?让我们检查一下日志(注意,输出被编辑了,stdout 输出直接进入日志):
$ journalctl -f -u greeter.service ① -- Logs begin at Sun 2021-01-24 14:36:30 GMT. -- Sep 12 14:00:01 starlite systemd[1]: Starting My Greeting Service... Sep 12 14:00:01 starlite greeter.sh[21071]: You are awesome! ...① 使用 journalctl 查看并跟踪(-f)greeter.service 单元的日志(用 -u 选择)。