《一篇搞懂》系列之三——systemd

对电脑稍微懂一点的人都知道,我们平时打开的软件也好,后台运行的服务也好,其最终都是以进程的方式运行在操作系统中。那么,不知各位是否想过这样的问题:“是什么在管理进程?系统启动后,第一个启动的进程是什么?”。

事实上,在Linux操作系统中,当系统启动成功后,init daemon是第一个运行的进程(PID=1),init daemon会以守护进程(daemon)的方式一直在系统中运行,直至系统关机。init daemon将作为系统中所有进程的父进程,操作系统首先运行init daemon,然后由init daemon来管理后续的系统启动程序。

拿CentOS为例,现在的CentOS系统一般都以systemd架构来实现init daemon,而在此之前,一般都以Init架构来实现init daemon。本文将站在介绍systemd的角度来介绍init daemonInit架构以及systemd架构的基本知识。

一、Init Daemon

1.1 Init Daemon是什么?

在文章的开头提到了一个init daemon,这个名词在Linux系统中并不代表着某一个工具(例如lscd)或者某一个服务(例如sshd),而是代表着Linux系统启动时的第一个进程。这个进程有如下的特点:

  • 由内核启动,且进程号为1(PID=1);
  • 具备初始化、管理以及追踪系统中服务的能力;
  • 系统中所有进程的父进程。

在Linux发展历史上有两套架构是能够提供init daemon的功能的:

  • Init架构,也被称为System V Init,或者SysVinit。
  • systemd架构,即system daemon。

1.2 浅谈系统开机流程

有句古话说得好:来都来了,不唠两句怎么行。既然已经谈到了系统开机方面的事情,那么就在这里简单聊一聊Linux系统的启动流程。Linux系统启动主要分为下面三个流程:

  1. 硬件引导(Hardware Boot):这部分由主板BIOS控制完成,加载操作系统等一系列工作。
  2. Linux操作系统引导(Linux Boot):加载Linux内核,加载完成后启动init daemon。
  3. Linux操作系统启动(Linux Startup):由init daemon管理开机后服务管理事项。

硬件引导中会涉及到系统指令和机器语言,所以一般会单独作介绍。大致了解一下一个总体的流程就好,这里也不会深入研究。

Linux系统启动引导流程

二、Init架构

在CentOS 6的系统中,如果要重启网络服务,我们一般会通过这样的命令去完成:

[root@localhost ~]# service network restart

上面的命令中,service命令就是Init架构(也称作为System V Init,或者SysVinit,或者System V)提供给系统管理员使用的,该命令可以用来管理Linux系统中的相关服务,控制其启动,关闭等行为。

2.1 系统运行级别

Init架构为系统提供了7个级别,分别如下:

  • 0:Shutdown:关机
  • 1:Single User Mode:单用户模式
  • 2:Multiuser mode without networking:离线多用户模式
  • 3:Multiuser mode with networking:联网多用户模式
  • 4:Unused:保留
  • 5:Multiuser mode with networking and GUI:带图形化界面的联网多用户模式
  • 6:Reboot:重启

至于使用哪种方式来启动系统则需要用到/etc/inittab文件。/etc/inittab文件是Init架构在启动init daemon时读取的第一个文件,这个文件中定义了系统初始化的相关配置,其中就包括使用哪个级别启动系统。比如下面的这一条指令就意味着:系统将采用联网多用户模式启动:

id:3:initdefault:

2.2 /etc/rc.d

还记得前面介绍Init架构的时候用的命令嘛?

[root@localhost ~]# service network restart

这个命令可以将网络服务重启,那么问题来了,为什么网络服务就叫network呢?为啥不叫network-service这种名字?我在哪能找到这个服务的管理脚本文件?怎样能让系统启动的时候就启动network服务呢(即开机自启)?对于这些问题,都可以从/etc/rc.d目录中获得答案。

2.2.1 /etc/rc.d/init.d

/etc/rc.d/init.d目录下存放了能够通过service命令管理的所有服务,也就是说,当你的服务管理脚本编写好后,将它移到/etc/rc.d/init.d目录下就可以通过service命令来管理了,就像我们一直用来举例的network服务。在CentOS 7系统下,它存在于/etc/rc.d/init.d目录下。

[root@localhost init.d]# pwd
/etc/rc.d/init.d
[root@localhost init.d]# ls
functions  netconsole  network  README

其文件内容大致如下:

#! /bin/bash

# SOME CODES

case "$1" in
start)
    # START LOGIC
stop)
    # STOP LOGIC
restart|force-reload)
    # RESTART LOGIC
esac

可以看到,network服务的管理脚本中提供了startstop以及restart|force-reload的操作逻辑。这样的话,我们就可以通过service network start/stop/restart|force-reload来管理network服务了。

在CentOS 7系统中,还会存在一个/etc/init.d目录。这个目录其实是/etc/rc.d/init.d目录的软链接。因此也会看到一些直接用脚本管理服务的操作,比如/etc/init.d/network start

[root@localhost etc]# ls -l init.d
lrwxrwxrwx. 1 root root 11 424 2020 init.d -> rc.d/init.d

2.2.2 /etc/rc.d/rcX.d

/etc/rc.d/rcX.d这个写法是一个范围,它包含了/etc/rc.d/rc0.d - /etc/rc.d/rc6.d七个目录。相信聪明的你已经发现了:Init架构为系统提供的运行级别也是7个。那这一组目录的作用也就很容易理解了:当系统以对应的级别启动/关机时,Init架构会执行相应的那个级别目录下的脚本。这也是Init架构下相关服务开机自启需要用到的目录。下面是CentOS 7系统中,系统运行级别为3时涉及的相关脚本:

[root@localhost rc.d]# cd rc3.d/
[root@localhost rc3.d]# ls
K50netconsole  S10network
[root@localhost rc3.d]# ls -l
总用量 0
lrwxrwxrwx. 1 root root 20 424 2020 K50netconsole -> ../init.d/netconsole
lrwxrwxrwx. 1 root root 17 424 2020 S10network -> ../init.d/network

可以看到,当系统以级别3(联网多用户模式)启动/关机时,涉及到两个脚本文件:K50netconsoleS10network,且实际上这两个脚本文件是软链接到我们刚介绍完的/etc/rc.d/init.d目录下的脚本文件上的。那么,为什么不直接用脚本文件呢?还要链接一下再取个这种奇怪的名字?

有位智者曾经说过:“当你对某件事物不理解时,一定是你还不够了解这件事物”。为什么要将好好的脚本文件network重命名为S10network这种格式,肯定也是有它的理由的:Init架构在读取/etc/rc.d/rcX.d目录下的脚本文件时,并不是在开机时执行所有脚本,也不是在关机时执行所有脚本,而是根据脚本文件的首字母来决定,脚本是开机执行还是关机执行

  • K:即Kill:以K开头的脚本文件都会在系统关机时运行;
  • S:即Start:以S开头的脚本文件都会在系统开机时运行。

而K|S后面接的数字,就代表着脚本执行的顺序。那么我们再回到K50netconsoleS10network这两个脚本文件:

  • 系统开机时,会运行network脚本,开启network服务;
  • 系统关机时,会执行netconsole脚本,关闭netconsole服务。

2.2.3 回答最初的问题

对Init架构的相关内容了解过后,我们来回答一下之前提出的那些问题:

  • 为什么网络服务叫做network?为什么不叫network-service?

答:因为/etc/rc.d/init.d目录下负责管理网络服务的脚本文件叫做network。当然,如果你想把它的名字换掉也是完全没有问题的,比如你可以复制一下network脚本文件,生成一个叫network-service的脚本,然后用network-service来进行服务管理,就像下面这样:

[root@localhost init.d]# cp network network-service
[root@localhost etc]# service network-service status
已配置设备:
lo eth0
当前活跃设备:
lo eth0 docker0 flannel.1 cni0 veth6620b70c@if3 vethc17e3aa2@if3
  • 在哪里能找到这个服务的管理脚本文件?

答:/etc/rc.d/init.d或者/etc/init.d目录下

  • 怎样能让系统启动的时候就启动network服务呢(即开机自启)?

答:将network服务管理脚本文件拷贝/软链接到系统运行级别对应的目录下,并以标准的命名格式给脚本文件重命名。例如联网多用户模式下,就将/etc/rc.d/init.d/network文件拷贝/软链接到/etc/rc.d/rc3.d目录下并重命名为S10network

2.3 小结

虽然从CentOS 7往后的几乎所有Linux操作系统中都由systemd架构来充当init daemon,但系统中仍然保留了Init架构的相关内容,比如/etc/init.d/etc/rc.d/init.d/etc/rc.d/rcX.d,而且systemd架构也兼容了Init架构的内容。可以看一下/etc/rc.d/init.d/README文件的内容:

[root@localhost init.d]# cat README
You are looking for the traditional init scripts in /etc/rc.d/init.d,
and they are gone?

Here's an explanation on what's going on:

You are running a systemd-based OS where traditional init scripts have
been replaced by native systemd services files. Service files provide
very similar functionality to init scripts. To make use of service
files simply invoke "systemctl", which will output a list of all
currently running services (and other units). Use "systemctl
list-unit-files" to get a listing of all known unit files, including
stopped, disabled and masked ones. Use "systemctl start
foobar.service" and "systemctl stop foobar.service" to start or stop a
service, respectively. For further details, please refer to
systemctl(1).

Note that traditional init scripts continue to function on a systemd
system. An init script /etc/rc.d/init.d/foobar is implicitly mapped
into a service unit foobar.service during system initialization.

Thank you!

Further reading:
        man:systemctl(1)
        man:systemd(1)
        http://0pointer.de/blog/projects/systemd-for-admins-3.html
        http://www.freedesktop.org/wiki/Software/systemd/Incompatibilities

从上面的内容大致可以看出以systemd架构作为init daemon的系统是如何兼容init套件的。Linux操作系统中都没有彻底摒弃Init套件,那这篇对systemd套件的介绍文章也一定是需要给足Init套件面子的。正所谓:以史为鉴,可以知兴替。了解这段历史才能对systemd套件有更深入的了解。那么接下来就正式开始对systemd套件的介绍!

三、systemd架构

systemd架构和Init架构一样,也是作为所有进程的父进程,以PID为1一直运行在Linux系统中。但systemd架构要比Init架构强大并复杂得多!systemd的诞生是有野心的,它企图管理Linux系统的绝大多数基础功能,而且它也做到了,下面是有关systemd比较常见的架构图:

systemd架构图

可以看到,systemd架构不像Init架构那样只管理服务启动和停止,它涵盖了Linux操作系统中绝大多数操作,比如用户登陆(loginctl)设备挂载日志采集(journalctl)网络管理(networkctl)等等。

3.1 如何管理服务?

相信大家在接触Linux的时候都会涉及到配置SSH服务器的内容,一般我们的做法分两步:

  1. 修改/etc/ssh/sshd.conf文件内容
  2. 重启SSHD服务

而重启SSHD服务这一步我们通常用这条命令来完成:

systemctl restart sshd

跟介绍Init架构时一样,我们同样抛出一些问题:为什么网络服务就叫sshd呢?为啥不叫ssd-server这种名字?我在哪能找到这个服务的管理脚本文件?怎样能让系统启动的时候就启动sshd服务呢(即开机自启)?咦?怎么有种似曾相识的感觉(手动狗头)?

3.1.1 systemd Unit

前面介绍systemd时我有提到:systemd不仅仅会管理服务,还会对系统其他的配置进行管理,比如设备挂载等。那么,systemd是如何将这些不同的系统配置做统一管理的呢?这就离不开systemd unit了。

systemd将它能够管理的系统配置统一称为一个单元,即unit。根据不同的unit类型,systemd可以管理系统中不同的资源和服务。根据Fedora对systemd的介绍,systemd提供的unit类型有下面这些:

单元类型文件后缀描述
Service.service定义了系统服务,包括启动,重启,关闭服务的相关指令
Target.target定义了一组单元的集合,通常作为单元启动的同步点,某个target启动成功就意味着一组相关的service启动成功
Automount.automount定义了系统引导时会进行自动挂载的挂载点
Device.device定义了由systemd管理的硬件设备
Mount.mount定义了由systemd管理的文件系统挂载点
Path.path定义了一条用于基于路径激活服务的文件路径。例如,可以基于某一条文件路径的状态(是否存在等)来启动某个服务。
Scope.scope定义了来自systemd总线接口的信息,通常用来管理额外的系统进程
Slice.slice定义了资源限额,基于Linux cgroup nodes实现。
Snapshot.snapshot定义了一次当前的systemd状态,通常在对systemd做修改后回滚使用
Socket.socket定义了进程间通信使用的socket,往往socket会与service相关联
Swap.swap定义了系统中的交换空间
Timer.timer定义了一个定时激活另一个单元的定时器

3.1.2 Service类型

Service应该是最常见的单元类型,因为你的Linux系统中几乎所有的服务都维护自己的一份Service类型的单元配置文件,以供systemd管理。像sshdchronyd这些服务都有独属于自己的一份.service文件。这里我们拿sshd.service文件来作为示例,简单介绍一下一份systemd Unit文件都包含什么。

在CentOS 7的系统中,默认就会提供sshd服务的unit文件,其路径为:/usr/lib/systemd/system/sshd.service。如果你以联网多用户模式启动的话,那你在/etc/systemd/system/multi-user.target.wants路径下也可以找到sshd.service这个文件。其文件内容如下:

[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target

简单做个介绍,一个Unit文件包括三个部分:[Unit][unit type][Install],其中[unit type]在这里是[Service]

  • [Unit]部分中定义了这个服务的描述信息(Description)帮助文档(Documentation)与其他服务之间的依赖(After & Wants)
  • [Service]部分中定义了这个服务的运行类型(Type)环境变量文件(EnvironmentFile)服务启动命令(ExecStart)服务配置重新加载时执行的命令(ExecReload)服务进程结束的方式(KillMode)服务重启机制(Restart & RestartSec)
  • [Install]部分中定义了这个服务被哪些Unit依赖(WantedBy)

所以,sshd.service这个Unit文件告诉了systemd:俺这是一个叫做OpenSSH server daemon的服务,怕你们不知道怎么用,俺还提供了两个manual可以给你们看,但是要想启动我这sshd服务,你得先帮俺把network.targetsshd-keygen.service这两个服务启动起来。这两个服务到位之后,俺就会启动sshd服务,服务启动命令是/usr/sbin/sshd -D $OPTIONS。俺除了会启动服务,俺还会自己加载配置,俺也知道服务出错了应该要重启。哦对了,俺不是一个人独自运行,俺还是multi-user.target这个单元的依赖项,没有俺,它还起不来捏!俺厉害不(手动拽)!

到这里,有关Service Unit文件的格式和大致的内容就介绍完了,下面的文章里我们将尝试写一个自己的Service Unit文件,请各位看官稍安勿躁~

3.1.3 systemd服务配置文件路径

在上一小节我们介绍sshd服务对应的Service Unit文件时,涉及到两个路径:

  • /usr/lib/systemd/system
  • /etc/systemd/system

这两个路径,是systemd读取配置的三个路径中的其中两个,所以这是一种规范,所以不是想放哪就放哪的。而根据RedHat官网对systemd相关服务配置文件路径的介绍,主要有三条路径:

目录路径描述优先级
/usr/lib/systemd/system/通过RPM包安装软件时,由软件RPM包下发的systemd unit files将存在这个目录下最低
/run/systemd/system/服务运行时产生的相关unit files都存放在这个目录下。中等
/etc/systemd/system/systemctl enable命令创建的systemd unit files将存放在此处。同时,一般系统管理员自定义的unit files也存放在该目录下。最高

3.1.4 /etc/systemd/system/default.target

在Init架构中,我们介绍了系统运行级别的概念,Init架构根据其配置文件/etc/inittab中定义的运行级别来启动相应运行级别对应目录/etc/rc.d/rcX.d下的服务。而在systemd架构中,系统启动时,也有类似的概念,但不同于系统运行级别,systemd中使用Target Unit来定义系统的运行模式。根据Fedora对系统运行级别和Target Unit之间的映射关系,可以得到下面的映射关系表:

Init架构中系统运行级别systemd架构中Target Unit备注
0runlevel0.target / poweroff.target关闭系统
1runlevel1.target / rescue.target单用户模式
2, 4runlevel2.target / runlevel4.target / multi-user.target用户自定义的运行级别。不同于Init架构中提供的离线多用户模式,systemd架构默认只提供联网多用户模式,也就是对应Init架构数字为3的运行级别。
3runlevel3.target / multi-user.target联网多用户模式,不带有图形化界面
5runlevel5.target / graphical.target联网多用户模式且带有图形化界面
6runlevel6.target / reboot.target重启系统
emergencyemergency.target进入紧急恢复状态

Target Unit理解起来并不难,它就是一组Units的集合。这就跟学生时代升旗仪式一样,每个班(Target)有很多学生(Units),只有当每位学生(Units)都到齐之后,这个班(Target)才允许进入操场。当所有的班(Target)都进入操场后,升旗仪式(default.target)才会进行。所以,在systemd架构下,系统的启动方式可以这样理解:systemd通过default.target来启动系统,什么时候default.target准备就绪,系统就认为启动成功

[root@localhost system]# pwd
/etc/systemd/system
[root@localhost system]# realpath default.target
/usr/lib/systemd/system/multi-user.target
[root@localhost system]# ls
basic.target.wants  default.target  default.target.wants  getty.target.wants  local-fs.target.wants  multi-user.target.wants  remote-fs.target.wants  sockets.target.wants  sysinit.target.wants  system-update.target.wants

从上面的命令可以看出,当前系统的default.target本质上是multi-user.target的软链接,也就是说,当前系统的默认启动模式是联网多用户模式。此外,在ls命令中我们还可以看到很多以.wants结尾的目录,这些目录其实是配合Target Unit工作的,代表某个Target Unit所管理的一组Units。比如,default.target.wants目录中的Units就是default.target所管理的一批Units。

所以我们可以这样理解,系统如果想以multi-user.target模式启动的话,就必须先将multi-user.target.wants目录中的Units都启动成功才行。都暗示到这里了,有关开机自启,你是不是已经知道了捏(手动淫笑)~

3.1.5 回答最初的问题

对systemd架构的相关内容了解过后,我们来回答一下之前提出的那些问题:

  • 为什么网络服务叫做sshd?为什么不叫sshd-server?

答:因为/usr/lib/systemd/system目录下存放了安装sshd包时提供的Service Unit文件,且文件名为sshd.service。当然,如果你想把它的名字换掉也是完全没有问题的,比如你可以复制一下sshd.service文件,生成一个叫sshd-server.service的文件,然后用sshd-server.service来进行服务管理,就像下面这样:

[root@localhost multi-user.target.wants]# pwd
/etc/systemd/system/multi-user.target.wants
[root@localhost multi-user.target.wants]# cp sshd.service sshd-server.service
[root@localhost multi-user.target.wants]# systemctl daemon-reload && systemctl status sshd-server

很显然,用sshd-server管理服务是有问题的(手动滑稽),因为sshd服务运行的时候不是只有一个sshd.service的,它还绑定了一些Socket Unit,显然,我们简单拷贝一个Service Unit是无法获取其他Units状态的。

  • 在哪里能找到这个服务的管理脚本文件?

答:/usr/lib/systemd/system/或者/etc/systemd/system/目录下

  • 怎样能让系统启动的时候就启动sshd服务呢(即开机自启)?

答:将sshd.service文件拷贝/软链接到系统运行级别对应Target Unit所管理的Units目录下。例如联网多用户模式(multi-user.target)下,就将/usr/lib/systemd/system/sshd.service文件拷贝/软链接到/etc/systemd/system/multi-user.target.wants/目录下即可。

3.2 创建并管理自己的服务

上面了解了systemd架构管理服务的内容和逻辑后,我们便可以着手写一个自己的服务,并让systemd代为管理。下面是我们这个服务的相关信息:

  • 没有任何依赖,运行一个python脚本;
  • 提供一个8888端口的HTTP服务;
  • 开机自启。

这一小节希望你能够跟我一起动起来,写代码敲命令!

3.2.1 编写Service Unit

前面我们介绍过,一个Service Unit分为三个部分:[Unit][Service][Install]。根据服务相关信息,我们可以生成下面的Service Unit文件:

[Unit]
Description=My Simple HTTP Service

[Service]
ExecStart=/usr/bin/python -m SimpleHTTPServer 8888
Restart=on-failure

[Install]
WantedBy=multi-user.target

非!常!简!单!有没有?没错,当我们自己为Linux系统写一个服务的时候往往并不会涉及到太多的依赖和其他的比较复杂的配置(环境变量,按需启动等等)。我们只需要给一个启动命令就可以了。不过这里还是对这个Service Unit做一个说明:

  • Unit – Description:这个Unit的描述:My Simple HTTP Service
  • Service – ExecStart:这个Service的启动命令:直接利用python命令自带的SimpleHTTPServer模块启动一个8888端口的HTTP服务。
  • Service – Restart:这个Service的重启策略:当服务出错时自动重启。
  • Install – WantedBy:这个Unit被哪些Units所依赖:被multi-user.target依赖,也就是说,系统以联网多用户模式启动时,我们自定义的服务会先于multi-user.target就绪,即开机自启。

现在我们把这个文件以/usr/lib/systemd/system/simplehttp.service路径保存起来。

3.2.2 加载服务

编写完文件之后,systemd并不会热加载新增的配置,我们需要手动让systemd加载全部配置文件,命令如下:

systemctl daemon-reload

随后,我们查看systemd是否已经读到了我们自定义的服务:

[root@localhost ~]# systemctl list-units -t service --all | grep simple
simplehttp.service      loaded    inactive dead    My Simple HTTP Service

可以看到,服务已经加载进来了(loaded),且并没有启动(inactive dead),此外,我们还可以看到我们给服务写的描述(My Simple HTTP Service)

3.2.3 启动服务

确认服务加载到systemd后,我们尝试启动我们的服务,命令如下:

systemctl start simplehttp

然后我们查看服务的状态:

[root@localhost ~]# systemctl status simplehttp
● simplehttp.service - My Simple HTTP Service
   Loaded: loaded (/usr/lib/systemd/system/simplehttp.service; bad; vendor preset: disabled)
   Active: active (running) since 四 2023-07-06 16:45:08 CST; 6s ago
 Main PID: 24511 (python)
   CGroup: /system.slice/simplehttp.service
           └─24511 /usr/bin/python -m SimpleHTTPServer 8888

7月 06 16:45:08 localhost systemd[1]: Started My Simple HTTP Service.

重启服务:

systemctl restart simplehttp

停止服务:

systemctl stop simplehttp

3.2.4 访问服务

好的,服务起来了。但我们不能止步于此,服务起来了咱得用它对不。我们启动了一个8888端口的HTTP服务,那我们先看看8888端口是不是已经处于监听状态了:

[root@localhost ~]# netstat -ltpn | grep 8888
tcp   0  0 0.0.0.0:8888    0.0.0.0:*       LISTEN      24511/python

可以看到,8888端口已经启动,而且相关的进程ID也刚好是我们服务的PID:24511。那么我们可以直接访问本机8888端口,看看服务是否可用:

[root@test-test-biz-hzmedia-worker-192-168-100-74 ~]# curl localhost:8888
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
<title>Directory listing for /</title>
<body>
<h2>Directory listing for /</h2>
<hr>
<ul>
<li><a href="bin/">bin@</a>
<li><a href="boot/">boot/</a>
<li><a href="data/">data/</a>
<li><a href="dev/">dev/</a>
<li><a href="etc/">etc/</a>
<li><a href="home/">home/</a>
<li><a href="lib/">lib@</a>
<li><a href="lib64/">lib64@</a>
<li><a href="media/">media/</a>
<li><a href="mnt/">mnt/</a>
<li><a href="opt/">opt/</a>
<li><a href="proc/">proc/</a>
<li><a href="root/">root/</a>
<li><a href="run/">run/</a>
<li><a href="sbin/">sbin@</a>
<li><a href="srv/">srv/</a>
<li><a href="sys/">sys/</a>
<li><a href="tmp/">tmp/</a>
<li><a href="usr/">usr/</a>
<li><a href="var/">var/</a>
<li><a href="xhzyadp/">xhzyadp/</a>
</ul>
<hr>
</body>
</html>

可以看到,服务正常可用。这个时候我们再看一下服务的状态:

[root@localhost ~]# systemctl status simplehttp
● simplehttp.service - My Simple HTTP Service
   Loaded: loaded (/usr/lib/systemd/system/simplehttp.service; enabled; vendor preset: disabled)
   Active: active (running) since 四 2023-07-06 16:45:08 CST; 13min ago
 Main PID: 24511 (python)
   CGroup: /system.slice/simplehttp.service
           └─24511 /usr/bin/python -m SimpleHTTPServer 8888

7月 06 16:45:08 localhost systemd[1]: Started My Simple HTTP Service.
7月 06 16:56:57 localhost python[24511]: 127.0.0.1 - - [06/Jul/2023 16:56:57] "GET / HTTP/1.1" 200 -
7月 06 16:57:15 localhost python[24511]: 127.0.0.1 - - [06/Jul/2023 16:57:15] "GET /root HTTP/1.1" 301 -
7月 06 16:57:17 localhost python[24511]: 127.0.0.1 - - [06/Jul/2023 16:57:17] "GET /root HTTP/1.1" 301 -
7月 06 16:57:30 localhost python[24511]: 127.0.0.1 - - [06/Jul/2023 16:57:30] "GET /root/ HTTP/1.1" 200 -
7月 06 16:57:34 localhost python[24511]: 127.0.0.1 - - [06/Jul/2023 16:57:34] "GET /root/ HTTP/1.1" 200 -

可以看到,服务运行正常,而且将所有的请求信息都输出到了控制台,我们在systemctl status simplehttp命令的时候便可以看到相关日志。服务运行时的日志,并不是凭空产生的,而是由systemd架构中的日志管理提供的功能。

3.3 命令集

systemd架构管理了Linux系统的太多基础配置,因此它也提供了许多的基础命令。在这一小节,我将列举出systemd中所有的命令,并给出他们用法的简单示例。

3.3.1 systemctl

systemctl是systemd架构的核心命令,用于管理systemd。下面列举出一些常用命令格式:

  • systemctl start network:启动network服务
  • systemctl restart network:重启network服务
  • systemctl status network:查看network服务状态
  • systemctl stop network:停止network服务
  • systemctl list-dependencies multi-user.target:列举出multi-user.target的所有依赖项
  • systemctl list-units --all -t service:列举出系统中所有的Service Unit

3.3.2 journalctl

journalctl提供了查看由journald服务管理的日志信息的功能。下面列举出一些常用命令格式:

  • journalctl -u sshd:查看sshd服务日志
  • journalctl -eu sshd:查看sshd服务日志,并直接跳转到日志末尾
  • journalctl -xeu sshd:查看sshd服务日志,并直接跳转到日志末尾,同时打印可用的服务描述
  • journalctl -u sshd -n 10:查看sshd服务日志,并只打印前10行
  • journalctl -u sshd -f:以实时更新的方式查看sshd服务日志
  • journalctl --file ${FILENAME}:读journal文件内容,journal文件一般存放在/run/log/journal/目录下。

3.3.2 systemd-X

你可以在终端输入systemd-然后按下Tab自动补全,终端为你显示出所有systemd-开头的命令,这些命令都是systemd架构提供的可用命令。这里列举出所有CentOS 7中可用的命令集以及简单介绍,并且将相关的参考文档也提供出来。

  • systemd-analyze:可以显示系统启动耗时,加上参数可以显示更详细的耗时情况。
  • systemd-nspawn:进阶的chroot命令,能够在轻量的命名空间容器中运行命令或系统。
  • systemd-ask-password:一个用来向系统中用户询问账户密码的工具。这工具可以用在脚本里头,在执行某些操作之前先让用户输入密码再继续。
  • systemd-tty-ask-password-agent:用来回应系统中的密码输入请求。例如systemd-ask-password命令产生的密码输入请求。
  • systemd-cat:可以将命令的标准输入、标准输出和标准错误重定向到journal日志里面。
  • systemd-cgls:显示系统中cgroup层级关系。
  • systemd-cgtop:对cgroup层级进行资源用量的排序,从命令命名可以看出,是cgroup的top命令。
  • systemd-coredump:可以用来对journal日志中的coredump信息进行分析,用来分析应用程序崩溃问题。
  • systemd-delta:可以用来检测系统中存在的配置文件覆盖情况。
  • systemd-detect-virt:可以检测系统的运行环境是否为虚拟机环境。
  • systemd-escape:用来对Unit文件中的特殊字符进行转义,也可以用于还原。
  • systemd-firstboot:用来在系统首次启动时进行系统信息配置,只在首次启动有效,内核引导中systemd.firstboot参数用来标识系统是不是首次启动。
  • systemd-hwdb:用来管理系统硬件数据库hwdb的工具,实际应用场景暂不确定。
  • systemd-inhibit:可用于运行一些必须在开机状态下工作的程序。该命令产生的进程将获得一个阻止系统关机或休眠的锁,并在运行后才释放锁,随后系统才能关机或休眠。有个实际的例子:利用systemd-inhibit保证当系统还有SSH连接时无法关机
  • systemd-loginctl:该命令跟loginctl命令一毛一样,用来管理用户登录信息。
  • systemd-machine-id-setup:可以用来管理机器ID,说白了就是对/etc/machine-id文件做操作。但值得注意的是,/etc/machine-id并不是systemd生成的,只是说systemd提供了一个工具来管理他。至于修改machine-id会造成什么问题,可以看这篇帖子
  • systemd-notify:一般被以Type=Notify的Service Unit使用,通过该命令可以告知systemd当前服务的状态等信息,通过systemctl status ${SERVICE}可以看到相关信息。
  • systemd-path:显示当前系统以及当前用户的关键文件路径信息,比如这个命令会告诉你/etc是干嘛的。
  • systemd-run:创建一个临时的Scope UnitService UnitTimer Unit来运行所给的命令。
  • systemd-stdio-bridge:将程序的标准输入输出重定向到指定的总线(D-bus)上。这里有一篇关于systemctl -H利用systemd-stdio-bridge建立SSH隧道的讨论,感兴趣的小伙伴可以看看。
  • systemd-sysv-convert:可以将Init架构下/etc/rc.d/init.d/目录里的服务脚本文件的运行级别移植到systemd架构中同名的Service Unit上。
  • systemd-tmpfiles:该命令结合/etc/tmpfiles.d目录下对临时文件管理的配置文件,创建、删除、清理易变文件与临时文件。

3.3.3 hostnamectl

hostnamectl用于管理当前主机的信息。下面列举出一些常用命令格式:

  • hostnamectl:显示主机信息,包括主机名,主机类型,虚拟化技术,CPU架构,内核版本,操作系统等等。
  • hostnamectl set-hostname new-localhost:设置主机名为new-localhost,设置完后并不会立马看到效果,可以通过su -命令重新加载一次tty窗口或者退出重新登录系统。

3.3.4 localectl

localectl用于查看本地化设置。下面列举出一些常用命令格式:

  • localectl status:显示本地化配置,status可要可不要。
  • localectl set-locale LANG=en_GB.utf8:修改本地语言配置为英文。

3.3.5 loginctl

loginctl用于管理当前登录的用户信息。这里简单介绍一下systemd管理用户登录信息的基本知识点:详细介绍可参考此介绍文档

  • user:任何登陆到Linux系统中的用户;
  • session:user的授权信息。除使用susudo命令外的所有其他登录方式(包括TTY,SSH或者图形化登录界面等)每次登录都会产生一个专门的新session。
  • seat:这个概念允许连接多套硬件(鼠标、键盘、显示器),并由多个用户同时使用。一般不使用此功能,而且系统中一般也就一个seat。

下面列举出一些常用命令格式:

  • loginctl list-sessions:列出当前系统中所有的sessions。
  • loginctl list-users:列出当前系统中所有登录的用户。
  • loginctl show-user root:查看系统中root用户的登录信息,可以看到同时有多少个root登录。
  • loginctl list-seats:查看系统中所有的seats。

3.3.6 timedatectl

timedatectl用于管理系统时间。下面列举出一些常用命令格式:

  • timedatectl:查看系统时间。
  • timedatectl list-timezones:列出所有时区。
  • timedatectl set-timezone Asia/Shanghai:修改系统时区为Asia/Shanghai
  • timedatectl set-time "2022-2-20 12:00:00":修改系统时间为2022-2-20 12:00:00
  • timedatectl set-ntp yes:启用ntp同步功能。
  • timedatectl set-local-rtc 1:使用RTC+Timezone作为Local Time。
  • timedatectl set-local-rtc 0:使用UTC时间作为Local Time。

四、总结

至此,本文介绍了init daemon的相关定义,以及CentOS操作系统使用过的两套init daemon架构,即Init架构以及systemd架构。祁祁希望通过这篇文章,能让读到这里的你能收获下面的知识:

  • init daemon的概念,作用以及其被启动的时间点;
  • Init架构中/etc/rc.d/目录下文件和目录的作用,以及其如何管理服务启停;
  • systemd架构中有关Unit文件的种类,以及如何自定义一个Service Unit
  • systemd架构中如何通过Target Unit来实现服务自启动;
  • systemd架构包含了哪些系统基础配置的管理。

如果你能搞清楚上面这些知识点的来龙去脉,那么恭喜你,你已经具备管理Linux服务的基本能力了,有关systemd架构的基本管理能力你也有了。但是也仅仅是基本能力,实际上systemd架构所提供的特性远远不止我上面介绍的那样简单。不过,具体的细节功能就留给聪明的你自己去挖掘咯~文章的末尾,我贴出一些有关systemd进阶使用的手法,各位按需翻阅:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值