Linux之(17)系统服务
Author:onceday Date:2022年12月24日
漫漫长路,有多少人对你笑过…
参考文档:
- Systemd 入门教程:命令篇 - 阮一峰的网络日志 (ruanyifeng.com)
- 可能是史上最全面易懂的 Systemd 服务管理教程!( 强烈建议收藏 ) - 腾讯云开发者社区-腾讯云 (tencent.com)
文章目录
- Linux之(17)系统服务
- 1.引言
- 2. systemctl管理服务
- 2.1 mask强制注销服务
- 2.2 查看系统上所有服务
- 2.3 target操作命令
- 2.4 分析服务之间依赖性
- 2.5 网络服务和端口的对应关系
- 3. systemctl配置文件
- 3.1 service配置文件
- 3.2 Unit部分参数
- 3.3 Install部分参数
- 3.4 Service部分参数
- 3.5 模板unit文件
1.引言
Unix-like系统,很多功能都是以服务的方式来运行,系统为了某些功能必须要提供一些服务。提供对应service的程序就被称为daemon。
下面是经典的systemd架构图:
运行服务的进程通常在运行之后,会在在进程名字后面加上一个d
(daemon)。例如:
at
和cron
,其后面daemon名字会取为atd
和crond
。
目前广泛使用的服务管理机制是systemd,有以下特点:
- 并行处理所有服务,加速开机流程。让所有的服务可以同时启动。
- 一经要求就响应的on-demand启动方式。
systemd
常驻内存,能及时响应启动需求。 - 服务依赖性的自我检查。会自动启动的当前服务所需的其他服务。
- 依daemon功能分类。依daemon功能分类。
- 将多个daemons集合成为一个群组。
- 向下兼容旧有的init服务脚本。
需要注意以下限制:
- 如果某个服务启动时管理员自己手动启动,而不是使用systemctl去启动,那么systemd将无法检测到该服务,而无法进一步管理。
- systemd启动过程中,无法与管理员通过标准输入传入信息,因此,自行编写systemd的启动设置时,务必要取消交互机制。
systemd将每一个daemon执行脚本都称为一个服务单位(unit),而每种服务单位根据功能来区分,就可以分类为不同的类型(type)。
基本的类型有如下几种:
- 系统服务。
- 数据监听与交换的socket文件服务。
- 存储系统状态的快照类型。
- 不同运行级别分类的操作环境。
基本的配置文件放在下面几个目录中:
/usr/lib/systemd/system/
,每个服务最主要的启动脚本设置,有点类似以前的/etc/init.d
下面的文件。/run/systemd/system/
,系统执行过程中所产生的服务脚本,这些脚本的优先级要比/usr/lib/systemd/system/
高。/etc/systemd/system/
,管理员根据主机系统的需求所建立的执行脚本。
/etc/systemd/system/
中是操作系统最关注的启动配置,其实际决定那些service启动。
具体的执行脚本内容放在usr/lib/systemd/system/
中,通过链接来生效。
root@ubuntu:~# ll /usr/lib/systemd/system
total 1364
drwxr-xr-x 25 root root 36864 Nov 12 21:07 ./
drwxr-xr-x 16 root root 12288 Feb 22 2022 ../
-rw-r--r-- 1 root root 741 Nov 9 2021 accounts-daemon.service
-rw-r--r-- 1 root root 115 Nov 28 2019 acpid.path
-rw-r--r-- 1 root root 261 Nov 28 2019 acpid.service
-rw-r--r-- 1 root root 115 Nov 28 2019 acpid.socket
-rw-r--r-- 1 root root 1162 Apr 11 2020 apparmor.service
-rw-r--r-- 1 root root 212 Dec 5 2019 apport-autoreport.path
-rw-r--r-- 1 root root 242 Dec 5 2019 apport-autoreport.service
......
systemd的unit分类实现很简单,按照上面所示,是通过文件后缀名来分类。
扩展名 | 主要服务功能 |
---|---|
.service | 一般服务类型(service unit): 主要是系统服务类型,包括服务器本身所需要的本地服务以及网络服务等,最常见服务类型。 |
.socket | 内部程序数据交换的socket服务(socket unit):主要是IPC(Inter-process communication)的传输信息socket文件(socket file)功能。 |
.target | 执行环境类型(target unit):其实是一群unit的集合,例如上面表格中谈到的multi-user.target,其本质是一堆服务的集合。 |
.mount/.automount | 文件系统挂载相关的服务(automount unit/mount unit):例如来自网络的自动挂载、NFS文件系统挂载等与文件系统相关性较高的进程管理。 |
.path | 检测特定文件或目录类型(path unit): 某些服务需要检测某些特定的目录来提供队列服务,例如打印服务,通过检测打印队列目录来启动打印功能。 |
.timer | 循环执行的服务(timer unit):这个服务有类似anacrontab,由systemd主动提供。 |
.swap | 用于封装一个交换分区或者交换文件,它与mount单元非常类似。 |
.slice | 用于控制特定CGroup内(例如一组service与scope单元)所有进程的总体资源。 |
.scope | 与service单元类似,但是由systemd根据D-bus接口接收到的消息自动的创建。可管理外部创建的进程。 |
.snapshot | 用于表示一个由systemctl snapshot命令创建的systemd units运行状态快照。 |
.device | 对于/dev目录下的设备,主要用于定义设备之间的依赖关系。 |
2. systemctl管理服务
systemctl
的参数是非常多的,输入systemctl --help
即可查看。
下面是一些常用的命令systemctl [command] [unit]
:
参数 | 描述 |
---|---|
start | 立刻启动后面接的unit |
stop | 立刻关闭后面接的unit |
restart | 立刻重新启动后面接的unit |
reload | 不关闭后面接的unit的情况下,重新加载配置文件,让设置生效 |
enable | 设置下次开机时,后面接的unit会被启动 |
disable | 设置下次开机时,后面接的unit不会被启动 |
status | 目的后面接的这个unit的状态。 |
is-active | 目前有没有正在运行中。 |
is-enable | 开机时有没有默认要启用这个unit |
可以如下查看某个unit工作的状态:
root@ubuntu:~# systemctl status atd
● atd.service - Deferred execution scheduler
Loaded: loaded (/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2022-12-05 23:10:34 CST; 2 weeks 4 days ago
Docs: man:atd(8)
Main PID: 687869 (atd)
Tasks: 1 (limit: 2269)
Memory: 792.0K
CGroup: /system.slice/atd.service
└─687869 /usr/sbin/atd -f
......
第三行的状态有以下的可能性:
active(dead)
,当前是关闭的。active(running)
,正有一个或多个进程在系统中运行。active(exited)
,仅执行一次就正常结束的服务,目前并没有任何进程在系统汇总执行。active(waiting)
,正在运行当中,不过还需等待其他的事件发生才能继续运行。inactive
这个服务目前没有运行。
daemon
默认状态有如下几种:
enabled
:这个daemon将在开机时被运行。disabled
:这个daemon在开机时不会被运行。static
:这个daemon不可以自己启动,不过可能会被其他的enabled的服务来唤醒(依赖属性的服务)。mask
:这个daemon无论如何都无法被启动,因为已经被强制注销。可通过systemctl unmask方式改回默认状态。
下面是一个实际操作的例子:
root@ubuntu:~# systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2022-10-17 09:25:54 CST; 2 months 7 days ago
......
root@ubuntu:~# systemctl stop nginx.service
root@ubuntu:~# systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Sat 2022-12-24 22:05:26 CST; 2s ago
......
root@ubuntu:~# systemctl disable nginx.service
Synchronizing state of nginx.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable nginx
Removed /etc/systemd/system/multi-user.target.wants/nginx.service.
可以看到,禁止开机启动,就是从/etc/systemd/system
从移除相应的链接文件。
2.1 mask强制注销服务
可以通过systemctl mask xxx.service
强制注销服务。
root@ubuntu:~# systemctl mask nginx.service
Created symlink /etc/systemd/system/nginx.service → /dev/null.
原理就是直接将文件链接到空文件上。
取消注销,使用unmask
命令即可:
root@ubuntu:~# systemctl unmask nginx.service
Removed /etc/systemd/system/nginx.service.
root@ubuntu:~# systemctl status nginx.service
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: inactive (dead)
Docs: man:nginx(8)
可以看到/etc/systemd/system/
路径的优先级比/lib/systemd/system/
中要更高。
2.2 查看系统上所有服务
直接使用systemctl
就会列出当前系统上的全部unit。常见命令如下:
systemctl list-units
,显示当前启动的unit,若加上--all
会列未启动的unit。systemctl list-unit-files
,依据usr/lib/systemd/system
内的文件,将所有文件列表说明。--type=TYPE
,按unit类型输出,如service/target/socket
。
示例如下:
列出所有的service:
root@ubuntu:~# systemctl list-units --type=service --all
UNIT LOAD ACTIVE SUB DESCRIPTION
accounts-daemon.service loaded active running Accounts Service
......
列出所有的target:
root@ubuntu:~# systemctl list-units --type=target --all |cat
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cloud-config.target loaded active active Cloud-config availability
cloud-init.target loaded active active Cloud-init target
......
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
33 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
2.3 target操作命令
使用systemctl list-units --type=target --all
可以列出所有的target unit。
其中几种常见的是:
graphical.target
,命令行加上图形界面,这个项目已经包含了下面的multi-user.target。multi-user.target
,纯命令行模式。rescue.target
,在无法使用root登入的情况下,systemd在启动时会多加一个额外的临时系统。emergency.target
,紧急处理系统的错误,需要root登录,但是无法使用rescue.target
时,可以尝试使用这个模式。shutdown.target
,关机模式。getty.target
,可设置需要几个tty。
正常使用的模式是multi-user.target
以及graphical.target
两个模式。
下面命令可修改target配置:
systemctl get-default
,取得当前的target。systemctl set-default xxx.target
,设置指定target为默认target。systemctl isolate xxx.target
,切换到后面接的模式。
通常可使用已集成好的命令来操作:
命令 | 描述 |
---|---|
systemctl poweroff | 系统关机 |
systemctl reboot | 重新开机 |
systemctl suspend | 进入挂起模式 |
systemctl hibernate | 进入休眠模式 |
systemctl rescue | 强制进入恢复模式 |
systemctl emergency | 强制进去紧急恢复模式 |
挂起模式,即暂停模式:
- 将系统的状态数据保存到内存中,然后关闭大部分的系统硬件。当用户唤醒机器时,系统数据会从内存中恢复,然后重新驱动被大部分关闭的硬件,并开始正常运行。
休眠模式:
- 将系统的状态保存到硬盘中,保存完毕后,将计算机关机。唤醒时,从硬盘读取系统状态。
2.4 分析服务之间依赖性
使用list-dependencies
列出服务之间的依赖性:
systemctl list-dependencies [unit] [--reverse]
--reverse
反向追踪谁使用这个unit。
示例:
root@ubuntu:~# systemctl list-dependencies
default.target
● ├─accounts-daemon.service
● ├─apport.service
● ├─display-manager.service
● ├─e2scrub_reap.service
● ├─kexec-load.service
● ├─kexec.service
● ├─systemd-update-utmp-runlevel.service
● └─multi-user.target
● ├─apport.service
● ├─atd.service
● ├─console-setup.serv
......
查找谁使用了sshd.service
这个服务:
root@ubuntu:~# systemctl list-dependencies sshd --reverse
sshd.service
● ├─cloud-init.service
● └─multi-user.target
● └─graphical.target
2.5 网络服务和端口的对应关系
在/etc/service
里面存放了各类服务和端口号的对应关系。
root@ubuntu:~# cat /etc/services
# Network services, Internet style
#
# Note that it is presently the policy of IANA to assign a single well-known
# port number for both TCP and UDP; hence, officially ports have two entries
# even if the protocol doesn't support UDP operations.
#
# Updated from https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml .
#
# New ports will be added on request if they have been officially assigned
# by IANA and used in the real-world or are needed by a debian package.
# If you need a huge list of used numbers please install the nmap package.
tcpmux 1/tcp # TCP port service multiplexer
echo 7/tcp
echo 7/udp
discard 9/tcp sink null
discard 9/udp sink null
systat 11/tcp users
daytime 13/tcp
......
3. systemctl配置文件
3.1 service配置文件
直接看一下已有的service unit文件,ssh.service
。
root@ubuntu:~# cat /usr/lib/systemd/system/ssh.service
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
Alias=sshd.service
配置文件可以分成三个配置区段:
Unit
,Unit文件通用,用于配置服务的说明和依赖设置。Service/Socket/Timer/Mount/Path
,不同的unit类型使用相对应的设置项目。Install
,这个项目就是将此unit安装到那个target里面去。
配置文件一般还有以下的规则:
- 设置项目可以重复,并且后面的设置会替换前面的配置。
- 如果设置参数有bool参数,可以使用
1/0
,yes/no
,true/false
,on/off
等组合。 - 空白行、
#/;
开头的行,都代表注释。
3.2 Unit部分参数
Uint存在隐形依赖,如dbus
,会自动添加Requirres=dbus.socket
和After=dbus.socket
。
socket
激活的Service会自动在Socket激活之后再启动,也就是自动将Service添加如.socket单元中的After=。
其可设置参数如下:
Description
:描述这个unit文件的信息,例如使用systemctl list-units
时看到的说明。Documentation
:这个项目在提供管理员能够进一步的文件查询功能,可以是如下内容:Documentation=http://www.....
Documentation=man:sshd(8)
Documentation=file:/etc/ssh/sshd_config
After
:说明此unit在哪一个daemon启动之后才启动。只是说明服务启动的顺序,并不会强制systemctl去启动其要求的服务,注意和后面requires
的区别。Before
:与After的意义相反,在某某服务启动前最好启动这个服务。并非强制启动需求。Requires
:明确的定义此unit需要在哪个daemon启动后才能够启动,即设置依赖服务。如果要求的服务没有启动,那么该unit便不会启动。Wants
:与Requires
相似,规范这个unit之后最好还要启动什么服务。并非强制规范,如果要求业务启动失败,也不会影响当前unit。Conflicts
:代表冲突的服务,如果这个服务列表里面有启动的服务,那么当前unit就不能启动。Binds to
:与Requires
相似,如果绑定列表里面任意一个结束或重启,那么当前unit也会跟着结束和重启。Part Of
:一个Bind To
作用的子集,仅在列出的任务模块失败或重启时,终止或重启当前服务,而不会随列出模板的启动而启动。OnFailure
:当这个模板启动失败时,就会自动启动列出的每个模块。Conditionxxx
:当前unit运行必须满足的条件。如ConditionHost=
、ConditionUser=
等。Assertxxx:
如果后面条件不满足,就会报错。
3.3 Install部分参数
可设置参数如下:
WantedBy
:这个设置后面接的大部分是*.target unit
,指明这个unit本身是依附于哪一个target unit
。通常大多数服务性质的unit都是依赖于multi-user.target
。Also
:当目标这个unit本身被enable时,Also后面接的unit
也enable
的意思。Alias
:运行一个链接别名的意思,可以使用别名来操作当前这个unit
。
3.4 Service部分参数
可设置参数如下:
Type
:定义启动时的进程行为,对下面的ExecStart
会有影响:simple
,默认值,由ExecStart接的命令来启动,启动后常驻内存。forking
,由ExecStart
启动的程序通过spawns扩展出其他子程序来做为此daemon的主要服务。原始的父进程在启动结束之后就会终止运行。oneshot
:与simple类似,不过这个进程在工作完毕后就关闭,不会常驻内存。dbus
:这个daemon需要获取一个D-Bus的名称之后,才会继续运行,该项目通常要设置BusName=
。idle
:这类daemon通常是开机到最后才执行的服务。
EnvironmentFile
:可以指定启动脚本的环境配置文件,如EnvironmentFile=-/etc/default/ssh
。ExecStart
:实际执行此daemon的命令或脚本程序。命令串一般只能接受简单的bash命令。ExecStop
:与systemctl stop的执行有关,关闭此服务时所运行的命令。ExecReload
:与systemctl reload有关的命令操作。Restart
:当Restart=1
时,则当此daemon服务终止后,会再次启动此服务。RemainAfterExit
:当设置为RemainAfterExit=1时,则当这个daemon所属的所有进程都终止后,此服务会再尝试启动,这对于Type=oneshot的服务很有帮助。TimeoutSec
:若这个服务在启动或关闭时,因为某些原因导致无法顺利(正常启动或结束),那么timeout之后便强制结束。KillMOde
:可以是process
、control-group
、none
其中一种,如果是process则daemon终止时,只会终止主要的进程ExecStart
接的后面那串命令。RestartSec
:与Restart有相关性,如果这个服务被关闭,然后需要重新启动时,大概要sleep多少时间再重新启动的意思,默认是100ms(毫秒)。
Restart可选参数及其对应启动关系如下:
Restart= | no | always | on-success | on-failure | on-abnormal | on-abort | on-watchdog |
---|---|---|---|---|---|---|---|
正常退出 | T | T | |||||
退出码不为0 | T | T | |||||
进程被强制杀死 | T | T | T | T | |||
systemd操作超时 | T | T | T | ||||
看门狗超时 | T | T | T | T |
3.5 模板unit文件
可以查看getty@.service
,特殊处在于:
root@ubuntu:~# cat /usr/lib/systemd/system/getty@.service
[Unit]
Description=Getty on %I
Documentation=man:agetty(8) man:systemd-getty-generator(8)
......
[Service]
ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear %I $TERM
Type=idle
Restart=always
RestartSec=0
UtmpIdentifier=%I
TTYPath=/dev/%I
.....
通过使用getty@tty1/getty@tty2/getty@tty3
等方式实例化多个不同的终端。
即上面%I
用于替换tty
,如getty@tty1
,实际执行的ExecStart
为:
ExecStart=-/sbin/agetty -o '-p -- \\u' --noclear tty1 linux