systemd
简介
systemd 是由Lennart Poettering(当时就职于Red Hat公司)领导开发的一套Linux服务和系统管理工具,用来为Linux提供一种更高效的启动管理机制以替代曾经的initd守护进程,并为用户提供并行化管理服务。systemd在Linux启动时会作为系统的第一个进程(PID为1)启动,然后由其负责启动系统的其它进程,大多数现代 Linux 发行版(如 Ubuntu、Debian、Fedora、CentOS、Arch Linux 等)都默认使用systemd来管理服务和系统进程,systemd主要提供以下功能:
- 服务管理:管理各类服务的启动、自启动、停止
- 依赖管理:管理服务依赖关系,确保服务按正确顺序启动
- 日志记录:提供 journald 日志系统,收集和存储系统日志
- 设备和挂载管理:支持动态设备挂载和自动挂载
- 维护基本系统配置:管理系统主机名、日期、区域设置,维护已登录用户和网络时间同步等
配置文件
配置文件路径
systemd 的配置文件路径是编译时指定的,用户无法修改,systemd所有的配置文件基本都存放在以下几个目录中,根据优先级顺序依次为:
- /etc/systemd/:存放用户配置文件,优先级最高,如果其他目录中存在与该目录下的文件同名的配置文件,则该目录中的文件会覆盖其他路径中的同名文件
- /run/systemd/:运行时生成的配置文件目录,用于存放在运行时生成的单元文件等,优先级次于用户配置文件,通常由系统或服务动态创建
- /usr/lib/systemd/(或 /lib/systemd/):系统提供的默认配置文件,优先级最低,方便用户覆盖
除了以上目录外,用户还可以创建如/etc/systemd/*.conf.d/,/usr/lib/systemd/*.conf.d/等类似的drop-in配置子目录,这些drop-in将具有更高的优先级
配置文件说明
以上目录中通常同时包含多种不同类型的systemd配置文件,以/etc/systemd/为例,该目录下可能存在以下文件或目录:
- /etc/systemd/system.conf:系统级systemd配置文件,是systemd软件自身的配置文件,定义了很多影响 systemd 行为的全局设置。它控制系统级的资源管理、进程限制等
- /etc/systemd/user.conf:用户级别的systemd配置文件,类似于 system.conf,该文件控制的是用户级别的服务行为
- /etc/systemd/system/:存放全局的单元(Unit)文件,该目录中存放的单元文件通常是系统级的守护进程、服务、挂载单元、target单元、定时单元等,通常由管理员创建且需要root权限
- /etc/systemd/user/:用于存放用户级别的单元文件,通常是一些仅在用户会话中运行的服务,不需要root权限
- /etc/systemd/journald.conf:systemd日志系统journald的配置文件,用于定义日志的存储、大小、级别等参数
- /etc/systemd/network/:该目录用于配置与网络相关的systemd 网络管理单元,包含网络接口配置文件(如静态IP配置)等
- /etc/systemd/logind.conf:用于配置与systemd-logind相关服务,管理用户会话和登录等
配置文件语法
systemd的配置文件语法参考了XDG Desktop Entry规范,而XDG的语法又受到Windows中.ini文件的影响,以下是systemd中各类配置文件的一些通用语法规则:
- 配置文件都是纯文本文件,以key=value形式指定
- 空行和以#、;开头的文件会被忽略,因此这两个符号可用来写注释行
- 配置文件中,如果内容在一行中写不下,可以使用反斜杠\在下一行续写,systemd在读取时会将两行合并,并使用空格替换反斜杠。如果反斜杠后为注释行,则注释行会被忽略,systemd将合并注释行后的内容
- 配置文件中的布尔值可以以各种格式书写,如:1、yes、true、on等价;0、no、false、off等价
- 配置文件中的时间,不标注单位时默认以秒为单位,单位支持使用y(year,years)、M(months, month)、w(weeks, week)、d(days, day)、h(hours, hour, hr)、m(minutes, minute, min)、s(seconds, second, sec)、ms(msec)、us(usec)
- 配置文件支持使用C语言的转义字符
unit的类型
systemd将系统资源和服务抽象为各种单元(unit),并使用单元配置文件来创建和管理单元,systemd一共提供了11种unit:
- Service unit 用于定义和管理各类服务,如启动、停止、重启服务
- Socket Unit 用于管理网络或 FIFO管道,当有基于Socket的连接时自动启动对应的服务
- Target unit 将多个unit组合为一个组,进行统一的管理(开启、关闭、依赖等)
- Mount Unit 用于定义和管理挂载点
- Automount Unit用于自动挂载,通常与.mount 配合使用,仅在访问时才挂载资源
- Path Unit 用于监控文件或目录的状态变化,当条件满足时触发相关服务
- Slice Unit 切片单元,用于对一组进程进行系统资源的分配与限制
- Scope Unit 与service类似,但Scope是由systemd根据 D-bus 接口接收到的信息自动创建,通常用于管理非 Systemd启动的外部进程
- Device Unit 用于表示系统中的硬件设备
- Swap Unit 用于管理交换分区或交换文件
- Timer Unit 定时器,用来替代传统的crond等,以执行定时任务
unit的状态
系统中的unit通常可以处于以下状态,各种单元类型可能会在此基础之上具有许多额外的子状态
- active 活动状态,表示单元已经启动、激活等
- inactive 停止
- activating 正在启动
- deactivating 正在停止
- failed 失败
- maintenance 单元已停止,且在进行维护操作
- reloading 正在重新加载其配置
unit单元文件
单元文件路径
unit单元文件目录位于systemd配置文件路径下,根据优先级顺序依次为:
- /etc/systemd/system/:存放系统级单元文件,优先级最高,如果其他目录存在与系统单元文件同名的文件,则该目录中的文件会覆盖其他路径中的同名文件
- /run/systemd/system/:运行时生成的配置文件目录,用于存放在运行时生成的单元文件,优先级次于用户配置文件,通常由系统或服务动态创建
- /usr/lib/systemd/system/(或 /lib/systemd/system/):系统提供的默认单元文件,优先级较低,通常由软件包管理器安装配置
system目录用来存放系级单元文件,该路径下还存在user目录,如果需要存放用户单元文件,只需要将以上路径中的system改为user即可,单元文件名需要遵守以下规则:
- 单元文件名前缀可以包含字母、数字和-._:\符号
- 必须包含单元类型后缀,如:game-start.service
[Unit]块
[Unit]部分用来书写单元的通用信息,且所有类型的单元文件都会有该块,只列出了部分配置项,完整的[unit]块配置请参考:
Description=
指定对该单元的简短描述,根据官方文档,这里的属性虽然是Description,但所指定的字符串应该是对该单元功能或身份的简洁”标识”或”标签”,方便用户快速识别,而不是详细描述它,如果需要详细描述,应该写在Documentation字段指向的外部文档中。Description所指定的字符串,systemcted会在状态消息中(如执行 systemctl status时)显示该字符串(因此应该开头大写),如:Description=Nginx Web Server,systemd将在启动nginx时显示Starting Nginx Web ServerDocumentation=
该单元以及其配置文件的相关文档,可以指定多个URI(可以是URL或URN),使用空格进行分隔。这里的URI仅支持”http://“、”https://“、”file:”、”info:”、”man:” 类型的 URI,如:man:command(6)Wants=
指定该单元的弱依赖单元,即使依赖单元启动失败,该单元仍会继续运行。此选项可以多次指定,也可以在一个选项中指定多个空格分隔的单位。注意,该选项配置的依赖关系不会影响服务的启动顺序,通常情况下,依赖单元和当前单元会同时启动。向单元文件附带的 .wants/ 目录添加单元的符号链接等同于在该配置项中添加单元。Requires=
指定该单元的强依赖单元,该单位启动时,也将启动该选项配置的这些单元。如果依赖单元启动失败、中途被”显式”停止或重启,该单元也将相应地启动失败、停止、重启。但这并不意味着当此单元运行时,另一个单元必须始终处于活动状态,如:单元启动成功后,某些依赖单元完成使命正常退出,这将不会影响到当前的单元。向单元文件附带的 .requires/ 目录添加单元的符号链接等同于在该配置项中添加单元。Requisite=
类似于requires,但是,该选项配置的是当前单元运行的必要前提条件,即当前单元运行前,这些单元必须已经运行,如果该选项指定的单元未启动,systemd将不再尝试启动当前单元,而将直接判定启动失败。因此,该设置通常与 After= 结合使用,以确保当前单元不会在Requisite配置的单元之前启动BindsTo=
类似于requires,但BindsTo所绑定的依赖关系更强,除了拥有requires的特点外,BindsTo会将当前单元的生命周期绑定到依赖单元,当前单元的运行严格依赖于依赖单元的存续。BindsTo所绑定的单元如果停止,则当前单元也将停止。该配置项用于需要紧密关联的单元,例如一个服务与其挂载点的绑定,如果挂载点被卸载或停止,当前服务也停止Upholds=
类似于Wants,但不同点在于,当前单元对Wants所指定单元的依赖是一次性的,systemd只会在启动当前单元时尝试启动Wants中指定的依赖,后续这些依赖是否停止,systemd都不再关心。而当前单元对Upholds所指定单元的依赖是持续性的,如果后续当前单元还在运行,而Upholds单元中途停止,systemd将不断尝试重启它们,即便它们不是强依赖单元。Conflicts=
指定冲突单元,表示两个单元之间存在冲突关系,不能同时运行。如:假设A.service的配置文件中配置了Conflicts=B.service,则在启动A时,如果B正在运行,将关闭B。同样,如果启动B时,A正在运行,则将关闭A,即时B的配置中未显式声明Conflicts=A。注意,Conflicts同样不会指定服务的启动或关闭顺序,如果需要确保在启动A单元之前,先停止B单元,需要显式添加After或Before配置Before=
定义单元的启动顺序,表示当前单元必须在Before所指定的单元之前启动,关闭时必须在这些单元之后关闭。如:A的配置文件配置了Before=B,则A必须在B之前启动,在B之后关闭。After=
定义单元的启动顺序,表示当前单元必须在After所指定的单元之后启动,关闭时必须在这些单元之前关闭。如:A的配置文件配置了After=B,则A必须在B之后启动,在B之前关闭。ConditionPathExists=
检查所指定的路径和文件是否存在,如果指定的绝对路径名不存在,将停止启动单元。可以在路径前加上一个!,表示当该文件不存在时,才启动该单元
[Install]块
[Install]块用于配置单元的安装和启用信息,
Alias=
定义单元的别名,该别名必须与原单元文件名具有相同的后缀(即type),可以指定多个别名,空格分隔。指定了别名后,在使用systemctl enable开机自启用单元时,将在/etc/systemd/system对应目录中创建一个符号链接并指向/usr/lib/systemd/system目录中的原单元文件,此后,用户可以通过这些别名启动服务WantedBy=
指定当前单元希望被哪些单元作为依赖使用(弱依赖),可以指定多个值,空格分隔。指定了值后,当通过 systemctl enable 命令安装当前单元时(开机自启动),将会在这些WantedBy所指定的每一个单元的.wants/ 目录中创建一个当前单元的符号链接。这里通常会指定一个target类型的单元值,即指定当前单元在哪种Linux开机模式下会被启动,如:在服务A的配置文件中添加WantedBy = multi-user.target,则在执行systemctl enable A.service启用A单元后,systemd将在/etc/systemd/system/multi-user.target.wants目录中创建一个符号链接A.service,该符号链接指向/usr/lib/systemd/system/A.service,表示A服务会在Linux以常规多用户模式启动时开机自启动。当然配置的值也可以是其他unit类型,如:在服务A的配置文件中添加WantedBy = B.service,则A的符号链接将被添加到B.service.wants目录中,表示启动服务B时,希望启动A。指定服务依赖的功能和[Unit]块中的wants有点类似,不同点在于:- Wants指定当前单元需要哪些依赖,WantedBy指定当前单元是其他单元的依赖
- Wants指定单元运行时的依赖关系,单元的设置会在启动或加载时立即生效;WantedBy定义单元安装时依赖关系,需要使用 systemctl enable 使其生效
RequiredBy=
指定当前单元必须被哪些单元作为依赖使用(强依赖),这意味着当前单元的运行失败,将影响到其他单元的运行。用法与WantedBy类似,这里所指定的每一个单元,它们的.Requires/目录中将有可能被添加当前单元的符号链接(取决于当前单元是否开机自启动)UpheldBy=
指定当前单元是哪些单元的维持性依赖,具体的依赖关系参考[Unit]块的Upholds,用法与WantedBy类似,但它没有类似的.Uphold目录,用于动态维持目标状态,使用场景较少Also=
当使用systemctl enable 或 systemctl disable命令安装/卸载当前单元时,需要一起安装/卸载的其他单元,可以指定多个值,空格分隔
Service类型
[Service]块
[Service]块是service类型的单元文件专属块,也是必须块,[service]块的配置可参考:
Type=
用于定义服务的启动类型,指定systemd 如何识别服务的启动完成状态以及如何管理服务的主进程,它支持以下值:- simple:systemd在启动服务时,会fork()一个systemd服务管理子进程,然后在子进程中运行该服务。当指定Type=simple时,systemd服务管理器会在fork()结束后立即返回服务已经启动的状态,即便此时服务的二进制文件还未真正执行,甚至可能会执行失败(如权限不足),因此该值可能具有一些潜在风险(如systemctl start命令错误返回服务启动状态,systemd因为识别服务已经启动而继续启动其他依赖造成启动顺序错误),该值适用于一些简单的单进程服务或脚本。当指定了 ExecStart= 但未指定 Type= 和 BusName=时,该值是默认值
- exec:类似于simple,但systemd服务管理器会等到fork()结束且服务的二进制文件被执行后才返回服务已启动的状态,因此该值不会存在二进制文件执行失败,但systemd识别为服务已经启动的情况。如果二进制文件执行失败,systemctl start 命令将正确报告服务启动失败状态。建议对长时间运行的服务使用 Type=exec
- oneshot:类似于simple,但oneshot表示该服务是一次性的短期任务,systemd会在该服务成功执行并退出后才视为服务启动完毕,然后开始执行后续任务。该类型适合用来配置哪些需要前期迅速执行完毕,为后续任务铺设环境的一次性任务,如初始化脚本、配置加载、清理上次登录的临时文件等任务。该选项通常需要配合 RemainAfterExit=true 配置项,来让systemd在返回其状态时返回值为”active”,否则,由于该服务会在执行完毕后退出,会导致其状态会直接从”activating”跳到”dead”或”deactivating”。当Type=和ExecStart=配置均未指定时,systemd将默认指定Type=oneshot
- dbus:dbus的行为类似于simple,但这种类型的单元必须指定 BusName= 配置,相反,如果指定了BusName=的值而未指定Type,则默认为Type=dbus。服务通过D-Bus总线注册完成后,systemd才会认为它已启动,该类型适用于基于D-Bus的服务
- notify:notify的行为类似于exec,不同之处在于服务在完成启动时会通过 sd_notify()或其他兼容的库的类似调用向systemd 发送”READY=1”消息,来告诉systemd当前服务已经启动完成。systemd会等待通知消息后再认为服务已启动。适用于需要执行一些初始化工作后,明确通知启动完成的服务
- idle:类似于simple,但服务的启动会延迟到所有其他任务完成后再运行,避免服务启动时,shell的输出混乱。该值仅用于避免控制台输出混乱,不用作通用的unit启动排序工具,因此服务启动延迟时间限制为5s,超时后无论如何都会启动服务。可用于非关键任务,让它们系统启动完成后再启动
- forking:服务会通过父进程创建子进程(fork)的方式运行,并且父进程会退出,子进程作为服务的主进程。这是传统UNIX守护进程设计模式的一种方式,当一个进程启动时,通常会绑定到启动它的终端tty,如果终端关闭,进程可能会受到 SIGHUP 信号的影响而退出,因此传统的守护进程(daemon)设计时,会先启动一个父进程,然后通过fork()创建子进程,然后父进程退出,子进程作为主进程继续运行。此时子进程可以在一个相对干净的环境中运行,且脱离了终端控制,成为孤儿进程并交由systemd接管。当Type=forking时,systemd会在父进程退出时,视为服务启动完成,由于这是传统UNIX的设计,因此对于现代项目,文档不建议使用此类型,而是建议改用 notify、notify-reload 或 dbus。如果一定要用该类型,建议同时PIDFile= 选项一起使用,以便 systemd 能够可靠地识别服务的主进程
ExitType=
指定退出类型,告诉systemd服务管理器何时认为当前unit已经关闭,有以下两个取值:- main:默认值,当服务主进程退出时,认为该单元已经停止。由于oneshot类型的服务是在主进程退出后才视为服务开始启动,因此该值不能与Type=oneshot 一起使用,
- cgroup:只要 cgroup 中至少有一个进程尚未退出,该服务就会被视为正在运行
ExecStart=
启动服务时执行的命令,如果服务类型Type是oneshot,可以指定多个命令,否则只能指定一个命令!通过该命令启动的进程将被视为守护进程的主进程(Type=forking的服务除外,因为此时子进程才是主进程)。当Type=oneshot时,可以指定多个要执行的命令,空格分隔,systemd会依次执行它们,如果其中一个命令失败,则该单元会被视为启动失败。可以在命令前添加”-“,则此时即便该命令执行失败,systemd也会继续执行后续命令,且不会视为单元启动失败。RemainAfterExit=
一个boolean值,该值指定是否应将服务视为活动状态,即使其所有进程都已退出,默认为 no,通常Type=oneshot会用到该配置项PIDFile=
指定一个PID文件路径,通常是/run目录下的路径,该配置项通常用来搭配Type=forking配置,以此告诉systemd服务管理器从该PID文件中读取服务主进程的PID,文档建议现代项目中尽量少使用BusName=
指定服务应使用的D-Bus目标名称,该配置项是Type=dbus时的必须配置ExecStartPre=
在 ExecStart= 所指定的命令执行前执行的其他命令。语法与 ExecStart= 相同,但允许指定多个命令,命令会依次执行。这些命令中任何一个命令(不以”-“前缀)执行失败,都将不再执行后续命令,并视为该单元启动失败。ExecStart所指定的命令只会在ExecStartPre所指定的所有命令(不以”-“前缀)成功退出后才开始执行ExecStartPost=
在 ExecStart= 所指定的命令执行后执行的其他命令。语法与 ExecStart= 相同,但允许指定多个命令,命令会依次执行。这些命令中任何一个命令(不以”-“前缀)执行失败,都将不再执行后续命令,并视为该单元启动失败。ExecStartPost所指定的命令只会在ExecStart所指定命令成功启动后执行,具体执行时间取决于systemd何时收到服务启动通知,具体参考Type配置项各类型的服务何时视为启动成功ExecReload=
服务的配置被重新加载时需要执行的命令,可以指定多个命令,遵循与ExecStart=相同的配置方案ExecStop=
指定停止当前服务时用户需要输入的命令,该配置遵循与ExecStart=相同的配置方案,该配置项是可选的,如果没有设置该配置,则服务停止时,将通过发送 KillSignal= 或 RestartKillSignal= 中指定的信号来终止进程。ExecStopPost=
在服务停止后执行的其他命令,服务停止的方式可以是通过执行ExecStop所指定的命令、启动失败停止、服务意外退出、收到系统信号终止等,这些都会触发systemd执行ExecStopPost所指定的命令。该配置项常用来设置一些服务停止后的清理工作,或者服务启动失败时,清理不完整的初始化数据RestartSec=
指定重新启动服务之前的休眠时间,可以直接指定一个数值(单位为秒),也可以是时间跨度(如:5min 20s),默认为100msRestart=
配置在服务进程退出(exit)、终止(kill)或达到超时(timeout)时是否应重新启动服务,支持以下值:- no:默认值,不重启服务
- on-success:仅当服务服务正常退出(退出代码是零)时才重启
- on-failure:服务因非零退出代码或异常信号失败时重启
- on-abnormal:服务因异常信号(如:SIGKILL、SIGSEGV等)终止时会重启
- on-watchdog:服务因看门狗超时被杀死时会重启,适用于需要高可靠性的服务,并启用了看门狗功能。systemd中,看门狗是用来监控服务或进程是否正常运行的进程,服务需要每隔一段时间就向看门狗发送一个报告,来表示服务在正常运行,如果超时时间内没有报告,systemd会认为服务卡住或挂起,然后会尝试重启或唤醒服务
- on-abort:服务因收到 SIGABRT信号终止时会重启,适用于需要响应服务主动触发中止操作的场景
- always:无论服务如何退出(成功、失败或异常),都进行重启
StandardInput=
控制标准输入连接到何处,可取以下值:- null:(默认)连接到/dev/null,进程的所有读取尝试都将导致立即 EOF
- tty:连接到 TTY,通常还需要用TTYPath指定tty的挂载路径
- file:绝对路径:连接到该文件
- data:传递一段文本或二进制数据给当前服务,传递内容通过StandardInputText=/StandardInputData=指定
StandardOutput=
控制标准输出连接到何处,可取以下值:- inherit:将标准输入的文件描述符复制给标准输出
- null:连接到 /dev/null,丢弃所有输出
- tty:连接到 TTY,通常还需要用TTYPath指定tty的挂载路径
- journal:(默认)连接到journal日志
- kmsg:连接到内核日志缓冲区
- journal+console:连接到日志并输出一份到控制台
- file:绝对路径:连接到该文件
- append:绝对路径:以附加形式连接到该文件
StandardError=
控制标准错误输出连接到何处,可取与StandardOutput相似StandardInputText=, StandardInputData=
指定一段文本或二进制数据,通过标准输入传递给当前服务,需要指定 StandardInput=data,否则该配置项不生效
service配置案例
[Service] Type=oneshot #simple类型不会等待脚本执行完毕返回,oneshot则会等待脚本执行 ExecStart=/myShell/testA.sh StandardOutput=tty StandardError=tty TTYPath=/dev/pts/0 ExecStartPre=/bin/echo "服务A启动" 5.编写/etc/systemd/system/testB.service内容 [Unit] Description=test B service
[Service] Type=simple ExecStart=/myShell/testB.sh 6.让systemd重新加载配置 systemctl daemon-reload 7.执行testA服务 systemctl start testA
Target类型
介绍
target 是一种特殊的单元类型,用于将多个相关的服务或单元组合到一起,然后一次性启动或关闭,这样就不需要手动一个个启动这些单元了。systemd预定义了一些target类型的单元,用于在特定情况启动(如:插入声卡、连接蓝牙时),其中包括一些系统关闭或启动时会执行的单元,这些target类型的单元对应传统的 SysV 运行级别(runlevel),用户也可以自行创建并配置target单元
target类型的Unit单元配置文件仅支持[Unit] 和 [Install]配置块,不存在专属[Target]块
运行级别与预定义Target
运行级别(runlevel) | systemd target(target别名) | 说明 |
---|---|---|
0 | poweroff.target(runlevel0.target) | 关机 |
1 | rescue.target(runlevel1.target) | 单用户状态,只启动系统核心,用于系统修复和维护 |
2 | multi-user.target(runlevel2.target) | 多用户状态,禁用NFS(网络文件系统)和网络服务,可用于停机维护 |
3 | multi-user.target(runlevel3.target) | 完全多用户状态,具有完整的功能 |
4 | 无 | 系统未使用,保留 |
5 | graphical.target(runlevel5.target) | GUI模式,桌面版Linux专属 |
6 | reboot.target(runlevel6.target) | 系统重启 |
target常用命令
systemctl isolate target名临时切换到该target(可以实现临时切换运行级别)
systemctl set-default target名设置默认目标(持久化修改开机运行级别)
开机自启动与target
当用户执行systemctl enable unit名设置单元开机自启动时,systemd会在/etc/systemd/system/multi-user.target.wants/(假设当前开机默认启动target为multi-user.target)中创建一个该单元文件的符号链接,这样就实现了开机启动该单元的功能。相反,当用户执行systemctl disable unit名来禁止单元开机自启动时,systemd会删除/etc/systemd/system/multi-user.target.wants/unit名 符号链接,从而阻止其在系统启动时自动启动。
systemctl
systemctl是systemd的提供的主要命令行工具,用来通过统一的接口来管理系统的各项服务,调用systemctl时会默认使用--system选项,用于管理系统级单元,这可能需要root权限。如果需要管理用户级单元,应该显式指定systemctl --user
系统管理
在systemd被广泛运用到各发行版中后,Linux中传统的系统管理命令(如:halt、poweroff、reboot等)通常会调用systemd 提供的命令,如:执行 halt 实际上会调用 systemctl halt命令
- systemctl is-system-running检查系统是否正常运行,是则返回0,如果系统处于正在启动、维护、关闭状态,或者有失败的启动服务时,返回非零值
- systemctl default进入默认模式
- systemctl rescue进入救援模式
- systemctl emergency进入紧急模式
- systemctl halt关闭系统,但保持硬件的开机状态
- systemctl poweroff关闭系统并关闭系统电源
- systemctl reboot重启系统
- systemctl soft-reboot软重启,重新启动用户空间
- systemctl suspend挂起(暂停)系统,系统会将当前的会话状态(如打开的应用程序和文件)保存在内存中,并将设备置于低功耗状态
- systemctl hibernate进入休眠状态,休眠模式会将系统的当前状态保存到硬盘(通常是交换分区或交换文件),然后完全关闭电源,下次开机将从硬盘恢复系统状态
- systemctl hybrid-sleep进入混合睡眠状态,该状态下,系统首先将当前会话状态保存在内存中,并备份一份到硬盘,然后将设备置于低功耗状态。如果之后系统正常唤醒,直接从内存加载数据。如果系统意外关闭(例如电源耗尽),用户也可以从硬盘恢复数据
- systemctl suspend-then-hibernate挂起后休眠,在这种模式下,系统首先进入挂起状态(suspend),将当前会话的状态保存在内存中,在一定时间后(通常是系统设置的超时设置),如果没有用户活动,系统会自动切换到休眠状态(hibernate),将会话状态保存到硬盘中并完全关闭电源,此模式适合用户需要短时间内离开电脑,但又希望在长时间未使用时确保数据安全的状况
- systemctl sleep进入睡眠状态,sleep模式在不同发行版中设置可能有所不同,可能执行suspend、hibernate、hybrid-sleep、suspend-then-hibernate中的任意一种,默认情况下,通常可能为suspend-then-hibernate
查看系统状态
systemctl status查看系统状态
systemctl --failed列出失败的单元
systemctl list-unit-files列出已经安装的单元
systemctl status PID值查看对应PID进程的状态
systemctl daemon-reload重新加载systemd单元配置,扫描单元变动
单元管理命令
systemctl [选项] 命令 单元名/模式
- -t unit类型(--type=unit类型):在列出unit单元信息时,默认会列出所有类型的单元,通过该选项可以指定只列出某几个类型的单元
- --state=状态:在列出unit单元信息时,默认会列出所有状态的单元,通过该选项可以指定只列出处于所指定状态的单元
- -p 属性名(--property=属性名):显式属性时,默认显式所有属性,该选项可以用来指定只显示所指定的1个或多个属性
- 该命令中的单元名,可以使用模式(PATTERN)来匹配多个单元(模式支持使用*和?,也支持使用[]匹配字符范围),也可以是具体的单元名,当指定具体单元名时,需要指定其完整的单元名,包括扩展名(如:sshd.socket),以下情况可以省略扩展名:
- 如果不指定拓展名,systemctl会默认扩展名为.service,因此如果操作对象的unit类型为service,可以不指定拓展名
- 挂载点会自动指定为.mount单元,如:/home等价于home.mount
- 设备会自动指定为.device单元,如:/dev/sda2等价于dev-sda2.device
- 某些命令只能用来处理特定类型的单元,此时可以省略单元类型,如:systemctl isolate默认单元类型为target
常用的单元管理命令
命令 | 说明 |
---|---|
systemctl status 单元名或PID单元名 | 查看单元或PID所属单元状态 |
systemctl start单元名 | 启动单元,只能启动已经被systemd加载的单元 |
systemctl stop单元名 | 停止单元 |
systemctl restart单元名 | 重启单元,如果单元未启动,则启动单元 |
systemctl try-restart 单元名 | 重启已启动的单元,如果单元未启动,则不做任何操作 |
systemctl reload单元名 | 让该单元重新加载其配置 |
systemctl reload-or-restart 单元名 | 尝试让单元重新加载其配置,如果加载失败,则尝试重启它。如果指定的单元尚未启动,则启动它 |
systemctl try-reload-or-restart 单元名 | 尝试让单元重新加载其配置,如果加载失败,则尝试重启它。如果指定的单元尚未启动,则不做任何操作 |
systemctl enable单元名 | 开机自启动该单元 |
systemctl disable单元名 | 取消开机自启动 |
systemctl reenable单元名 | 重新启用单元 |
systemctl mask单元名 | 屏蔽单元,该单元将无法手动启动,也无法作为依赖启动 |
systemctl unmask单元名 | 取消屏蔽单元 |
systemctl status返回值
- systemctl status [单元名或PID]
如果指定了单元,则显示指定单元的运行时状态信息,以及这些单元最近的日志数据。如果指定了PID,那么显示指定PID所属单元的运行状态信息,以及这些单元最近的日志数据,默认输出10行日志,且会截断超长的部分。如果未指定任何单元或PID,那么显示整个系统的状态信息,此时若与 --all 连用,则同时显示所有已加载单元(可以用-t选项限定单元类型)的状态信息。该命令旨在生成人类可读的输出,如果需要输出方便脚本分析的信息,应该使用systemctl show命令
Nov 18 10:15:42 server-name nginx[1234]: 2021/11/18 10:15:42 [error] 2345#0: *1 open() …
Nov 18 10:15:53 server-name nginx[1234]: 2021/11/18 10:15:42 [error] 2345#0: *1 open() …
单元状态查询命令
systemctl 或 systemctl list-units 单元名
列出systemd已经加载的单元,默认列出处于活动、失败状态和正在处于任务队列的单元,使用--all选项可以列出所有单元,可以使用--type选项和--state选项过滤要列出的单元systemctl list-sockets [PATTERN] 单元名
列出已加载的套接字(socket)单元,并按照监听地址排序。使用--show-types选项可以显示套接字类型,支持--all和--state选项
systemctl list-timers [PATTERN]
列出已加载的定时器(timer)单元,并按照下次执行的时间点排序,支持--all和--state选项systemctl is-active 单元名
检查指定的单元中,是否有处于活动(active)状态的单元。如果存在至少一个处于活动(active)状态的单元,返回状态0,否则返回非零值。命令还会在标准输出打印单元状态,使用--quiet选项可以禁止该输出systemctl is-failed 单元名
检查指定的单元中,是否有处于失败(failed)状态的单元。如果存在至少一个处于失败(failed)状态的单元,返回状态0,否则返回非零值。命令还会在标准输出打印单元状态,使用--quiet选项可以禁止该输出systemctl show [单元名或JOB]
以”属性=值”的形式显示指定单元或任务的所有属性。单元用其名称表示,而任务则用其id表示。如果没有指定任何单元或任务,那么显示管理器(systemd)自身的属性。默认不显示属性值为空的属性,使用--all选项可以显示所有属性。可以使用--property选项可以仅显示特定的属性systemctl cat 单元名
显示指定单元的单元文件内容,首行会显示该单元文件的绝对路径systemctl set-property 属性名 值
在运行时修改单元的属性值,主要用于修改单元的资源控制属性值而无需直接修改单元文件,并非所有属性都可以在运行时被修改。 作修改会立即生效,并永久保存在磁盘上,以确保永远有效。如果使用了 --runtime选项,那么此修改仅临时有效,下次重启此单元后,将会恢复到原有的设置。设置属性的语法与单元文件中的写法相同。如:systemctl set-property foobar.service CPUShares=777,可以同时修改多个属性值,只需依次将各个属性用空格分隔即可。systemctl list-dependencies [单元名]
显示单元的依赖关系,即显示由 Requires=, Requisite=, ConsistsOf=, Wants=, BindsTo= 所形成的依赖关系。如果没有明确指定单元的名称,那么表示显示default.target的依赖关系树。默认情况下,仅以递归方式显示 target 单元的依赖关系树,而对于其他类型的单元,仅显示一层依赖关系(不递归)。 但如果使用了--all 选项,那么将对所有类型的单元都强制递归的显示完整的依赖关系树。还可以使用 --reverse, --after, --before 选项指定仅显示特定类型的依赖关系
systemd-journald
systemd-journald是systemd内置的日志收集和存储服务
日志文件存储路径
systemd-journald保存日志的方式有两种:volatile(临时存储,存储于内存)和persistent(持久化存储,存储于磁盘),当前使用哪种存储方式取决于配置文件中的Storage配置项:
- 持久化日志的存储位置为:/var/log/journal/
- 临时日志的存储位置为:/run/log/journal/,该路径下存储的日志会在系统重启时丢失
systemd-journald收集的日志文件通常分为两种,一种是当前处于活跃状态的(active),通常文件名为system.journal,活跃状态的文件是journald正在写入的文件,通过journalctl命令删除日志时无论如何不会删除活跃的日志文件;另一种是已经归档的(archived)日志文件,文件名通常包含日志时间范围和系统标识符的哈希值,类似于system@0-000027b7a-000158412d.journal
,journald不会向这类文件再写入东西,这些通常是旧的日志文件。
journalctl日志命令
systemd-journald是以二进制格式存储日志的,不能使用传统vim、cat等工具直接打开,需要使用journalctl命令
journalctl [选项]
- 默认情况下将显示所有日志,旧的日志显示在前,以分页形式显示,长行会被截断为屏幕宽度,可以使用左右箭头查看截断部分
- -r 倒叙查看,最新的日志排于前
- 字段=值:过滤出指定的字段,如:_PID=1234(查看该PID服务的日志),_UID=1111(查看该用户的日志)
- -n 值:显示指定数量的日志条目
- -u 服务名:查看指定服务的日志
- --since 日期:查看指定日期之后的日志,规范的指定日期形式为”yyyy-MM-dd HH:mm:ss”
- --untile 日期:查看指定日期之前的日志,规范的指定日期形式为”yyyy-MM-dd HH:mm:ss”
- -f 实时查看日志,类似于tail -f命令
- -p 日志等级:查看指定等级以上的日志,可取值有emerg, alert, crit, err, warning, notice, info, debug,也可以使用0-7的值依次代替这些等级
- -o 输出格式:指定日志的输出格式,常用的输出格式有
- short:简洁格式
- verbose:详细格式
- json:JSON格式
- cat:仅显示日志内容,不包含其他信息
- --no-pager 禁用分页模式
- --disk-usage 显示所有日志文件在当前磁盘的占用情况
- --rotate 立即开始日志轮换,将当前活跃的日志文件立即归档并重命名,然后标记为archived,然后新建新的日志文件作为活跃文件
- --vacuum-size=值:删除最早的归档日志,直到日志所占用空间小于指定值,接受K、M、G、T单位
- --vacuum-time=值:删除早于指定时间跨度的归档日志,单位默认为s,接受m、h、days、weeks、months、years单位
- --vacuum-files=值:只保留指定数量的归档日志文件
- --sync 立即将日志同步到磁盘,在同步操作完成之前,此调用不会返回
日志服务配置文件
日志配置文件journald.conf的主文件路径是systemd编译时指定的,无法修改,这些路径包括/etc/systemd/、/run/systemd/、/usr/local/lib/systemd/、/usr/lib/systemd/,它们的优先级也是固定的,journald会按照上述顺序查找配置文件,只会加载第一个找到的文件。主配置文件用来定义系统默认配置,一般情况下,绝大部分Linux发行版的主配置文件只有/etc/systemd/journald.conf文件,且该文件中的配置项是被注释掉的,这是因为日志的默认配置在编译时内置到了journald服务中,journald.conf文件中的内容只是对这些默认值的说明,用来帮助管理员了解可以配置的选项及其默认行为。
除了主配置文件,日志服务还会从/usr/lib/systemd/journald.conf.d/、/usr/local/lib/systemd/journald.conf.d/、/etc/systemd/journald.conf.d/路径中查找配置文件,这些路径中的配置会覆盖系统的默认主配置,且这些路径中的配置文件会按上述顺序全部加载,对于只接受单个值的配置项,后面的配置会覆盖前面的,而对于接受多个值的配置项,所有配置都将生效。换而言之,/etc/systemd/journald.conf.d/路径下的配置文件优先级将是最高的,同一目录中的配置文件会按文件名字典顺序加载。
通常情况下,如果要修改日志的配置,只需要修改/etc/systemd/journald.conf文件即可,如果需要为不同的Unit单元或服务定制专属日志配置,则可以在/etc/systemd/目录中新建journald.conf.d(该目录通常需要自行创建),然后在该目录中创建新的日志配置文件,如:my-global-settings.conf,该文件的优先级将是最高的,/etc/systemd/journald.conf文件的默认配置如下:
配置文件语法
Storage=
指定日志数据的存储方式,可以为以下值:- volatile:日志只存储于内存中,存储位置为:/run/log/journal,存储内容会在系统重启后丢失
- persistent:日志存储在磁盘上,存储位置为:/var/log/journal,但在系统引导初期(boot)以及磁盘无法写入时将回滚为volatile模式
- auto:如果目录/var/log/journal 存在,则写入磁盘,否则将回滚为volatile模式
- none:关闭日志存储,所有日志将被丢弃(但被转发到其他目标位置,如被转发到控制台、内核日志缓冲区或 syslog 套接字的配置仍将有效)
Compress=
指定日志是否压缩,需要指定一个boolean值,默认为yes,此时会将大于默认阈值512bytes的数据进行压缩。也可以直接指定一个值,表示进行压缩的阈值,可以使用K、M、G等单位Seal=
指定是否为持久化的日志文件启用安全密封(FSS),以保护日志文件免受纂改,需要指定一个boolean值,默认为yesSplitMode=
指定日志的分割方式,可以取以下值:none :默认值,不分割日志uid :按用户ID分割日志
RateLimitIntervalSec=,RateLimitBurst=
用于限制日志的写入速率,防止占用太多系统资源,默认值为30s内最多允许写入1000条日志,多余的日志会被丢弃。RateLimitIntervalSec用于指定限制时间,默认值为30,可以使用s、min、h、ms、us单位;RateLimitBurst用于指定上述时间内的限制写入条数,默认值为1000,二者需要搭配使用。当达到限制速率时,systemd-journald 会生成类似日志信息:”Rate limit reached for messages, suppressing X messages from Y services”,X表示被丢弃的日志数量,Y表示服务来源。将值设置为0表示不进行任何限制
RuntimeMaxUse=,SystemMaxUse=
指定内存,磁盘中日志最大占用空间,默认值均为当前文件系统大小的10%,上限为4G,当日志存储空间接近限制时,journald会删除旧的归档日志RuntimeKeepFree=,SystemKeepFree=
指定需要为内存,磁盘保留多大空闲空间,默认值均为当前文件系统大小的15%,上限为4G。当内存或磁盘空间被非日志文件占用,剩余空间低于该设置的值时,journald将停止写入新日志,但不会去删除旧日志(是否删除旧日志取决于RuntimeMaxUse=或SystemMaxUse=设置的阈值)RuntimeMaxFileSize=,SystemMaxFileSize=
指定单个日志文件的最大大小,达到此大小时,journald会创建一个新文件,默认值为SystemMaxUse= 和 RuntimeMaxUse= 的1/8,最大上限为128M,即如果SystemMaxUse的1/8超过了128M,上限仍为128M,如果启用了日志压缩,最大限制为4GRuntimeMaxFiles=,SystemMaxFiles=
指定日志文件的最大数量,达到限制后,旧的日志文件会被删除,默认值为100MaxFileSec=
指定单个日志文件能够记录数据的最长时间,一旦时间达到这个值,当前日志文件将被关闭并归档,journald 会启动一个新的日志文件来存储后续日志,默认值为1个月,可以使用year、month、week、day、h或m作为时间单位,默认单位为s,设置为0可以关闭此功能。如果日志数据量很大时,文件也有可能会因为达到SystemMaxFileSize值而被强制轮换,导致单个文件中记载的时间不足该指定值MaxRetentionSec=
指定日志的最长保留时间。如果日志文件的最后修改时间早于这个时间阈值,它们将被删除。默认值为0,可以使用year、month、week、day、h或m作为时间单位,默认单位为s,设置为0可以关闭此功能。SyncIntervalSec=
控制 journald 将内存中缓存的日志条目写入磁盘以持久化保存的时间间隔,默认值为5min写入一次。CRIT、ALERT 或 EMERG级别的日志会被立即写入磁盘而不受此设置影响,此设置仅适用于ERR、WARNING、NOTICE、INFO、DEBUG 级别的日志消息ForwardToSyslog=, ForwardToKMsg=, ForwardToConsole=, ForwardToWall=, ForwardToSocket=
指定是否需要将日志转发到传统日志服务(syslog,默认为no)、内核日志缓冲区(/dev/kmsg,默认为no)、控制台(默认为no,可以通过TTYPath指定转发到哪个控制台)、所有登录用户(类似于wall命令,默认为yes)、Socket服务(该服务为/run/systemd/journal/socket上所监听的服务,如果要指定该配置则需要指定该服务的地址,默认无转发),以上设置,默认仅启用转发到wall(且只有出现emerg级别的日志时才转发,参考MaxLevelSocket配置)TTYPath=
指定日志转发的TTY设备设备路径,仅在 ForwardToConsole=yes 时生效,默认为/dev/consoleMaxLevelStore=, MaxLevelSyslog=, MaxLevelKMsg=, MaxLevelConsole=, MaxLevelWall=, MaxLevelSocket=
指定存储、转发到syslog、内核日志缓冲区、控制台、所有登录用户、Socket服务的日志其日志等级,可选值有:emerg、alert、crit、err、warning、notice、info、debug,以下为默认值:- MaxLevelStore=debug
- MaxLevelSyslog=debug
- MaxLevelKMsg=notice
- MaxLevelConsole=info
- MaxLevelWall=emerg
- MaxLevelSocket=debug
ReadKMsg=
控制journald是否读取内核环形缓冲区(/dev/kmsg)中的日志消息,这些消息通常由内核及其模块生成,是系统启动、硬件事件和内核日志的重要来源,默认为yesAudit=
控制 journald 是否从内核审计子系统(Audit Framework)读取审计日志,审计日志记录系统的安全相关事件(如用户登录、权限更改等),通常由内核的审计功能生成,默认为yesLineMax=
指定journald从stdout/stderr读取流数据,并将其转换为记录日志时允许的最大行长度,默认为48k,超出部分会被journald截断并添加…后缀,表示此行已被截断。可以使用K、M、G、T为单位,最小可设置的值为79(bytes),小于该值的设置会被提升到79bytes