Systemd 是 Linux 的系统和服务的管理器,兼容 SysV 和 LSB初始化脚本,Systemd有以下特性:
systemctl 命令是管理 systemd 的主要工具,它将 SysVinit service 和 chkconfig 命令的功能结合到一个工具中,您可以使用它来永久启用和禁用服务或仅针对当前会话启用和禁用服务
Systemd 管理 unit,它们是系统资源和服务的表示,以下列表显示了 systemd 可以管理的 unit 类型:
systemctl start chronyd #启动
systemctl stop chronyd #停止
systemctl restart chronyd #重启
systemctl status chronyd #查看 unit 状态systemctl enable chronyd #设置 unit 开启启动
systemctl disable chronyd #取消 unit 开机启动
systemctl is-enabled chronyd #查看 unit 是否开机启动# 重新加载 unit 的配置文件,每次修改了 unit 的配置文件后,需要执行以下命令重新加载 unit 的配置文件
systemctl daemon-reloadsystemctl mask chronyd #屏蔽 unit,屏蔽后 unit 无法启动
systemctl unmask chronyd #取消屏蔽# 更多命令可通过 systemctl --help 或 man systemctl 来查看
sshd 服务的 unit 配置文件如下所示,主要分为三部分:[Unit]、[Service] 和 [Install]
[root@vm03 ~]# cat /usr/lib/systemd/system/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
此部分中使用的参数不仅限于 service 类型的 unit,对其它类型 unit 也是通用的,有关这些参数及其说明的完整列表,可运行命令 man systemd.unit 或访问 systemd.unit 中文手册
注意:在 [unit] 块中的每个参数后都可以指定一个以空格分隔的列表
只有 service 类型的 unit 才有这些参数,参数完整列表请访问 systemd.service 中文手册 或 systemd.service
RemainAfterExit:一个布尔值,它指定即使服务的所有进程都已退出,也应将服务视为活动的,默认为 no
GuessMainPID:一个布尔值,指定systemd在无法可靠确定服务的主 PID 时是否应该猜测它。除非设置了 Type=forking 并且未设置 PIDFile,否则此选项将被忽略,默认为 yes
PIDFile:指向此守护进程的 PID 文件的绝对文件名。对于 Type=forking 的服务,建议使用此选项。Systemd 在服务启动后读取守护进程的主进程的 PID。Systemd 不会写入此处配置的文件,但它会在服务关闭后删除该文件
BusName:到达此服务的 D-Bus 总线名称。对于 Type=dbus 的服务,此选项是必需的
ExecStart:服务启动时执行的命令和参数
ExecStartPre: 服务启动之前执行的命令
ExecStartPost: 服务启动之后执行的命令
ExecReload:重启服务时执行的命令
ExecStop:服务停止时执行的命令和参数
ExecStopPost:服务停止之后执行的命令
RestartSec:重新启动服务前的睡眠时间(以秒为单位)
TimeoutStartSec:等待服务启动的时间(以秒为单位)
TimeoutStopSec:等待服务停止的时间(以秒为单位)
TimeoutSec:同时配置TimeoutStartSec和TimeOutshopSec的缩写
Restart:配置当服务的进程退出、被杀死或达到超时时是否重新启动服务,可以设置的值如下:
Environment:指定环境变量
KillMode:定义systemd如何停止服务,可以设置的值如下:
下面列出了 service, socket, mount, swap 单元所共有的、 用于定义进程执行环境的配置选项,完整参数说明可运行命令 man systemd.exec 或访问 systemd.exec 中文手册
WorkingDirectory:设置进程的工作目录
User=, Group:设置进程在执行时使用的用户与组,既可以设为一个数字形式的 UID/GID 也可以设为一个字符串形式的名称
NoNewPrivileges:接收一个布尔值。设为 yes 表示该服务的所有进程与子进程都不能通过 execve() 调用获得任何新权限。该选项是最简单也是最有效的防止进程提升权限的方法
SELinuxContext:设置进程的 SELinux 安全上下文
设置进程的各种软/硬资源限制:LimitCPU=, LimitFSIZE=, LimitDATA=, LimitSTACK=, LimitCORE=, LimitRSS=, LimitNOFILE=, LimitAS=, LimitNPROC=, LimitMEMLOCK=, LimitLOCKS=, LimitSIGPENDING=, LimitMSGQUEUE=, LimitNICE=, LimitRTPRIO=, LimitRTTIME= 这些指令的值有两种表示法,一个单独的 value 值表示将软硬两种限制设为同一个值。 而冒号分隔的 soft:hard 值表示分别设置软限制与硬限制 (例如 LimitAS=4G:16G),特殊值 infinity 表示没有限制。对于以字节为单位的选项,可以使用以1024为基数的 K, M, G, T, P, E 后缀(例如 LimitAS=16G)。对于时间限制,可以加上 "ms"(毫秒), "s"(秒), "min"(分钟), "h"(小时), "d"(天), "w"(周) 等明确的时间单位后缀
UMask:设置文件创建掩码,默认值为 0022
OOMScoreAdjust:设置进程因内存不足而被杀死的优先级。可设为 -1000(禁止被杀死) 到 1000(最先被杀死)之间的整数值
Environment:设置进程的环境变量, 接受一个空格分隔的 VAR=VALUE 列表。 可以多次使用此选项以增加新的变量或者修改已有的变量(同一个变量以最后一次设置为准)。设为空表示清空先前所有已设置的变量。 注意:(1)不会在字符串内部进行变量展开(也就是"$"没有特殊含义);(2)如果值中包含空格或者等号,那么必须在字符串两边使用双引号(")界定,例如:Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" 表示设置了 "VAR1", "VAR2", "VAR3" 三个变量,其值分别为 "word1 word2", "word3", "$word 5 6"
EnvironmentFile:与 Environment= 类似,不同之处在于此选项是从文本文件中读取环境变量的设置。文件中的空行以及以分号(;)或井号(#)开头的行会被忽略, 其他行的格式必须符合 VAR=VALUE 的shell变量赋值语法。 行尾的反斜杠(\)将被视为续行符,这与shell语法类似。若想在变量值中包含空格, 则必须在值的两端加上双引号(")界定。文件必须用绝对路径表示(可以包含通配符)。但可在路径前加上 "-" 前缀表示忽略不存在的文件。可以多次使用此选项,以从多个不同的文件中读取设置。若设为空,则表示清空所有先前已经从文件中读取的环境变量。这里列出的文件将在进程启动前的瞬间被读取,因此可以由前一个单元生成配置文件, 再由后一个单元去读取它。从文件中读取的环境变量会覆盖 Environment= 中设置的同名变量。文件的读取顺序就是它们出现在单元文件中的顺序,并且对于同一个变量,以最后读取的文件中的设置为准
UnsetEnvironment:明确撤销该单元的特定环境变量
StandardInput:设置进程的标准输入(STDIN),可设为 null, tty, tty-force, tty-fail, data, file:path, socket, fd:name 之一,此选项的默认值是 null
StandardOutput:设置进程的标准输出(STDOUT),可设为 inherit, null, tty, journal, syslog, kmsg, journal+console, syslog+console, kmsg+console, file:path, append:path, socket, fd:name 之一
StandardError:设置进程的标准错误(STDERR),取值范围及含义与 StandardOutput= 相同
StandardInputText, StandardInputData:设置通过标准输入(STDIN)传递给进程的任意文本或二进制数据,这些选项仅在 StandardInput=data 时有意义
LogLevelMax:按此日志级别过滤该单元生成的日志消息,可设为一个 syslog 日志级别,也就是 emerg(最低日志级别,仅显示最致命的消息), alert, crit, err, warning, notice, info, debug(最高日志级别,显示最细致的调试消息) 之一
详细说明访问 systemd.exec 中文手册
$PATH:可执行文件的目录列表(冒号分隔的绝对路径), 此值固定为 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$LANG:本地化设置。可以通过 locale.conf(5) 文件设置
$USER, $LOGNAME, $HOME, $SHELL:用户名, 用户名, 家目录, 登录shell
$MAINPID:单元主进程的PID (如果能确定的话)
service, socket, mount, swap, scope 单元都拥有一组如何杀死进程的配置选项,完整参数说明可运行命令 man systemd.kill 或访问 systemd.kill 中文手册
KillMode:设置在单元停止时,杀死进程的方法。取值范围如:control-group, process, mixed, none 默认值是 control-group 表示杀死该单元的 cgroup 内的所有进程(对于 service 单元,还要先执行 ExecStop= 动作)
KillSignal:设置杀死进程的第一步使用什么信号,所有可用的信号详见 signal(7) 手册。 默认值为 SIGTERM 信号。注意, systemd 会无条件的紧跟此信号之后再发送一个 SIGCONT 信号, 以确保干净的杀死已挂起(suspended)的进程
SendSIGHUP:是否在第一步发送 KillSignal= 信号后,立即紧跟着向该单元的所有进程再发送一个 SIGHUP 信号。这主要用于通知 shell 之类的进程,它们的连接已中断。默认为"no"
SendSIGKILL:是否在超过 TimeoutStopSec= 时间后,使用 SIGKILL 或 FinalKillSignal= 信号杀死依然残存的进程。默认值为"yes"
FinalKillSignal:当发生了超时并且已开启 SendSIGKILL= 时, 发送哪个信号给剩余的进程。应当设置为不能被服务捕获和处理的信号(SIGTERM 就不合适)。对于开发人员来说,可以使用它来生成 coredump 以了解为什么服务在接收到最初的 SIGTERM 信号时没有正确终止。具体做法是设置 LimitCORE= 并且将 FinalKillSignal= 设为 SIGQUIT 或 SIGABRT 之一。此选项的默认值为 SIGKILL
WatchdogSignal:在看门狗(WatchdogSec=)发生超时的情况下,使用哪个信号终止服务。此选项的默认值为 SIGABRT
slice, scope, service, socket, mount, swap 单元共享一组用于限制进程资源占用的配置选项,本质上,这些选项依赖于Linux内核的 cgroups 功能,将一组进程组织成树形层次结构,并对其允许占用的各种资源进行限制,有关这些参数及其说明的完整列表,可运行命令 man systemd.resource-control 或访问 systemd.resource-control 中文手册
[install] 定义了 unit 的安装信息,此部分配置仅在 systemctl enable 或 systemctl disable 时使用,在 unit 运行时不解释此部分,相当于是配置如何开机启动
此部分中使用的参数不仅限于service类型的unit,对其它类型的 unit也是通用的,有关这些参数及其说明的完整列表,可运行命令 man systemd.unit 或访问 systemd.unit 中文手册
Target的含义是服务组,表示一组服务 WantedBy=multi-user.target 指的是,unit 所在的 Target 是multi-user.target(多用户模式)
这个设置非常重要,因为执行systemctl enable 是会将 unit 链接到 /etc/systemd/system/multi-user.target.wants目录之中,实现开机启动的功能
# nginx的unit 配置文件
cat /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target[Service]
Type=forking
PIDFile=/usr/local/nginx/run/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP $(/bin/cat /usr/local/nginx/run/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM $(/bin/cat /usr/local/nginx/run/nginx.pid)"[Install]
WantedBy=multi-user.target# redis的unit 配置文件
[Unit]
Description=Redis data structure server
Documentation=https://redis.io/documentation
Wants=network-online.target
After=network-online.target[Service]
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf
LimitNOFILE=10032
NoNewPrivileges=yes
OOMScoreAdjust=-900
Type=notify
User=redis
Group=redis[Install]
WantedBy=multi-user.target# mysql的unit 配置文件
[Unit]
Description=mysql server
Documentation=https://dev.mysql.com/doc/refman/5.7/en/using-systemd.html
After=network.target
After=syslog.target[Service]
User=mysql
Group=mysql
Type=forking
PIDFile=/usr/local/mysql/mysqld.pid
ExecStart=/usr/local/mysql/bin/mysqld --daemonize --pid-file=/usr/local/mysql/mysqld.pid $MYSQLD_OPTS
LimitNOFILE=5000
Restart=on-failure[Install]
WantedBy=multi-user.target# prometheus的unit 配置文件
[Unit]
Description=prometheus service
Documentation=https://prometheus.io/docs/prometheus/latest/management_api
After=network.target[Service]
Type=simple
ExecStart=/usr/local/prometheus/prometheus \--config.file=/usr/local/prometheus/prometheus.yml \--storage.tsdb.retention.time=92d \--storage.tsdb.path=/usr/local/prometheus/data \--web.listen-address=0.0.0.0:9090 \--web.console.templates=/usr/local/prometheus/consoles \--web.console.libraries=/usr/local/prometheus/console_libraries
#如果想要输出日志重定向到文件,可以按如下方式,注意此时就不能使用续行符了
#ExecStart=/bin/bash -ce "/usr/local/prometheus/prometheus --config.file=/usr/local/prometheus/prometheus.yml >> /var/log/prometheus.log 2>&1"
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-failure[Install]
WantedBy=multi-user.target# alertmanager的unit 配置文件
[Unit]
Description=alertmanager service
Documentation=https://prometheus.io/docs/alerting/latest/management_api
After=network.target[Service]
Type=simple
ExecStart=/usr/local/alertmanager/alertmanager \--config.file=/usr/local/alertmanager/alertmanager.yml \--storage.path=/usr/local/alertmanager/data \--data.retention=120h \--web.listen-address=0.0.0.0:9093
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-failure[Install]
WantedBy=multi-user.target# node_exporter的unit配置文件
[Unit]
Description=node_exporter
Documentation=https://github.com/prometheus/node_exporter
After=network.target[Service]
Type=simple
ExecStart=/usr/local/prometheus_exporter/node_exporter-1.1.2.linux-amd64/node_exporter \--web.listen-address=0.0.0.0:9100 \--web.telemetry-path=/metrics
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-failure[Install]
WantedBy=multi-user.target# redis_exporter的unit配置文件
[Unit]
Description=redis_exporter
Documentation=https://github.com/oliver006/redis_exporter
After=network.target[Service]
Type=simple
ExecStart=/usr/local/prometheus_exporter/redis_exporter-v1.25.0.linux-amd64/redis_exporter \-redis.addr=localhost:6379 \-redis.password=123456 \-web.listen-address=:9121 \-web.telemetry-path=/metrics
Restart=on-failure[Install]
WantedBy=multi-user.target# blackbox_exporter的unit配置文件
[Unit]
Description=blackbox_exporter
Documentation=https://github.com/prometheus/blackbox_exporter
After=network.target[Service]
Type=simple
ExecStart=/usr/local/prometheus_exporter/blackbox_exporter-0.19.0.linux-amd64/blackbox_exporter \--web.listen-address=0.0.0.0:9115 \--config.file=/usr/local/prometheus_exporter/blackbox_exporter-0.19.0.linux-amd64/blackbox.yml
ExecStop=/bin/kill -s TERM $MAINPID
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure[Install]
WantedBy=multi-user.target# mysqld_exporter的unit配置文件
[Unit]
Description=mysql_exporter
Documentation=https://github.com/prometheus/mysqld_exporter
After=network.target[Service]
Type=simple
ExecStart=/usr/local/prometheus_exporter/mysqld_exporter-0.13.0.linux-amd64/mysqld_exporter \--config.my-cnf=/usr/local/prometheus_exporter/mysqld_exporter-0.13.0.linux-amd64/.my.cnf \--web.listen-address=:9104 \--web.telemetry-path=/metrics
Restart=on-failure[Install]
WantedBy=multi-user.target# systemd管理java进程
[Unit]
Description=question_api
Documentation=https://docs.oracle.com/javase/tutorial/deployment/jar/basicsindex.html
After=network.target[Service]
Type=forking
SuccessExitStatus=143
ExecStart=/bin/sh -c "/usr/local/java/jdk1.8.0_201/bin/java -Xms2048m -Xmx2048m -jar /app/question_api/question_api_beta.jar --server.port=8080 >> /var/log/app/question_api.log 2>&1 &"
ExecStop=/bin/kill -s TERM $MAINPIDRestart=on-failure[Install]
WantedBy=multi-user.target# 配置项 SuccessExitStatus=143 是为了抑制stop时报错 Main process exited, code=exited, status=143/n/a
# 这是因为 java 程序在响应 SIGTERM 时不会并不会发回预期的退出状态
# 所以需要将退出代码 SuccessExitStatus=143 添加到 systemd 服务文件作为成功退出状态来抑制这种报错