systemd (学习笔记)

1. sysvinit

Linux在内核态启动完成后,调用用户态的“init”程序开始布置整个用户态的应用环境,init在随后根据配置文件调用文件系统中的初始化脚本。在这里,唯一可以肯定的是任何linux发行版本第一个应用程序都是会去调用init程序,且init程序解析配置文件的方法都是一致的。而关于启动脚本的组织形式和风格,在多个发行版本之间是各不相同、多种多样的。
所以如果需要修改启动脚本以用来加入一些自定义的模块,需要先理解该linux文件系统的脚本架构。
Linux脚本的启动顺序大概如下图所示:
在这里插入图片描述

/etc/inittab

Linux下为什么会要有个init?用过windows 9.x的人应该知道有个批处理文件autoexec.bat,用过windows NT/2000系统的人应该在控制面板中见过system service工具,它们的目的是相同的。只是比较起来windows下的这些东西功能太弱(当然用法也更简单)。
init是Linux启动的最后一步,它帮助用户完成每次启动系统都必须完成的一些重复性任务,如加载文件系统、各类网络服务等等程序;它还有一个重要用途,让用户自定义系统运行环境,只启动需要的进程,关闭不用的进程,释放内存和处理器资源,让系统运行得更快更稳。
常见的init用户程序有两种:一种完整版的init程序sysvinit,sysvinit软件包提供了一系列开关机的命令,常见的有:hutdown、reboot、halt、poweroff、telinit、init。它们都可以达到关机或重启的目的,但是每个命令的工作流程并不一样。
另一种是busybox提供的精简版init :
在这里插入图片描述

init会按任务表执行我们下的命令,这个任务表就是/etc/inittab文件。下面查看一个inittab文件的例子:
在这里插入图片描述

“/etc/inittab”文件每一行定义一个指令,其基本格式为:id:runlevels:action:command。各字段的详解如下:

id:是任意一个名称(具体是什么并不重要);

runlevels:是一个数字串(代表运行等级);
一条命令可以是一个等级下执行,也可以是多个等级下执行,例如:“1:2345:respawn:/sbin/getty 38400 tty1 “,该命令在等级2345下都会被执行。
根据Linux的定义,Init 可以启动到8个不同的运行级别上:0-6 和 S 或 s。
运行级别可以由超级用户通过 telinit 命令来转换,此命令可以将转换信号传递给 init,告诉它切换到哪个运行级别。
运行级别 0,1,和 6为系统保留的专用运行级别。
运行级别 0 用来关机,运行级别 6 用来重启,运行级别 1 用来使计算机进入单用户模式。
运行级别 S 不是给我们直接使用的,更多是为进入运行级别 1 时运行某些可执行脚本时被调用。下面是几个运行级的简单介绍:
# 0 - 关机(千万不要把initdefault 设置为0 )
# 1 - 单用户模式
# 2 - 多用户,但是没有 NFS
# 3 - 完全多用户模式
# 4 - 没有用到
# 5 - X11
# 6 - 重启(千万不要把initdefault 设置为6 )

action:描述何时执行命令;
action,告诉init执行的动作,即如何处理process字段指定的进程。action字段允许的值及对应的动作分别为:
1)respawn:如果process字段指定的进程没有运行,则启动该进程,init不等待处理结束,而是继续扫描inittab文件中的后续进程,当这样的进程终止时,init会重新启动它,如果这样的进程已经运行,则什么也不做。
2)wait:启动process字段指定的进程,并等到处理结束才去处理inittab中的下一记录项。
3)once:启动process字段指定的进程,不等待处理结束就去处理下一记录项。当这样的进程终止时,也不再重新启动它,在进入新的运行级别时,如果这样的进程仍在运行,init也不重新启动它。
4)boot:只有在系统启动时,init才处理这样的记录项,启动相应进程,并不等待处理结束就去处理下一个记录项。当这样的进程终止时,系统也不重启它。
5)bootwait:系统启动后,当第一次从单用户模式进入多用户模式时处理这样的记录项,init启动这样的进程,并且等待它的处理结束,然后再进行下一个记录项的处理,当这样的进程终止时,系统也不重启它。
6)powerfail:当init接到断电的信号(SIGPWR)时,处理指定的进程。
7)powerwait:当init接到断电的信号(SIGPWR)时,处理指定的进程,并且等到处理结束才去检查其他的记录项。
8)off:如果指定的进程正在运行,init就给它发SIGTERM警告信号,在向它发出信号SIGKILL强制其结束之前等待5秒,如果这样的进程不存在,则忽略这一项。
9)ondemand:功能通respawn,不同的是,与具体的运行级别无关,只用于runlevel字段是a、b、c的那些记录项。
10)sysinit:指定的进程在访问控制台之前执行,这样的记录项仅用于对某些设备的初始化,目的是为了使init在这样的设备上向用户提问有关运行级别的问题,init需要等待进程运行结束后才继续。
11)initdefault:指定一个默认的运行级别,只有当init一开始被调用时才扫描这一项,如果rstate字段指定了多个运行级别,其中最大的数字是默认的运行级别,如果runlevel字段是空的,init认为字段是0123456,于是进入级别6,这样便陷入了一个循环,如果inittab文件中没有包含initdefault的记录项,则在系统启动时请求用户为它指定一个初始运行级别。

command:指定执行的实际命令。该字段中进程可以是任意的守候进程、可执行脚本或程序,后面可以带参数。

Inittab是所有启动脚本的总入口,各种版本linux的启动脚本组织风格虽然不同,从这里都能找到它的入口。

/etc/init.d/rc 和 /etc/rc.d

虽然不同linux版本启动脚本的组织风格是不一样,你也可以自定义出一套风格来,但是普遍来说/etc/rc.d/rcN.d是一种最常见的风格。
如在/etc/inittab文件中,N运行级别调用/etc/rc.d/rc N的命令:
在这里插入图片描述

以运行级别5为例,init将执行配置文件inittab中的以下这行:l5:5:wait:/etc/rc.d/rc 5
这一行表示以5为参数运行/etc/rc.d/rc/etc/rc.d/rc是一个Shell脚本,它接受5作为参数,去执行/etc/rc.d /rc5.d/目录下的所有的rc启动脚本,/etc/rc.d/rc5.d/目录中的这些启动脚本实际上都是一些链接文件,而不是真正的rc启动脚本,真正的rc启动脚本实际上都是放在/etc/rc.d/init.d/目录下。而这些rc启动脚本有着类似的用法,它们一般能接受start、stop、 restart、status等参数。
/etc/rc.d/rc5.d/中的rc启动脚本通常是KS开头的链接文件,对于以以S开头的启动脚本,将以start参数来运行。而如果发现存在相应的脚本也存在K打头的链接,而且已经处于运行态了(以/var/lock/subsys/下的文件作为标志),则将首先以stop为参数停止这些已经启动了的守护进程,然后再重新运行。这样做是为了保证是当init改变运行级别时,所有相关的守护进程都将重启。

root@am57xx-evm:~# ls /etc/rc  
rc0.d/ rc1.d/ rc2.d/ rc3.d/ rc4.d/ rc5.d/ rc6.d/ rcS.d/ 
root@am57xx-evm:~# ls /etc/rc3.d/  
S01networking          S08rc.pvr              S10tiipclad-daemon.sh  S19nfscommon           S20thttpd              S30rng-tools           S97matrix-gui-2.0      S99rmnologin.sh
S02dbus-1              S10dropbear            S12rpcbind             S20hwclock.sh          S21avahi-daemon        S70lighttpd            S98thermal-zone-init
S03uim-sysfs           S10telnetd             S15mountnfs.sh         S20syslog              S22ofono               S95gdbserverproxy      S99gplv3-notice
root@am57xx-evm:~# ls -l /etc/rc3.d/
lrwxrwxrwx    1 root     root            20 Oct  3 21:07 S01networking -> ../init.d/networking
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S02dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S03uim-sysfs -> ../init.d/uim-sysfs
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S08rc.pvr -> ../init.d/rc.pvr
lrwxrwxrwx    1 root     root            18 Oct  3 21:07 S10dropbear -> ../init.d/dropbear
lrwxrwxrwx    1 root     root            17 Oct  3 21:07 S10telnetd -> ../init.d/telnetd
lrwxrwxrwx    1 root     root            28 Oct  3 21:07 S10tiipclad-daemon.sh -> ../init.d/tiipclad-daemon.sh
lrwxrwxrwx    1 root     root            17 Oct  3 21:07 S12rpcbind -> ../init.d/rpcbind
lrwxrwxrwx    1 root     root            21 Oct  3 21:07 S15mountnfs.sh -> ../init.d/mountnfs.sh
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S19nfscommon -> ../init.d/nfscommon
lrwxrwxrwx    1 root     root            20 Oct  3 21:07 S20hwclock.sh -> ../init.d/hwclock.sh
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S20syslog -> ../init.d/syslog
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S20thttpd -> ../init.d/thttpd
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S21avahi-daemon -> ../init.d/avahi-daemon
lrwxrwxrwx    1 root     root            15 Oct  3 21:07 S22ofono -> ../init.d/ofono
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S30rng-tools -> ../init.d/rng-tools
lrwxrwxrwx    1 root     root            18 Oct  3 21:07 S70lighttpd -> ../init.d/lighttpd
lrwxrwxrwx    1 root     root            24 Oct  3 21:07 S95gdbserverproxy -> ../init.d/gdbserverproxy
lrwxrwxrwx    1 root     root            24 Oct  3 21:07 S97matrix-gui-2.0 -> ../init.d/matrix-gui-2.0
lrwxrwxrwx    1 root     root            27 Oct  3 21:07 S98thermal-zone-init -> ../init.d/thermal-zone-init
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S99gplv3-notice -> ../init.d/gplv3-notice
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S99rmnologin.sh -> ../init.d/rmnologin.sh

example 1

在这里插入图片描述

example 2

在这里插入图片描述

example 3

在这里插入图片描述

sysvinit 缺点

sysvinit 就是 System V 风格的 init 系统,顾名思义,它源于 System V 系列的 UNIX。最初的 linux 发行版几乎都是采用 sysvinit 作为 init 系统。sysvinit 用术语 runlevel 来定义 “预订的运行模式”。比如 runlevel 3 是命令行模式,runlevel 5 是图形界面模式,runlevel 0 是关机,runlevel 6 是重启。sysvinit 会按照下面的顺序按部就班的初始化系统:

激活 udev 和 selinux
设置定义在 /etc/sysctl.conf 中的内核参数
设置系统时钟
加载 keymaps
启用交换分区
设置主机名(hostname)
根分区检查和 remount
激活 RAID 和 LVM 设备
开启磁盘配额
检查并挂载所有文件系统
清除过期的 locks 和 PID 文件
最后找到指定 runlevel 下的脚本并执行,其实就是启动服务。

除了负责初始化系 统,sysvinit 还要负责关闭系统,主要是在系统关闭是为了保证数据的一致性,需要小心地按照顺序进行任务的结束和清理工作。另外,sysvinit 还提供了很多管理和控制系统的命令,比如 halt、init、mesg、shutdown、reboot 等等。
sysvinit 的优点是概念简单。特别是服务(service)的配置,只需要把启动/停止服务的脚本链接接到合适的目录就可以了。
sysvinit 的另一个重要优点是确定的执行顺序,脚本严格按照顺序执行(sysvinit 靠脚本来初始化系统),一个执行完毕再执行下一个,这非常有益于错误排查。

同时,完全顺序执行任务也是 sysvinit 最致命的缺陷。如果 linux 系统只用于服务器系统,那么漫长的启动过程可能并不是什么问题,毕竟我们是不会经常重启服务器的。但是现在 linux 被越来越多的用在了桌面系统中,漫长的启动过程对桌面用户来说是不能接受的。 除了启动慢,sysvinit 还有一些其它的缺陷,比如不能很好的处理即插即用的设备,对网络共享磁盘的挂载也存在一定的问题,于是 init 系统开始了它的进化之旅。

2. SystemD

在这里插入图片描述

systemd 的主要优点:

  • 兼容性

systemd 提供了和 sysvinit 兼容的特性。系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。

root@am57xx-evm:~# ls -l /sbin/init 
lrwxrwxrwx    1 root     root            20 Oct  3 21:08 /sbin/init -> /lib/systemd/systemd
root@am57xx-evm:~# 

为了与传统的 SysV 兼容,如果将 systemd 以 init 名称启动,并且"PID≠1",那么它将执行 telinit 命令并将所有命令行参数原封不动的传递过去。 这样对于普通的登录会话来说,无论是调用 init 还是调用 telinit 都是等价的。

当作为系统实例运行时,systemd将会按照system.conf配置文件以及system.conf.d配置目录中的指令工作;
当作为用户实例运行时,systemd 将会按照user.conf配置文件 以及 user.conf.d配置目录中的指令工作。

  • 启动速度

systemd 提供了比 upstart 更激进的并行启动能力,采用了 socket / D-Bus activation 等技术启动服务。一个显而易见的结果就是:更快的启动速度。

为了减少系统启动时间,systemd 的目标是:
尽可能启动更少的进程
尽可能将更多进程并行启动

upstart 的并行方式:
在这里插入图片描述

upstart 增加了系统启动的并行性,从而提高了系统启动速度。但是在 upstart 中,有依赖关系的服务还是必须先后启动。比如任务 A,B,(C,D)因为存在依赖关系,所以在这个局部,还是串行执行。

systemd 的并行方式:
在这里插入图片描述

systemd 能够更进一步提高并发性,即便对于那些 upstart 认为存在相互依赖而必须串行的服务,比如 Avahi 和 D-Bus 也可以并发启动。
在 systemd 中,所有的任务都同时并发执行,总的启动时间被进一步降低为 T1。可见 systemd 比 upstart 更进一步提高了并行启动能力,极大地加速了系统启动时间。

  • 按需启动

当 sysvinit 系统初始化的时候,它会将所有可能用到的后台服务进程全部启动运行。并且系统必须等待所有的服务都启动就绪之后,才允许用户登录。这种做法有两个缺点:首先是启动时间过长,其次是系统资源浪费。

某些服务很可能在 很长一段时间内,甚至整个服务器运行期间都没有被使用过。比如 CUPS,打印服务在多数服务器上很少被真正使用到。您可能没有想到,在很多服务器上 SSHD 也是很少被真正访问到的。花费在启动这些服务上的时间是不必要的;同样,花费在这些服务上的系统资源也是一种浪费。

systemd 可以提供按需启动的能力,只有在某个服务被真正请求的时候才启动它。当该服务结束,systemd 可以关闭它,等待下次需要时再次启动它。
这有点类似于以前系统中的 inetd,并且有很多文章介绍如何把过去 inetd 管理的服务迁移到 systemd。

  • cgroups 管理进程

systemd 利用了 Linux 内核的特性即 cgroups 来完成跟踪的任务。当停止服务时,通过查询 cgroups,systemd 可以确保找到所有的相关进程,从而干净地停止服务。
cgroups 已经出现了很久,它主要用来实现系统资源配额管理。cgroups 提供了类似文件系统的接口,使用方便。当进程创建子进程时,子进程会继承父进程的 cgroups 。因此无论服务如何启动新的子进程,所有的这些相关进程都会属于同一个 cgroups ,systemd 只需要简单地遍历指定的 cgroups 即可正确地找到所有的相关进程,将它们一一停止即可。

  • 挂载管理

启动挂载点:
传统的 linux 系统中,用户可以用 /etc/fstab 文件来维护固定的文件系统挂载点。这些挂载点在系统启动过程中被自动挂载,一旦启动过程结束,这些挂载点就会确保存在。这些挂载点都是对系统运行至关重要 的文件系统,比如 HOME 目录。和 sysvinit 一样,Systemd 管理这些挂载点,以便能够在系统启动时自动挂载它们。systemd 还兼容 /etc/fstab 文件,您可以继续使用该文件管理挂载点。

自动挂载:
有时候用户还需要动态挂载点,比如打算访问 DVD 或者 NFS 共享的内容时,才临时执行挂载以便访问其中的内容,而不访问光盘时该挂载点被取消(umount),以便节约资源。传统地,人们依赖 autofs 服务来实现这种功能。
systemd 内建了自动挂载服务,无需另外安装 autofs 服务,可以直接使用 systemd 提供的自动挂载管理能力来实现 autofs 的功能。

  • 依赖关系管理

系统启动过程是由 很多的独立工作共同组成的,这些工作之间可能存在依赖关系,比如挂载一个 NFS 文件系统必须依赖网络能够正常工作。systemd 虽然能够最大限度地并发执行很多有依赖关系的工作,但是类似"挂载 NFS"和"启动网络"这样的工作还是存在天生的先后依赖关系,无法并发执行。对于这些任务,systemd 维护一个"事务一致性"的概念,保证所有相关的服务都可以正常启动而不会出现互相依赖,以至于死锁的情况。

2.1 units

systemd 把初始化过程中需要需要做的每件事都抽象成了配置单元,即unit。

系统初始化需要做的事情非常多。需要启动后台服务,比如启动 ssh 服务;需要做配置工作,比如挂载文件系统。这个过程中的每一步都被 systemd 抽象为一个配置单元,即 unit。可 以认为一个服务是一个配置单元,一个挂载点是一个配置单元,一个交换分区的配置是一个配置单元等等。systemd 将配置单元归纳为以下一些不同的类型。然而,systemd 正在快速发展,新功能不断增加。所以配置单元类型可能在不久的将来继续增加。

下面是一些常见的 unit 类型:

service :代表一个后台服务进程,比如 mysqld。这是最常用的一类。
socket :此类配置单元封装系统和互联网中的一个套接字 。当下,systemd 支持流式、数据报和连续包的 AF_INET、AF_INET6、AF_UNIX socket 。
        每一个套接字配置单元都有一个相应的服务配置单元 。
        相应的服务在第一个"连接"进入套接字时就会启动(例如:nscd.socket 在有新连接后便启动 nscd.service)。
device :此类配置单元封装一个存在于 Linux 设备树中的设备。
        每一个使用 udev 规则标记的设备都将会在 systemd 中作为一个设备配置单元出现。
mount :此类配置单元封装文件系统结构层次中的一个挂载点。Systemd 将对这个挂载点进行监控和管理。
        比如可以在启动时自动将其挂载;可以在某些条件下自动卸载。
        Systemd 会将 /etc/fstab 中的条目都转换为挂载点,并在开机时处理。
automount :此类配置单元封装系统结构层次中的一个自挂载点。
        每一个自挂载配置单元对应一个挂载配置单元 ,当该自动挂载点被访问时,systemd 执行挂载点中定义的挂载行为。
swap:和挂载配置单元类似,交换配置单元用来管理交换分区。
        用户可以用交换配置单元来定义系统中的交换分区,可以让这些交换分区在启动时被激活。
target :此类配置单元为其他配置单元进行逻辑分组。它们本身实际上并不做什么,只是引用其他配置单元而已。
        这样便可以对配置单元做一个统一的控制。这样就可以实 现大家都已经非常熟悉的运行级别概念。
        比如想让系统进入图形化模式,需要运行许多服务和配置命令,这些操作都由一个个的配置单元表示,将所有这些配置单元 组合为一个目标(target),就表示需要将这些配置单元全部执行一遍以便进入目标所代表的系统运行状态。 
        (例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别 5)
timer:定时器配置单元用来定时触发用户定义的操作,这类配置单元取代了 atd、crond 等传统的定时服务。
snapshot :与 target 配置单元相似,快照是一组配置单元。它保存了系统当前的运行状态。
path:文件系统中的一个文件或目录。
scope:用于 cgroups,表示从 systemd 外部创建的进程。
slice:用于 cgroups,表示一组按层级排列的单位。slice 并不包含进程,但会组建一个层级,并将 scope 和 service 都放置其中。

每个配置单元都有一个对应的配置文件,系统管理员的任务就是编写和维护这些不同的配置文件,比如一个 MySQL 服务对应一个 mysql.service 文件。这种配置文件的语法非常简单,用户不需要再编写和维护复杂的系统脚本了。

2.1.1 unit 格式

unit的配置文件一般在/lib/systemd/system//usr/lib/systemd/user//run/systemd/generator/

root@am57xx-evm:~# ls /lib/systemd/system/         
-.slice                                 emergency.target                        nfs-statd.service                       runlevel2.target                        systemd-backlight@.service              systemd-remount-fs.service
alsa-restore.service                    exit.target                             nss-lookup.target                       runlevel2.target.wants                  systemd-bootchart.service               systemd-resolved.service
alsa-state.service                      final.target                            nss-user-lookup.target                  runlevel3.target                        systemd-exit.service                    systemd-rfkill.service
root@am57xx-evm:~# 
root@am57xx-evm:~# ls /usr/lib/systemd/user/
basic.target          busnames.target       exit.target           printer.target        pulseaudio.socket     smartcard.target      sound.target          timers.target
bluetooth.target      default.target        paths.target          pulseaudio.service    shutdown.target       sockets.target        systemd-exit.service

可以通过下面的指令查询systemd配置目录:

root@am57xx-evm:~# pkg-config systemd --print-variables              
binfmtdir
catalogdir
modulesloaddir
pcfiledir
prefix
sysctldir
systemdshutdowndir
systemdsleepdir
systemdsystemconfdir
systemdsystemgeneratordir
systemdsystempresetdir
systemdsystemunitdir
systemdsystemunitpath
systemduserconfdir
systemdusergeneratordir
systemduserpresetdir
systemduserunitdir
systemduserunitpath
systemdutildir
systemgidmax
systemuidmax
sysusersdir
tmpfilesdir
root@am57xx-evm:~# pkg-config systemd --variable=systemdsystemunitdir   // unit dir
/lib/systemd/system
root@am57xx-evm:~# pkg-config systemd --variable=systemdsystemconfdir   // config dir
/etc/systemd/system
root@am57xx-evm:~# pkg-config systemd --variable=systemdsystemgeneratordir
/lib/systemd/system

systemctl cat命令可以用来查看配置文件,那么我们来看一下sshd配置文件的内容,分析下它每项配置的含义是什么。

systemctl cat sshd.service查看的service配置文件:

[Unit]
Description=OpenSSH server daemon   # 当前服务的简单描述
Documentation=man:sshd(8) man:sshd_config(5)  # sshd是启动脚本,sshd_config是配置文件
After=network.target sshd-keygen.service  # 启动ssh服务之前会先启动这两个Unit
Wants=sshd-keygen.service  # 此Unit启动成功与否不影响ssh服务的正常启动

[Service]
Type=notify  # ssh服务启动成功后会通知systemd,再启动其他依赖服务
EnvironmentFile=/etc/sysconfig/sshd  # 指定ssh服务的环境参数配置文件
ExecStart=/usr/sbin/sshd -D $OPTIONS  # 启动ssh服务执行的命令
ExecReload=/bin/kill -HUP $MAINPID  # 重启ssh服务执行的命令
KillMode=process  # process表示只停止主进程,不停止子进程
Restart=on-failure  # 进程非正常退出时,包括信号终止和超时,会重启服务
RestartSec=42s  # 上面Restart重启之前需要等待42秒再重启

[Install]
WantedBy=multi-user.target   # ssh服务所在的系统运行模式

Unit的配置文件的内容,一般会有以下三个区块,具体含义如下:

[Unit] 区块

  • 1、[Unit]区块通常是配置文件的第一个区块,用来定义Unit的元数据,以及配置与其他Unit的关系,它的主要字段如下:
Description:简单描述
Documentation:服务的启动文件和配置文件
Requires:当前Unit依赖的其他Unit,如果它们没有运行,当前Unit会启动失败
Wants:与当前Unit配合的其他Unit,如果它们没有运行,不影响当前Unit的启动
BindsTo:与Requires类似,它指定的Unit如果退出,会导致当前Unit停止运行
Before:如果该字段指定的Unit也要启动,那么必须在当前Unit之后启动
After:如果该字段指定的Unit也要启动,那么必须在当前Unit之前启动
Conflicts:这里指定的Unit不能与当前Unit同时运行
Condition...:当前Unit运行必须满足的条件,否则不会运行
Assert...:当前Unit运行必须满足的条件,否则会报启动失败

[Unit]区块:启动顺序与依赖关系

After字段定义哪些服务在ssh服务启动之前启动,Before字段定义哪些服务在ssh服务启动之后启动,After和Before字段只涉及启动顺序,不涉及依赖关系:
举例来说,某web应用需要postgresql数据库储存数据,在配置文件中只定义了postgresql在该web应用之前启动,而没有定义依赖关系, 由于某种原因postgresql需要重新启动,在postgresql停止期间,该web应用就会无法建立数据库连接。

设置依赖关系,需要使用Wants字段和Requires字段:
Wants字段表示sshd.service与sshd-keygen.service之间属于“弱依赖”关系,即sshd-keygen.service启动失败或者停止运行,不影响sshd.service的运行。
Requires字段则表示“强依赖”关系,即如果该服务启动失败或者停止运行,那么sshd.service也不会启动。
注意:Wants字段与Requires字段只涉及依赖关系,与启动顺序无关,默认情况下是同时启动的。

[Service] 区块

  • 2、[Service]区块配置,只有Service类型的Unit才有这个区块,它的主要字段如下:
Type:定义启动时的进程行为,它有以下几种值。
    Type=simple:默认值,执行ExecStart指定的命令,启动主进程
    Type=forking:以fork方式从父进程创建子进程,之后父进程会退出,子进程成为主进程
    Type=oneshot:一次性进程,Systemd会等当前服务退出,再继续往下执行
    Type=dbus:当前服务通过D-Bus启动
    Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
    Type=idle:若有其他任务,则其他任务执行完毕,当前服务才会运行
ExecStart:启动当前服务的命令
ExecStartPre:启动当前服务之前执行的命令
ExecStartPost:启动当前服务之后执行的命令
ExecReload:重启当前服务时执行的命令
ExecStop:停止当前服务时执行的命令
ExecStopPost:停止当其服务之后执行的命令
RestartSec:自动重启当前服务间隔的秒数
Restart:定义何种情况Systemd会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
TimeoutSec:定义Systemd停止当前服务之前等待的秒数
Environment:指定环境变量

[Service]区块:启动、停止、重启行为

EnvironmentFile字段:指定ssh服务的环境参数配置文件,该文件内部的key=value键值对,可以用$key的形式,在当前配置文件中获取。
ExecStart字段定义了启动ssh服务的命令是/usr/sbin/sshd -D $OPTIONS,其中的变量$OPTIONS就来自EnvironmentFile字段定义的环境参数配置文件。
所有的启动设置前面都可以加上一个符号(),表示“抑制错误”,即发生错误也不影响其他命令的执行。比如,EnvironmentFile=-/etc/sysconfig/sshd表示即使/etc/sysconfig/sshd文件不存在,也不会抛出错误。
Type字段定义启动类型,Type=notify表示ssh服务启动后会向Systemd发出通知信号,然后Systemd再启动其他服务。

举个例子,笔记本电脑启动时,要把触摸板关掉,配置文件可以这样写:

[Unit]
Description=Switch-off Touchpad

[Service]
Type=oneshot
ExecStart=/usr/bin/touchpad-off

[Install]
WantedBy=multi-user.target

Type设置为oneshot时,就表示这个服务只要运行一次就够了,不需要长期运行。

如果关闭后,将来某个时候还想打开,配置文件修改如下:

[Unit]
Description=Switch-off Touchpad

[Service]
Type=oneshot
ExecStart=/usr/bin/touchpad-off start
ExecStop=/usr/bin/touchpad-off stop
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

RemainAfterExit字段设置为yes,表示进程退出后,服务仍然保持执行。这样的话,一旦使用systemctl stop命令停止服务,ExecStop定义的命令就是执行,从而重新开启触摸板。

KillMode字段设为process表示只停止主进程,不停止任何子进程,即子进程打开的ssh session仍然保持连接。这个设置不太常见,但对ssh服务很重要,否则你停止服务的时候,会连自己打开的ssh session一起杀掉。

KillMode字段可以设置的值如下:

control-group(默认值):当前控制组里面的所有子进程,都会被杀掉
process:只杀主进程
mixed:主进程将收到SIGTERM信号,子进程收到SIGKILL信号
none:没有进程会被杀掉,只是执行服务的stop命令。

Restart设为on-failure表示任何意外的失败,都将重启ssh服务。如果ssh服务正常停止(比如执行systemctl stop sshd.service命令),ssh服务就不会重启。

Restart字段可以设置的值如下:

no(默认值):退出后不会重启
on-success:只有正常退出时(退出状态码为0),才会重启
on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启
on-abnormal:只有被信号终止和超时,才会重启
on-abort:只有在收到没有捕捉到的信号终止时,才会重启
on-watchdog:超时退出,才会重启
always:不管是什么退出原因,总是重启

对于需要守护的进程,推荐设为on-failure;对于那些允许发生错误退出的服务,可以设为on-abnormal

RestartSec表示Systemd重启服务之前,需要等待的秒数。

[Install] 区块

  • 3、[Install]通常是配置文件的最后一个区块,用来定义运行模式(Target)、Unit别名等设置,以及是否开机启动,它的主要字段如下:
WantedBy:它的值是一个或多个Target,当前Unit激活时(enable)时,符号链接会放入/etc/systemd/system目录下面以Target名+.wants后缀构成的子目录中
RequiredBy:它的值是一个或多个Target,当前Unit激活时,符号链接会放入/etc/systemd/system目录下面以Target名+.required后缀构成的子目录中
Alias:当前Unit可用于启动的别名
Also:当前Unit激活(enable)时,会被同时激活的其他Unit

[Install]区块:定义服务启动的系统运行模式,即该服务在哪个运行模式下开机启动。

WantedBy定义服务所在的TargetWantedBy=multi-user.target指的是ssh服务所在的Target是multi-user.target(多用户命令行模式)。
当我们执行systemctl enable sshd.service命令时,sshd.service的一个符号链接,就会放在/etc/systemd/system目录下面的multi-user.target.wants子目录之中。

Systemd有默认启动的Target,multi-user.target(多用户命令行模式):

root@am57xx-evm:~# systemctl get-default
multi-user.target

multi-user.target直接关联的子service,会放在multi-user.target.wants子目录之中。multi-user.target.wants子目录会有多个:

root@am57xx-evm:~# find / -name multi-user.target.wants
/lib/systemd/system/multi-user.target.wants
/run/systemd/generator.late/multi-user.target.wants
/etc/systemd/system/multi-user.target.wants
root@am57xx-evm:~# 
root@am57xx-evm:~# 

这几个multi-user.target.wants目录包含的service:

root@am57xx-evm:~# ls /etc/systemd/system/multi-user.target.wants
avahi-daemon.service      busybox-klogd.service     busybox-syslog.service    lighttpd.service          ofono.service             remote-fs.target          strongswan.service        systemd-networkd.service  systemd-resolved.service
root@am57xx-evm:~# 
root@am57xx-evm:~# ls /lib/systemd/system/multi-user.target.wants
dbus.service                          getty.target                          systemd-ask-password-wall.path        systemd-logind.service                systemd-update-utmp-runlevel.service  systemd-user-sessions.service
root@am57xx-evm:~# 
root@am57xx-evm:~# ls /run/systemd/generator.late/multi-user.target.wants
dropbear.service           gdbserverproxy.service     rc.pvr.service             rng-tools.service          telnetd.service            thermal-zone-init.service  thttpd.service             tiipclad-daemon.service    uim-sysfs.service
root@am57xx-evm:~# 

就是multi-user.target第一级的子service:

root@am57xx-evm:~# systemctl list-dependencies multi-user.target  

multi-user.target
 ├─avahi-daemon.service
 ├─busybox-klogd.service
 ├─busybox-syslog.service
 ├─dbus.service
 ├─dropbear.service
 ├─gdbserverproxy.service
 ├─gplv3-notice.service
 ├─lighttpd.service
 ├─matrix-gui-2.0.service
 ├─ofono.service
 ├─rc.pvr.service
 ├─rng-tools.service
 ├─strongswan.service
 ├─systemd-ask-password-wall.path
 ├─systemd-logind.service
 ├─systemd-networkd.service
 ├─systemd-resolved.service
 ├─systemd-restart-weston.service
 ├─systemd-update-utmp-runlevel.service
 ├─systemd-user-sessions.service
 ├─telnetd.service
 ├─thermal-zone-init.service
 ├─thttpd.service
 ├─tiipclad-daemon.service
 ├─uim-sysfs.service
 ├─weston.service
 ├─basic.target
 │ ├─-.mount
 │ ├─alsa-restore.service
 │ ├─alsa-state.service
 │ ├─tmp.mount
 │ ├─paths.target
 │ ├─slices.target
 │ │ ├─-.slice
 │ │ └─system.slice
 │ ├─sockets.target
 │ │ ├─avahi-daemon.socket
 │ │ ├─dbus.socket
 │ │ ├─dropbear.socket
 │ │ ├─rpcbind.socket
 │ │ ├─systemd-initctl.socket
 │ │ ├─systemd-journald-audit.socket
 │ │ ├─systemd-journald-dev-log.socket
 │ │ ├─systemd-journald.socket
 │ │ ├─systemd-networkd.socket
 │ │ ├─systemd-udevd-control.socket
 │ │ └─systemd-udevd-kernel.socket
 │ ├─sysinit.target
 │ │ ├─alignment.service
 │ │ ├─dev-hugepages.mount
 │ │ ├─dev-mqueue.mount
 │ │ ├─kmod-static-nodes.service
 │ │ ├─ldconfig.service
 │ │ ├─run-postinsts.service
 │ │ ├─sync-clocks.service
 │ │ ├─sys-fs-fuse-connections.mount
 │ │ ├─sys-kernel-config.mount
 │ │ ├─sys-kernel-debug.mount
 │ │ ├─systemd-ask-password-console.path
 │ │ ├─systemd-firstboot.service
 │ │ ├─systemd-hwdb-update.service
 │ │ ├─systemd-journal-catalog-update.service
 │ │ ├─systemd-journal-flush.service
 │ │ ├─systemd-journald.service
 │ │ ├─systemd-machine-id-commit.service
 │ │ ├─systemd-modules-load.service
 │ │ ├─systemd-random-seed.service
 │ │ ├─systemd-sysctl.service
 │ │ ├─systemd-timesyncd.service
 │ │ ├─systemd-tmpfiles-setup-dev.service
 │ │ ├─systemd-tmpfiles-setup.service
 │ │ ├─systemd-udev-trigger.service
 │ │ ├─systemd-udevd.service
 │ │ ├─systemd-update-done.service
 │ │ ├─systemd-update-utmp.service
 │ │ ├─systemd-vconsole-setup.service
 │ │ ├─local-fs.target
 │ │ │ ├─-.mount
 │ │ │ ├─home-root.mount
 │ │ │ ├─media-ram.mount
 │ │ │ ├─mnt-app.mount
 │ │ │ ├─systemd-fsck-root.service
 │ │ │ ├─systemd-remount-fs.service
 │ │ │ ├─tmp.mount
 │ │ │ ├─var-lib-machines.mount
 │ │ │ ├─var-volatile-lib.service
 │ │ │ └─var-volatile.mount
 │ │ └─swap.target
 │ └─timers.target
 │   └─systemd-tmpfiles-clean.timer
 ├─getty.target
 │ ├─getty@tty1.service
 │ ├─serial-getty@ttyO2.service
 │ └─serial-getty@ttyS2.service
 └─remote-fs.target

2.1.2 target

target是一种特殊的unit,它不执行任何实际的操作,它的作用就是把一组unit利用各种依赖和包含关系组织起来共同完成某件事情。

systemd 就是用目标(target)替代了运行级别的概念,提供了更大的灵活性,如您可以继承一个已有的目标,并添加其它服务,来创建自己的目标。下表列举了 systemd 中的 target 和 sysvinit 中常见的 runlevel 的对应关系:

sysvinit runlevelsystemd target描述
0poweroff.target关闭系统。
1,s,singlerescue.target单用户模式。
2,4multi-user.target用户定义/域特定运行级别。默认等同于 3。
3multi-user.target多用户,非图形化。用户可以通过多个控制台或网络登录。
5graphical.target多用户,图形化。通常为所有运行级别 3 的服务外加图形化登录。
6reboot.target重启。
emergencyemergency.target紧急 Shell。

可以使用systemctl set-default NAME来设置当前默认开机运行的target

也可以使用systemctl get-default来查询当前默认开机运行的target:

root@am57xx-evm:~# systemctl get-default
multi-user.target

我们来看一下multi-user.target的内容,systemctl cat multi-user.target

root@am57xx-evm:~# systemctl cat multi-user.target
/lib/systemd/system/multi-user.target
#  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=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

Requires=basic.target:要求basic.target一起运行。
Conflicts字段:冲突字段,如果rescue.servicerescue.target正在运行,multi-user.target就不能运行,反之亦然。
After:表示multi-user.targetbasic.targetrescue.servicerescue.target之后启动,如果它们有启动的话。
AllowIsolate:允许使用systemctl isolate命令切换到multi-user.target

修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务:

重新加载配置文件
systemctl daemon-reload
重启相关服务
systemctl restart foo

2.1.3 service

service是最常用的一种unit,关于它的格式在unit格式一节中已有详细描述。和它相关的有以下命令:

  • 服务的启动、重启、停止等常用命令对比:

|System V init命令| systemctl命令| 作用|
|-|-|
|service foo start| systemctl start foo.service| 启动服务|
|service foo restart| systemctl restart foo.service| 重启服务|
|service foo stop| systemctl stop foo.service| 停止服务|
|service foo reload| systemctl reload foo.service | 重新加载配置文件(不停止服务)|
|service foo status| systemctl status foo.service| 查看服务状态|

  • 设置服务开机启动、不启动等常用命令对比:

|System V init命令| systemctl命令| 作用|
|-|-|
|chkconfig foo on| systemctl enable foo.service| 开机自动启动|
|chkconfig foo off| systemctl disable foo.service| 开机不自动启动|
|chkconfig foo| systemctl is-enabled foo.service| 查看服务是否为自动启动|
|chkconfig --list| systemctl list-unit-files| 查看各个服务的启动与禁用情况|

2.1.4 timer

timer也是一种unit,它与 .service 和 .target 文件有着相似的结构,而区别在于 [Timer] 段。举个例子:

[Timer]
OnBootSec=1h
OnUnitActiveSec=1w

OnBootSec 选项告诉 Systemd 在系统启动一小时后启动这个单元。
OnUnitActiveSec选项的意思是:自那以后每周启动这个单元一次。关于定时器有大量选项您可以设置,输入 man systemd.time 查看完整列表。

Systemd 的时间精度默认为一分钟。也就是说,它会在设定时刻的一分钟内运行单元,但不一定精确到那一秒。这么做是基于电源管理方面的原因,但如果您需要一个没有任何延时且精确到毫秒的定时器,您可以添加以下一行:

    AccuracySec=1us

另外, WakeSystem 选项(可以被设置为 true 或 false)决定了定时器是否可以唤醒处于休眠状态的机器。

2.1.5 sysv兼容

我们在文件系统中依然可以看到传统sysvinit的文件夹/etc/init.d/etc/rcN.d

root@am57xx-evm:~# ls /etc/rc
rc0.d/ rc1.d/ rc2.d/ rc3.d/ rc4.d/ rc5.d/ rc6.d/ rcS.d/ 
root@am57xx-evm:~# ls -l /etc/rc3.d 
lrwxrwxrwx    1 root     root            20 Oct  3 21:07 S01networking -> ../init.d/networking
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S02dbus-1 -> ../init.d/dbus-1
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S03uim-sysfs -> ../init.d/uim-sysfs
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S08rc.pvr -> ../init.d/rc.pvr
lrwxrwxrwx    1 root     root            18 Oct  3 21:07 S10dropbear -> ../init.d/dropbear
lrwxrwxrwx    1 root     root            17 Oct  3 21:07 S10telnetd -> ../init.d/telnetd
lrwxrwxrwx    1 root     root            28 Oct  3 21:07 S10tiipclad-daemon.sh -> ../init.d/tiipclad-daemon.sh
lrwxrwxrwx    1 root     root            17 Oct  3 21:07 S12rpcbind -> ../init.d/rpcbind
lrwxrwxrwx    1 root     root            21 Oct  3 21:07 S15mountnfs.sh -> ../init.d/mountnfs.sh
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S19nfscommon -> ../init.d/nfscommon
lrwxrwxrwx    1 root     root            20 Oct  3 21:07 S20hwclock.sh -> ../init.d/hwclock.sh
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S20syslog -> ../init.d/syslog
lrwxrwxrwx    1 root     root            16 Oct  3 21:07 S20thttpd -> ../init.d/thttpd
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S21avahi-daemon -> ../init.d/avahi-daemon
lrwxrwxrwx    1 root     root            15 Oct  3 21:07 S22ofono -> ../init.d/ofono
lrwxrwxrwx    1 root     root            19 Oct  3 21:07 S30rng-tools -> ../init.d/rng-tools
lrwxrwxrwx    1 root     root            18 Oct  3 21:07 S70lighttpd -> ../init.d/lighttpd
lrwxrwxrwx    1 root     root            24 Oct  3 21:07 S95gdbserverproxy -> ../init.d/gdbserverproxy
lrwxrwxrwx    1 root     root            24 Oct  3 21:07 S97matrix-gui-2.0 -> ../init.d/matrix-gui-2.0
lrwxrwxrwx    1 root     root            27 Oct  3 21:07 S98thermal-zone-init -> ../init.d/thermal-zone-init
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S99gplv3-notice -> ../init.d/gplv3-notice
lrwxrwxrwx    1 root     root            22 Oct  3 21:07 S99rmnologin.sh -> ../init.d/rmnologin.sh
root@am57xx-evm:~# 
root@am57xx-evm:~# ls /etc/init.d/
Myinitscript.sh           bootmisc.sh               functions                 hwclock.sh                networking                read-only-rootfs-hook.sh  save-rtc.sh               systemd-udevd             umountfs
README                    checkroot.sh              functions.initscripts     inetd.busybox             nfscommon                 reboot                    sendsigs                  telnetd                   umountnfs.sh
alignment.sh              dbus-1                    gdbserverproxy            lighttpd                  ofono                     rmnologin.sh              single                    thermal-zone-init         urandom
alsa-state                devpts.sh                 halt                      modutils.sh               populate-volatile.sh      rng-tools                 sysfs.sh                  thttpd
avahi-daemon              dmesg.sh                  hostapd                   mountall.sh               psplash.sh                rpcbind                   syslog                    tiipclad-daemon.sh
banner.sh                 dropbear                  hostname.sh               mountnfs.sh               rc.pvr                    run-postinsts             syslog.busybox            uim-sysfs
root@am57xx-evm:~# 

/etc/init.d保存的是大量启动shell脚本,而/etc/rcN.d保存的是指向/etc/init.d下脚本的链接,根据不同的运行等级N运行不同/etc/rcN.d文件夹下的脚本。

系统启动时init程序会根据/etc/inittab的配置,调用/etc/init.d/rc来执行/etc/rcN.d文件夹下的脚本。

如今打开/etc/init.d/README文件,会看到一段声明:

You are looking for the traditional init scripts in /etc/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/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/Incompatibilit

声明的意思是/etc/init.d/xxx的shell脚本已经被systemd的xxx.service服务所取代,请使用systemd服务。

每次系统启动和systemd服务重启时,/lib/systemd/system-generators/systemd-sysv-generator工具会把/etc/init.d/xxx下的shell脚本转换成systemd的service:

root@am57xx-evm:/# ls /run/systemd/generator/
-.mount                   getty.target.wants        local-fs.target.requires  local-fs.target.wants     media-ram.mount           proc-bus-usb.mount        var-volatile.mount
root@am57xx-evm:/# ls /run/systemd/generator.late/
Myinitscript.service       gdbserverproxy.service     hostname.service           rc.pvr.service             rng-tools.service          sshd.service               thttpd.service             umountnfs.service
alignment.service          graphical.target.wants     inetd.busybox.service      reboot.service             save-rtc.service           sysinit.target.wants       tiipclad-daemon.service
bootmisc.service           halt.service               multi-user.target.wants    reboot.target.wants        sendsigs.service           telnetd.service            uim-sysfs.service
dropbear.service           hostapd.service            poweroff.target.wants      rescue.target.wants        single.service             thermal-zone-init.service  umountfs.service
root@am57xx-evm:/# 
root@am57xx-evm:/# ls /usr/lib/systemd/user-generators/
systemd-dbus1-generator
root@am57xx-evm:/# ls /usr/lib/systemd/user/           
basic.target          busnames.target       exit.target           printer.target        pulseaudio.socket     smartcard.target      sound.target          timers.target
bluetooth.target      default.target        paths.target          pulseaudio.service    shutdown.target       sockets.target        systemd-exit.service
root@am57xx-evm:/# 

在disable/enable这些传统服务时,也会调用/lib/systemd/systemd-sysv-install来执行兼容操作:

root@am57xx-evm:/# systemctl disable telnetd.service              
telnetd.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install disable telnetd
update-rc.d: /etc/init.d/telnetd exists during rc.d purge (continuing)
 Removing any system startup links for telnetd ...
root@am57xx-evm:/# 
root@am57xx-evm:/# systemctl enable telnetd.service   
telnetd.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install enable telnetd
 Adding system startup for /etc/init.d/telnetd.
root@am57xx-evm:/# 

2.1.6 调试命令

  • 1、使用systemctl list-units命令列出已启动的Unitloaded units:
root@am57xx-evm:~# systemctl list-units
  UNIT                                                                                                     LOAD   ACTIVE SUB       DESCRIPTION
  sys-devices-platform-44000000.ocp-48020000.serial-tty-ttyS2.device                                       loaded active plugged   /sys/devices/platform/44000000.ocp/48020000.serial/tty/ttyS2
  sys-devices-platform-44000000.ocp-4806a000.serial-tty-ttyS0.device                                       loaded active plugged   /sys/devices/platform/44000000.ocp/4806a000.serial/tty/ttyS0
  ...
  • 2、使用systemctl list-units --all命令列出所有Unit,包括没有找到配置文件的或者启动失败的loaded but inactive units:
root@am57xx-evm:~# systemctl list-units -all
  • 3、使用systemctl list-unit-files命令列出所有Unit的状态all installed unit files
root@am57xx-evm:~# systemctl list-unit-files
...
alsa-state.service                     static  
autovt@.service                        enabled
avahi-daemon.service                   enabled
banner.service                         mmasked
...

Unit的四种状态:

enabled:开机启动
disabled:不开机启动
static:该Unit没有[Install]部分(无法执行),只能作为其他Unit的依赖
masked:该Unit被禁止开机启动

如果修改了某个服务的配置文件,就要重新加载配置,然后重新启动,否则修改不会生效。

systemctl daemon-reload
systemctl restart httpd.service
  • 4、systemctl list-units命令可以查看系统的所有Unit信息。
列出已启动的Unit
systemctl list-units
列出所有Unit,包括没有找到配置文件的或者启动失败的
systemctl list-units --all
列出所有没有启动的Unit
systemctl list-units --all --state=inactive
列出所有启动失败的Unit
systemctl list-units --failed
列出所有正在运行的、类型为service的Unit
systemctl list-units --type=service
  • 5、systemctl status命令用于查看系统状态和单个Unit的状态。
显示系统状态
systemctl status
显示单个 Unit 的状态
sysystemctl status httpd.service
显示远程主机的nginx服务的状态
systemctl -H root@192.168.2.204 status nginx.service
除了status外,systemctl还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
显示某个 Unit 是否启动
systemctl is-active application.service
显示某个 Unit 是否启动失败
systemctl is-failed application.service
显示某个 Unit 服务是否开机启动
systemctl is-enabled application.service
  • 6、systemctl list-dependencies命令列出一个Unit的所有依赖。
systemctl list-dependencies nginx.service
上面命令的输出结果之中,有些依赖是Target类型,默认不会展开显示。如果要展开Target,就需要使用--all参数。
systemctl list-dependencies --all nginx.service

更详细的依赖查看:

root@am57xx-evm:/# systemctl show -p "After" bootmisc.service
After=sysinit.target basic.target system.slice systemd-journald.socket mountvirtfs.service
root@am57xx-evm:/#
root@am57xx-evm:/# systemctl show -p "Before" bootmisc.service
Before=gdbserverproxy.service sysinit.target rng-tools.service rc.pvr.service uim-sysfs.service thttpd.service thermal-zone-init.service shutdown.target tiipclad-daemon.service telnetd.service

  • 7、systemctl常用命令
立即启动一个服务
systemctl start httpd.service
立即停止一个服务
systemctl stop httpd.service
重启一个服务
systemctl restart httpd.service
杀死一个服务的所有子进程
systemctl kill httpd.service
重新加载一个服务的配置文件
systemctl reload httpd.service
重载所有修改过的配置文件
systemctl daemon-reload
显示某个 Unit 的所有底层参数
systemctl show httpd.service
显示某个 Unit 的指定属性的值
systemctl show -p CPUShares httpd.service
设置某个 Unit 的指定属性
systemctl set-property httpd.service CPUShares=500
Unit的后缀名.service可以省略,例如启动ssh的命令systemctl start sshd.service可以写成systemctl start sshd。
Unit之间存在依赖关系,A依赖于B,就意味着systemd在启动A的时候,同时会去启动B。
  • 8、系统运行模式target相关命令
查看当前系统的所有Target
systemctl list-unit-files --type=target
查看一个 Target 包含的所有Unit
systemctl list-dependencies multi-user.target
查看启动时的默认Target
systemctl get-default
设置启动时的默认Target
systemctl set-default multi-user.target
切换Target时,默认不关闭前一个Target启动的进程,systemctl isolate命令改变这种行为,关闭前一个Target里面所有不属于后一个Target的进程
systemctl isolate multi-user.target

2.1.7 系统命令

  • 1、systemctl是systemd的主命令,用于管理系统和服务。
重启系统
systemctl reboot
关闭系统,切断电源
systemctl poweroff
CPU停止工作
systemctl halt
暂停系统
systemctl suspend
让系统进入冬眠状态
systemctl hibernate
让系统进入交互式休眠状态
systemctl hybrid-sleep
启动进入救援状态(单用户状态)
systemctl rescue
  • 2、systemd-analyze命令用于查看启动耗时。
查看系统启动耗时
systemd-analyze
查看每个服务的启动耗时
systemd-analyze blame
显示瀑布状的系统启动过程流
systemd-analyze critical-chain
显示指定服务的启动流
systemd-analyze critical-chain atd.service
  • 3、hostnamectl命令用于查看当前主机的信息。
显示当前主机的信息
hostnamectl
设置主机名。
hostnamectl set-hostname xuad1
  • 4、localectl命令用于查看本地化设置。
查看本地化设置
localectl
设置本地化参数。

localectl set-locale LANG=zh_CN.UTF-8
localectl set-keymap zh_CN
  • 5、timedatectl命令用于查看当前系统时区设置。
查看当前时区设置
timedatectl
显示所有可用的时区
timedatectl list-timezones
设置当前时区

timedatectl set-timezone Asia/Shanghai
timedatectl set-time YYYY-MM-DD
timedatectl set-time HH:MM:SS
  • 6、loginctl命令用于查看当前登陆的用户。
列出当前session
loginctl list-sessions
列出当前登录用户
loginctl list-users
列出显示指定用户的信息
loginctl show-user root

2.3 systemctl 命令格式大全

root@am57xx-evm:~# systemctl --help
systemctl [OPTIONS...] {COMMAND} ...

Query or send control commands to the systemd manager.

  -h --help           Show this help
     --version        Show package version
     --system         Connect to system manager
     --user           Connect to user service manager
  -H --host=[USER@]HOST
                      Operate on remote host
  -M --machine=CONTAINER
                      Operate on local container
  -t --type=TYPE      List units of a particular type
     --state=STATE    List units with particular LOAD or SUB or ACTIVE state
  -p --property=NAME  Show only properties by this name
  -a --all            Show all loaded units/properties, including dead/empty
                      ones. To list all units installed on the system, use
                      the 'list-unit-files' command instead.
  -l --full           Don't ellipsize unit names on output
  -r --recursive      Show unit list of host and local containers
     --reverse        Show reverse dependencies with 'list-dependencies'
     --job-mode=MODE  Specify how to deal with already queued jobs, when
                      queueing a new job
     --show-types     When showing sockets, explicitly show their type
  -i --ignore-inhibitors
                      When shutting down or sleeping, ignore inhibitors
     --kill-who=WHO   Who to send signal to
  -s --signal=SIGNAL  Which signal to send
     --now            Start or stop unit in addition to enabling or disabling it
  -q --quiet          Suppress output
     --no-block       Do not wait until operation finished
     --no-wall        Don't send wall message before halt/power-off/reboot
     --no-reload      Don't reload daemon after en-/dis-abling unit files
     --no-legend      Do not print a legend (column headers and hints)
     --no-pager       Do not pipe output into a pager
     --no-ask-password
                      Do not ask for system passwords
     --global         Enable/disable unit files globally
     --runtime        Enable unit files only temporarily until next reboot
  -f --force          When enabling unit files, override existing symlinks
                      When shutting down, execute action immediately
     --preset-mode=   Apply only enable, only disable, or all presets
     --root=PATH      Enable unit files in the specified root directory
  -n --lines=INTEGER  Number of journal entries to show
  -o --output=STRING  Change journal output mode (short, short-iso,
                              short-precise, short-monotonic, verbose,
                              export, json, json-pretty, json-sse, cat)
     --firmware-setup Tell the firmware to show the setup menu on next boot
     --plain          Print unit dependencies as a list instead of a tree

Unit Commands:
  list-units [PATTERN...]         List loaded units
  list-sockets [PATTERN...]       List loaded sockets ordered by address
  list-timers [PATTERN...]        List loaded timers ordered by next elapse
  start NAME...                   Start (activate) one or more units
  stop NAME...                    Stop (deactivate) one or more units
  reload NAME...                  Reload one or more units
  restart NAME...                 Start or restart one or more units
  try-restart NAME...             Restart one or more units if active
  reload-or-restart NAME...       Reload one or more units if possible,
                                  otherwise start or restart
  try-reload-or-restart NAME...   If active, reload one or more units,
                                  if supported, otherwise restart
  isolate NAME                    Start one unit and stop all others
  kill NAME...                    Send signal to processes of a unit
  is-active PATTERN...            Check whether units are active
  is-failed PATTERN...            Check whether units are failed
  status [PATTERN...|PID...]      Show runtime status of one or more units
  show [PATTERN...|JOB...]        Show properties of one or more
                                  units/jobs or the manager
  cat PATTERN...                  Show files and drop-ins of one or more units
  set-property NAME ASSIGNMENT... Sets one or more properties of a unit
  help PATTERN...|PID...          Show manual for one or more units
  reset-failed [PATTERN...]       Reset failed state for all, one, or more
                                  units
  list-dependencies [NAME]        Recursively show units which are required
                                  or wanted by this unit or by which this
                                  unit is required or wanted

Unit File Commands:
  list-unit-files [PATTERN...]    List installed unit files
  enable NAME...                  Enable one or more unit files
  disable NAME...                 Disable one or more unit files
  reenable NAME...                Reenable one or more unit files
  preset NAME...                  Enable/disable one or more unit files
                                  based on preset configuration
  preset-all                      Enable/disable all unit files based on
                                  preset configuration
  is-enabled NAME...              Check whether unit files are enabled
  mask NAME...                    Mask one or more units
  unmask NAME...                  Unmask one or more units
  link PATH...                    Link one or more units files into
                                  the search path
  add-wants TARGET NAME...        Add 'Wants' dependency for the target
                                  on specified one or more units
  add-requires TARGET NAME...     Add 'Requires' dependency for the target
                                  on specified one or more units
  edit NAME...                    Edit one or more unit files
  get-default                     Get the name of the default target
  set-default NAME                Set the default target

Machine Commands:
  list-machines [PATTERN...]      List local containers and host

Job Commands:
  list-jobs [PATTERN...]          List jobs
  cancel [JOB...]                 Cancel all, one, or more jobs

Environment Commands:
  show-environment                Dump environment
  set-environment NAME=VALUE...   Set one or more environment variables
  unset-environment NAME...       Unset one or more environment variables
  import-environment [NAME...]    Import all or some environment variables

Manager Lifecycle Commands:
  daemon-reload                   Reload systemd manager configuration
  daemon-reexec                   Reexecute systemd manager

System Commands:
  is-system-running               Check whether system is fully running
  default                         Enter system default mode
  rescue                          Enter system rescue mode
  emergency                       Enter system emergency mode
  halt                            Shut down and halt the system
  poweroff                        Shut down and power-off the system
  reboot [ARG]                    Shut down and reboot the system
  kexec                           Shut down and reboot the system with 
kexecec                           Shut down and reboot the system with kexec
  exit [EXIT_CODE]                Request user instance or container exit
  switch-root ROOT [INIT]         Change to a different root file system
  suspend                         Suspend the system
  hibernate                       Hibernate the system
  hybrid-sleep                    Hibernate and suspend the system

2.4 journal

systemd 自带日志服务 journald,该日志服务的设计初衷是克服现有的 syslog 服务的缺点。比如:

  • syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
  • 数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。

systemd journal 用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。

systemd journal 的优点如下:

简单性:代码少,依赖少,抽象开销最小。
零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
移植性:日志文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
性能:添加和浏览日志非常快。
最小资源占用:日志数据文件需要较小。
统一化: 各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记 录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
安全性:日志文件是可以验证的,让无法检测的修改不再可能。

要查看整个 journal,输入以下命令:

    journalctl

像许多其他的 Systemd 命令一样,该命令将输出通过管道的方式引向 less 程序,因此您可以使用空格键向下滚动,键入/(斜杠)查找,以及其他熟悉的快捷键。您也能在此看到少许颜色,像红色的警告及错误信息。

以上命令会输出很多信息。为了限制其只输出本次启动的消息,使用如下命令:

    journalctl -b

这就是 Systemd 大放异彩的地方!您想查看自上次启动以来的全部消息吗?试试 journalctl -b -1 吧。再上一次的?用 -2 替换 -1 吧。那自某个具体时间,例如2014年10月24日16:38以来的呢?

    journalctl -b --since=”2014-10-24 16:38”

即便您对二进制日志感到遗憾,那依然是个有用的特性,并且对许多系统管理员来说,构建类似的过滤器比起写正则表达式而言容易多了。

我们已经可以根据特定的时间来准确查找日志了,那可以根据特定程序吗?对单元而言,试试这个:

    journalctl -u gdm.service

(注意:这是个查看 X server 产生的日志的好办法。)那根据特定的进程号?

    journalctl _PID=890

您甚至可以请求只看某个可执行文件产生的消息:

    journalctl /usr/bin/pulseaudio

若您想将输出的消息限制在某个优先级,可以使用 -p 选项。该选项参数为 0 的话只会显示紧急消息(也就是说,是时候向 $DEITY 祈求保佑了)(LCTT 译注: D E I T Y 是 一 个 计 算 机 方 面 的 幽 默 , D E I T Y 是 指 广 义 上 的 “ 神 ” , DEITY 是一个计算机方面的幽默,DEITY 是指广义上的“神”, DEITYDEITY广前缀表示这是一个变量),为 7 的话会显示所有消息,包括调试消息。请查看手册 (man journalctl) 获取更多关于优先级的信息。

值得指出的是,您也可以将多个选项结合在一起,若想查看在当前启动中由 GDM 服务输出的优先级数小于等于 3 的消息,请使用下述命令:

    journalctl -u gdm.service -p 3 -b

最后,如果您仅仅想打开一个随 journal 持续更新的终端窗口,就像在没有 Systemd 时使用 tail 命令实现的那样,输入 journalctl -f 就好了。

二进制日志并不流行,但 journal 的确有它的优点,如非常方便的信息查找及过滤。

posted @ 2020-11-10 15:30  pwl999  阅读(311)  评论(0编辑  收藏  举报