管理coredump
注:debian testing中systemd(204)的coredumpctl目前不可用,打包时候选择了
--disable-coredump
,原因不明。本节实验在fedora20上完成(with systemd-208)。开启core dump
#ulimit -c
输入以上命令看看返回值,如果是非0,则表示core dump功能已开启,如果是0,需要手动开启。
手动开启(例:无限制存储、64MB)
#ulimit -c unlimited
#ulimit -c 67108864
注:以上设置只在当前终端下生效,全局设置可以在
/etc/profile.d/
目录新建配置文件写入配置信息。获取core dump文件
systemd下使用coredumpctl工具获取的core dump是来自它的journal,即在磁盘目录上是找不到存储文件的(注:215有变化,见下面)。
查看所有的core dump记录:
# systemd-coredumpctl
# systemd-coredumpctl list '要匹配的字符串'
需要将core dump导出为文件,只需指定
--output=FILE
。另外coredumpctl可以根据PID、进程名称、执行路径等对code dump进行筛选,更多选项请man coredumpctl
。
注:systemd-215开始,可以配置为自动将coredumps存储在磁盘上(
/var/lib/systemd/coredump
,可能会经过压缩)。这个选项是默认开启的,配置文件在/etc/systemd/coredum.conf
。
若要配置为在指定目录获取core dump文件,而不通过systemd,只需配置
kernel.core_pattern
参数即可。
/sysctl/kernel.txt#core_pattern:
If the first character of the pattern is a '|', the kernel will treat the rest of the pattern as a command to run. The core dump will be written to the standard input of that program instead of to a file.
这个文件的默认值在systemd 下,是一个以'|' 字符(其实就是个管道)开头的字符串,一般类似:
| /usr/lib/systemd/systemd-coredump [参数](参数请在上文链接中中搜索'corename format specifiers')
若我们期望在指定目录(例如当前目录)立刻产生转储文件,那么只需要修改core_pattern 为如下:
#sysctl -w 'kernel.core_pattern=%t-%e-%p-%c.core'
在Fedora上,
kernel.core_pattern=core
,即默认可在程序目录下看到core.*
文件。
关于core dump的过滤,systemd并没有提供更多的途径,依然是通过内核存储掩码来配置(
coredump_filter
),具体请查看上文的/sysctl/kernel.txt
。本节参考链接
- coredumpctl-Retrieve coredumps from the journal
- systemd 下的core dump(内核转储)
- systemd-devel-ANNOUNCE-systemd 215
日志的记录,分类,过滤,分发和监控
Systemd Journal 特点
systemd 自带日志服务 journald,该日志服务的设计初衷是克服现有的 syslog 服务的缺点。比如:
- syslog 不安全,消息的内容无法验证。每一个本地进程都可以声称自己是 Apache PID 4711,而 syslog 也就相信并保存到磁盘上。
- 数据没有严格的格式,非常随意。自动化的日志分析器需要分析人类语言字符串来识别消息。一方面此类分析困难低效;此外日志格式的变化会导致分析代码需要更新甚至重写。
Systemd Journal 用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。无需自己编写复杂脆弱的字符串分析处理程序。
Systemd Journal 的优点如下:
- 简单性:代码少,依赖少,抽象开销最小。
- 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
- 移植性:日志 文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
- 性能:添加和浏览 日志 非常快。
- 最小资源占用:日志 数据文件需要较小。
- 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。Syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
- 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
- 安全性:日志 文件是可以验证的,让无法检测的修改不再可能。
日志记录
Messages coming in via /dev/log, via the native protocol, via STDOUT/STDERR of all services and via the kernel are received in the journal daemon.
Journal通过以下三种方式收集日志:
- 程序使用libc库 syslog()输出的日志
- 内核使用printk()函数打印的日志
- 任何服务进程输出到STDOUT/STDERR的所有内容
syslog()
用法例1(C):
#include <syslog.h>
void syslog(int priority, const char *message, ... /* argument */);
#include <syslog.h>
int main(int argc, char *argv[]) {
syslog(LOG_NOTICE, "Hello World");
return 0;
}
用法例2(Python): - syslog
#!/usr/bin/evn python
import syslog
syslog.syslog('Hello World')
编写简单的service单元文件调用log.py。
或用journalctl命令查看。
查看生成的日记格式(JSON)(
journalctl -o json-pretty -f
):{
"__CURSOR" : "s=0e4330b5048f4ee09c213caf4c99f294;i=d1f;b=49cbe7a3d....",
"__REALTIME_TIMESTAMP" : "1406216993978340",
"__MONOTONIC_TIMESTAMP" : "24171673254",
"_BOOT_ID" : "49cbe7a3d9f646beb526340832a145e6",
"PRIORITY" : "6",
"_UID" : "0",
"_GID" : "0",
"_SYSTEMD_SLICE" : "system.slice",
"_MACHINE_ID" : "0de206a66f9cf937239d126753c62e2f",
"_HOSTNAME" : "debian",
"_CAP_EFFECTIVE" : "1fffffffff",
"_TRANSPORT" : "syslog",
"MESSAGE" : "Hello World",
"SYSLOG_FACILITY" : "1",
"SYSLOG_IDENTIFIER" : "log.py",
"_PID" : "7643",
"_COMM" : "python",
"_EXE" : "/usr/bin/python2.7",
"_CMDLINE" : "python /root/log.py",
"_SYSTEMD_CGROUP" : "/system.slice/python-syslog.service",
"_SYSTEMD_UNIT" : "python-syslog.service",
"_SOURCE_REALTIME_TIMESTAMP" : "1406216993976092"
}
prntf()
如上文提到的,journal可以捕获服务进程往STDOUT/STDERR输出的所有内容,即例如C语言中的print函数打印的内容,Python中print打印的内容,以及Shell脚本中echo打印的内容等等都可以被journal捕获到,加入服务进程日志。
例:
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n");
return 0;
}
如一般的printf打印内容,日志等级为LOG_INFO(可以通过service单元文件中的",
SyslogLevel=
更改默认日志等级)。如何指定日志等级,可在每行打印内容前加上"N
为需要指定的日志等级。如下:#include<stdio.h>
#define PREFIX_NOTICE "<5>"
int main(void){
printf(PREFIX_NOTICE "Hello World\n");
fprintf(stderr, "<3>Hello Error\n");
return 0;
}
其他例子:
#!/usr/bin/env python
print '<5>Hello World'
#!/bin/bash
echo "<5>Hello World"
Native Messages
systemd提供了原生的C语言库(
systemd/sd-journal.h
),用于向系统journal提交日志。 详情请查看systemd/sd-journal.h。
例(未实验,例子与实验结果摘录自Lennart的blog):
#include <systemd/sd-journal.h>
int main(int argc, char *argv[]) {
sd_journal_print(LOG_NOTICE, "Hello World");
return 0;
}
相比上文使用print()或者syslog()提交的日志,使用sd_journal_print可以直观的指定LOG等级、日志内容等等,另外输出的日志会包含执行代码的位置信息,例如执行到的函数,代码文件位置,代码具体行数,方便开发人员调试。
除了可以包含代码信息,也可以向提交的日志中加入自定义段包含更多自定义信息,配合journalctl工具,可以更方便的过滤日志。
例:
#include <systemd/sd-journal.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
sd_journal_send("MESSAGE=Hello World!",
"MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555",
"PRIORITY=5",
"HOME=%s", getenv("HOME"),
"TERM=%s", getenv("TERM"),
"PAGE_SIZE=%li", sysconf(_SC_PAGESIZE),
"N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN),
NULL);
return 0;
}
使用journalctl,通过指定自定义条目,快速过滤日志。
extension for systemd
除了systemd提供的一套C语言库,目前其他个别语言也衍生了systemd的相关扩展,其中就包含了和journald相关的扩展。
from systemd import journal
journal.send('Hello world')
journal.send('Hello, again, world', FIELD2='Greetings!', FIELD3='Guten tag')
var journald = require('journald').Log;
journald.log({
MESSAGE: 'Hello world',
ARG1: '',
ARG2: '',
ARG3: ''
});
<?php
sd_journal_send('MESSAGE=Hello world.');
sd_journal_send('MESSAGE=Hello, again, world.', 'FIELD2=Greetings!', 'FIELD3=Guten tag.');
sd_journal_send('ARBITRARY=anything', 'FIELD3=Greetings!');
local fmt = require('string').format
local Journal = require('systemd-journal')
j = Journal:new()
j:print(1, "Hello World From Print")
j:send({PRIORITY=1, MESSAGE="Hello World From Send", VERSION=process.version})
本小节参考链接
日志存储
systemd中日志不再以文本格式保存, Journal用二进制格式保存所有日志信息,用户使用 journalctl 命令来查看日志信息。
默认情况下(当 Storage= 在文件 /etc/systemd/journald.conf 中被设置为 auto(注:debian中默认该选项进行了注释,默认为auto,但是需要手动创建存储目录)),日志记录将被写入 /var/log/journal/。该目录是 systemd 软件包的一部分。若被删除,systemd 不会自动创建它,直到下次升级软件包时重建该目录。如果该目录缺失,systemd 会将日志记录写入 /run/systemd/journal。这意味着,系统重启后日志将丢失。
手动创建日志储存目录:
# mkdir -p /var/log/journal
重启之后,可在
/var/log/journal/$MACHINE_ID/
目录发现存储的日志文件,\$MACHINE_ID为系统本机的ID,详细介绍请参考Machine ID一节。
注:journal会自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽,默认日志存储限制为所在文件系统容量的10%。 可在journald.conf文件中通过配置SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= 等选项来设置日志占的占的磁盘空间比率、systemd-journal必须给系统空出的文件系统容量等等,具体请参考本节参考链接4。
日志过滤和分发
过滤
systemd journal的工具journalctl提供了强大的日志过滤功能,可以按日志等级、进程ID、UID、GID、单元、执行路径、设备路径、时间区间、主机名、程序名等过滤,设置将这些选项进行配合使用过滤日志,详情请参考本节参考链接3与journalctl 用户手册。
使用示例:
显示本次启动后的所有日志:
# journalctl -b
显示本地启动后,且等级为err的日志:
#journalctl -b -p err
动态跟踪最新日志:
# journalctl -f
显示特地时间区间内的日志:
#journalctl --since=yesterday
#journalctl --since=2012-10-15 --until="2011-10-16 23:59:59"
显示某磁盘设备相关的日志:
#journalctl /dev/sda
显示特定程序的所有消息:
# journalctl /usr/lib/systemd/systemd
显示特定进程的所有消息:
# journalctl _PID=1
显示指定单元的消息(+时间区间):
# journalctl -u httpd
# journalctl -u httpd --since=00:00 --until=9:30
显示与指定用户相关的日志:
# journalctl _UID=70
# journalctl _UID=70 _UID=71
http://0pointer.de/blog/projects/journalctl.html #And now, it becomes magic!
分发
systemd journal本身未提供日志分发功能。
- 常见的解决方案,做好单机日志的存储配置之后,通过rsync、btsync等工具收集同步日志至某中心节点进行分析处理。
- 另外在systemd-193添加了systemd-journal-gatewayd.service,服务器开启此服务之后,将监听本地19531端口,其他机器可通过HTTP或JSON协议访问服务器得到后者日志,详细介绍(登录验证等)请查看systemd-journal-gatewayd.service。
- 注:systemd-212引入了 systemd-journal-remote >systemd-journal-remote is a command to receive serialized journal events and store them to the journal.
日志监控和报警
journal没有监控和报警方面的特性与功能,可以通过日志工具的过滤再配合脚本或程序做监控与报警。
本节参考链接
- 浅析 Linux 初始化 init 系统,第 3 部分: Systemd#日志服务
- Log and Service Status
- Using the Journal
- journald.conf — Journal service configuration file
- Writing syslog Daemons Which Cooperate Nicely With systemd
- systemd Journal译文
Journal与Rsyslog(syslog)
systemd 提供了 socket /run/systemd/journal/syslog,以兼容传统日志服务。所有系统信息都会被传入。要使传统日志服务工作,需要让syslog daemon绑定该 socket, 而非 /dev/log,见systemd v38 released。
debian testing下默认安装rsyslog用于代替syslog,
/etc/systemd/system/syslog.service
:注意ExecStart 选项[Unit]
Description=System Logging Service
Requires=syslog.socket
[Service]
Type=notify
ExecStart=/usr/sbin/rsyslogd -n
StandardOutput=null
[Install]
WantedBy=multi-user.target
Alias=syslog.service
/lib/systemd/system/rsyslog.service
:注意Alias选项[Unit]
Description=System Logging Service
Requires=syslog.socket
[Service]
Type=notify
ExecStart=/usr/sbin/rsyslogd -n
StandardOutput=null
[Install]
WantedBy=multi-user.target
Alias=syslog.service
而默认情况下,journald.conf中ForwardToSyslog=默认开启,journal的日志会转发给syslog daemon,通过套接字(/run/systemd/journal/syslog)。
/lib/systemd/system/syslog.socket
[Unit]
Description=Syslog Socket
Documentation=man:systemd.special(7)
Documentation=http://www.freedesktop.org/wiki/Software/systemd/syslog
DefaultDependencies=no
Before=sockets.target syslog.target shutdown.target
# Don't allow logging until the very end
Conflicts=shutdown.target
# Pull in syslog.target to tell people that /dev/log is now accessible
Wants=syslog.target
[Socket]
ListenDatagram=/run/systemd/journal/syslog
SocketMode=0666
PassCredentials=yes
PassSecurity=yes
ReceiveBuffer=8M
注:关于进程向journal提交日志的接口请参考 详细介绍--日志管理--日志的记录..一节,另外可关注服务单元的标准输出StandardOutput=,可选择将 进程标准输出连接到inherit, null, tty, syslog, kmsg, journal, syslog+console, kmsg+console, journal+console 还是 socket,默认为journal,即systemd的日志系统。
Messages coming in via /dev/log, via the native protocol, via STDOUT/STDERR of all services and via the kernel are received in the journal daemon.
Audit record generation for started services
介绍
We hooked systemd up to the Linux auditing subsystem: as first init system at all systemd now generates auditing records for all services it starts/stops, including their failure status.
systemd下服务单元的启动、停止以及进入失败状态都会生成Audit记录,日志记录在
/var/log/audit/audit.log
文件中。实例
安装auditd:
# aptitude install -y auditd
默认的auditd.conf与auditd.rulues下(实验环境debian stable:sysv,debian testing:systemd,两者默认auditd.conf差别只是num_logs项,不影响;两者默认auditd.rulues相同),设置auditd开启自动启动,我们看看开启自动启动的那些服务信息是否会被记录到audit.log中。
(sysv与systemd下的系统中,都安装了nginx服务,并随机启动)
可发现systemd下的auditd.log中记录了systemd下service单元启动的信息,sysv下见不到sysv管理的服务的启动信息。
我们手动restart或停止systemd下的nginx.service,见图 systemd-auditd-nginx-log,同样发现有相关信息,从左侧的Type,可区分哪些记录是启动,哪些记录是停止。
本节参考链接
Systemd-analyze
systemd-analyze 是一个内置的启动性能分析工具,它除了可以分析和直观的展现系统启动时候每项服务的耗时,也可以图表的方式直观得绘出启动阶段各服务的依赖关系,方便系统管理员优化系统启动,理解系统服务依赖关系等,具体用法请参考用户手册,非常简单。
注:systemd-209,systemd-analyze增加远程控制功能(over SSH)。
本节参考链接
-----------------------------
systemd实战
systemctl对服务的操作
设置开机启动
对于那些支持Systemd的软件,安装的时候,会自动在
/usr/lib/systemd/system
目录添加一个配置文件(一般为.service
后缀)。
配置文件的后缀名,就是该Unit的种类,比如
sshd.socket
。如果省略,Systemd默认后缀名为.service
,所以nginx
会被理解成nginx.service
。
如果你想让该软件开机启动,就执行下面的命令(以nginx.service为例):
上面的命令相当于在
/etc/systemd/system/
目录添加一个符号链接nginx.service
,指向/usr/lib/systemd/system/nginx.service
。
这是因为开机时,Systemd只执行
/etc/systemd/system/
目录里面的配置文件。这也意味着,如果把修改后的配置文件放在该目录,就可以达到覆盖原始配置的效果。
但要注意,符号链接可能不是直接在
/etc/systemd/system/
目录下,而是在该目录下的multi-user.target.wants/
目录中。启动服务
设置开机启动以后,软件并不会立即启动,必须等到下一次开机。如果想现在就运行该软件,那么要执行以下命令:
为了查看nginx服务是否真的启动了,可以查看一下它的状态:
输出结果:
● nginx.service - nginx - high performance web server
Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; vendor preset: disabled)
Active: active (running) since 二 2019-03-26 03:06:39 CST; 1 weeks 1 days ago
Docs: http://nginx.org/en/docs/
Main PID: 4084 (nginx)
Tasks: 3
Memory: 34.0M
CGroup: /system.slice/nginx.service
├─ 4084 nginx: master process /usr/local/openresty/nginx/sbin/nginx -c /usr/lo...
├─25383 nginx: worker process
└─25384 nginx: cache manager process
Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
- Loaded行:配置文件的位置,表示是否设为开机启动,enabled表示已经设置为开机自启动。
- Active行:表示是否处于激活状态(即是否正在运行)
- Docs行:该软件的文档,有可能是一个网址,有可能是man(意思是让你用man命令查看)
- Main PID行:主进程PID
- Tasks行:表示一共有几个子进程
- Memory行:表示该服务占用的内存大小
- CGroup块:应用的所有子进程
- 日志块:应用的日志
停止服务
终止正在运行的服务,需要执行systemctl stop命令:
有时候,该命令可能没有响应,服务停不下来。这时候就不得不”杀进程”了,向正在运行的进程发出kill信号:
当然,我们自己用
ps -ef | grep nginx
找到pid,然后自己用kill -9 pid
也是可以的重启服务
读懂配置文件
一个服务怎么启动,完全由它的配置文件决定。下面就来看,配置文件有些什么内容。
前面说过,配置文件主要放在
/usr/lib/systemd/system
目录,也可能在/etc/systemd/system
目录。找到配置文件以后,使用文本编辑器打开即可。systemctl cat
命令可以用来查看配置文件,下面以sshd.service
文件为例,它的作用是启动一个SSH服务器,供其他用户以SSH方式登录。
可以看到,配置文件分成几个区块,每个区块包含若干条键值对。下面依次解释每个区块的内容。
[Unit]区块:启动顺序与依赖关系
- Description:当前服务的简单描述
- Documentation:文档位置,有可能是一个网址,有可能是
man
,意思是让你用man命令去查。 - After:表示如果network.target或sshd-keygen.service需要启动,那么sshd.service应该在它们之后启动。
相应地,还有一个Before字段,定义sshd.service应该在哪些服务之前启动。
注意:After和Before字段只涉及启动顺序,不涉及依赖关系。
举例来说,某Web应用需要mysql数据库储存数据。在配置文件中,它只定义要在 mysql之后启动,而没有定义依赖mysql。上线后,由于某种原因,mysql需要重新启动,在停止服务期间,该Web应用就会无法建立数据库连接。
设置依赖关系,需要使用Wants字段和Requires字段。
– Wants:表示sshd.service与sshd-keygen.service之间存在”弱依赖”关系,即如果”sshd-keygen.service”启动失败或停止运行,不影响sshd.service继续执行。
– Wants:表示sshd.service与sshd-keygen.service之间存在”弱依赖”关系,即如果”sshd-keygen.service”启动失败或停止运行,不影响sshd.service继续执行。
Requires字段则表示”强依赖”关系(由于sshd没有强依赖,所以在这里并没有写Requies字段),即如果该服务启动失败或异常退出,那么sshd.service也必须退出。
注意,Wants字段与Requires字段只涉及依赖关系,与启动顺序无关,默认情况下是同时启动的。
[Service] 区块:启动行为
Service区块定义如何启动当前服务。
启动命令
许多软件都有自己的环境参数文件,该文件可以用
EnvironmentFile
字段读取。
EnvironmentFile字段:指定当前服务的环境参数文件。该文件内部的key=value键值对,可以用
$key
的形式,在当前配置文件中获取。
上面的例子中,sshd的环境参数文件是
/etc/sysconfig/sshd
。ExecStart
:定义启动进程时执行的命令,配置文件里面最重要的字段是ExecStart。
上面的例子中,启动sshd,执行的命令是
/usr/sbin/sshd -D $OPTIONS
,其中的变量$OPTIONS
就来自EnvironmentFile
字段指定的环境参数文件。
与之作用相似的,还有如下这些字段。
- ExecReload字段:重启服务时执行的命令
- ExecStop字段:停止服务时执行的命令
- ExecStartPre字段:启动服务之前执行的命令
- ExecStartPost字段:启动服务之后执行的命令
- ExecStopPost字段:停止服务之后执行的命令
请看下面的例子。
上面这个配置文件,第二行ExecStart设为空值,等于取消了第一行的设置,运行结果如下。
execstart2
post1
post2
所有的启动设置之前,都可以加上一个连词号(-),表示”抑制错误”,即发生错误的时候,不影响其他命令的执行。比如,
EnvironmentFile=-/etc/sysconfig/sshd
(注意等号后面的那个连词号),就表示即使/etc/sysconfig/sshd
文件不存在,也不会抛出错误。启动类型
Type字段定义启动类型。它可以设置的值如下:
- simple(默认值):ExecStart字段启动的进程为主进程
- forking:ExecStart字段将以
fork()
方式启动,此时父进程将会退出,子进程将成为主进程 - oneshot:类似于simple,但只执行一次,Systemd会等它执行完,才启动其他服务
- dbus:类似于simple,但会等待D-Bus信号后启动
- notify:类似于simple,启动结束后会发出通知信号,然后Systemd再启动其他服务
- idle:类似于simple,但是要等到其他任务都执行完,才会启动该服务。一种使用场合是为让该服务的输出,不与其他服务的输出相混合
下面是一个oneshot的例子,笔记本电脑启动时,要把触摸板关掉,配置文件可以这样写。
上面的配置文件,启动类型设为oneshot,就表明这个服务只要运行一次就够了,不需要长期运行,但是你有没有发现,停止了之后,无法用systemctl开启呀,所以我们可以再改成以下这样:
可以看到,上面配置文件中添加了ExecStop和RemainAfterExit。
当执行start后,就关闭了触控板(有人可能会觉得奇怪,start不是开启触摸板么?怎么会关闭呢?但你要看清楚,被执行的命令是
当执行start后,就关闭了触控板(有人可能会觉得奇怪,start不是开启触摸板么?怎么会关闭呢?但你要看清楚,被执行的命令是
touchpad-off
,start表示执行touchpad-off
这个命令,当然就是关闭触控板)RemainAfterExit
字段的值可以为true或false,也可以用yes和no。
这个字段可能比较多人不懂,它设为yes的意思是“程序虽然退出了,但仍然让
systemctl status
命令查询到的状态为active
”,为什么要这样呢?因为只有这样才可以执行stop操作,假如你本身就是stop状态,你是没法执行systemctl stop
操作的(实际上你去执行它是不会报错的,但按原则来说,只有状态为active的服务才能stop)。
有人会觉得,既然执行之后就自己退出了,对程序来说实际上已经
RemainAfterExit这个配置主要是提供给一些并非常驻内存的程序使用。
stop
了,为什么还要stop呢?很明显,本例的stop并不是指“/usr/bin/touchpad-off”这个服务的stop,而是指“/usr/bin/touchpad-off start”的“反操作”而已。RemainAfterExit这个配置主要是提供给一些并非常驻内存的程序使用。
重启行为
Service区块有一些字段,定义了重启行为。
KillMode字段:定义Systemd如何停止sshd服务。
上面这个例子中,将KillMode设为process,表示只停止主进程,不停止任何sshd 子进程,即子进程打开的 SSH session 仍然保持连接。这个设置不太常见,但对sshd很重要,否则你停止服务的时候,会连自己打开的SSH session一起杀掉(这样你就再也无法远程连接去启动它了,所以不能这么做,sshd这点比较特殊)。
KillMode字段可以设置的值如下:
- control-group(默认值):当前控制组里面的所有子进程,都会被杀掉
- process:只杀主进程
- mixed:主进程将收到SIGTERM信号,子进程收到SIGKILL信号
- none:没有进程会被杀掉,只是执行服务的stop命令。
接下来是Restart字段。
Restart字段:定义了sshd退出后,Systemd的重启方式。
Restart字段:定义了sshd退出后,Systemd的重启方式。
上面的例子中,Restart设为on-failure,表示任何意外的失败,就将重启sshd。如果sshd正常停止(比如执行systemctl stop命令),它就不会重启。
Restart字段可以设置的值如下。
- no(默认值):退出后不会重启
- on-success:只有正常退出时(退出状态码为0),才会重启
- on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启
- on-abnormal:只有被信号终止和超时,才会重启
- on-abort:只有在收到没有捕捉到的信号终止时,才会重启
- on-watchdog:超时退出,才会重启
- always:不管是什么退出原因,总是重启
对于守护进程,推荐设为
on-failure
。对于那些允许发生错误退出的服务,可以设为on-abnormal
。
RestartSec字段:表示Systemd重启服务之前,需要等待的秒数。上面的例子设为等待42秒。
[Install]区块
Install区块,定义如何安装这个配置文件,即怎样做到开机启动。
WantedBy字段:表示该服务所在的Target。
Target的含义是服务组,表示一组服务。WantedBy=multi-user.target指的是,sshd所在的Target是multi-user.target。
这个设置非常重要,因为执行
systemctl enable sshd.service
命令时,sshd.service的一个符号链接,就会放在/etc/systemd/system目录下面的multi-user.target.wants子目录之中。
Systemd有默认的启动Target,使用以下命令查看:
一般来说,常用的Target有两个:一个是multi-user.target,表示多用户命令行状态;另一个是graphical.target,表示图形用户状态,它依赖于multi-user.target。官方文档有一张非常清晰的Target依赖关系图。
Target的配置文件
注意,Target 配置文件里面没有启动命令。
上面输出结果中,主要字段含义如下。
- Requires字段:要求basic.target一起运行。
- Conflicts字段:冲突字段。如果rescue.service或rescue.target正在运行,multi-user.target就不能运行,反之亦然。
- After:表示multi-user.target在basic.target 、 rescue.service、 rescue.target之后启动,如果它们有启动的话。
- AllowIsolate:允许使用systemctl isolate命令切换到multi-user.target。
修改配置文件后重启
修改配置文件以后,需要重新加载配置文件,然后重新启动相关服务。