认识系统服务(daemon)
1、什么是 daemon 与服务(service)
服务:常驻内存的程序,且可以提供一些系统或网络功能,那就是服务。达成这个 service 的程序我们就称为 daemon。
1.1、早期 System V 的 init 管理行为中 daemon 的主要分类(Optional)
在早期的系统中我们启动系统服务的管理方式被称为 Sys V 的 init 脚本程序的处理方式!即系统内核第一支呼叫的程序是 init,然后 init 去唤起所有的系统所需要的服务,不论是本地服务还是网络服务。基本上 init 管理机制有几个特色如下:
-
服务的启动、关闭与观察等方式:
所有的服务启动脚本通通放在 /etc/init.d/ 底下,基本上都是使用 bash shell script 所写成的脚本程序,需要启动、关闭、重启、观察状态时,可以通过如下的方式:
- 启动:/etc/init.d/daemon start
- 关闭:/etc/init.d/daemon stop
- 重启:/etc/init.d/daemon restart
- 观察状态:/etc/init.d/daemon status
-
服务启动的分类:
init 服务的分类中,依据服务是独立启动或被一支总管程序管理而分为两大类:
- 独立启动模式(stand alone):服务独立启动,该服务直接常驻内存,提供本机或用户的服务行为,反应速度快;
- 总管程序(super daemon):由特殊的 xinetd 或 inetd 这两个程序提供 socket 对应或 port 对应的管理。当没有用户要求 socket 或 port 时,所需要的服务是不会被启动的。若用户要求时,xinetd 总管程序才会去唤醒对应的服务。当要求结束时,这个服务也会被结束掉。
-
服务的相依赖性问题
-
执行的等级分类:
上面说到的 init 是开机后内核主动呼叫的,然后 init 可以根据用户自定义的执行等级(runlevel)来唤醒不同的服务,以进入不同的操作界面。基本上, Linux 提供 7 个执行等级,分别是 0,1,…,6,比较重要的是(1)单人维护模式、(3)纯文本模式、(5)文字加图形界面。而各个执行等级的启动脚本是通过:/etc/rc.d/rc[0-6]/SXXdaemon 链接到 /etc/init.d/daemon ,链接文件的功能是:S 为启动该服务,XX 是数字,为启动的顺序。由于有 SXX 的设定,因此开机时可以 “依序执行” 所有需要的服务,同时也能解决相依赖性的问题。
-
制定执行等级默认要启动的服务:
若要建立如上提到的 SXXdaemon 的话,不需要管理员手动建立连接文件,通过如下的指令来处理默认启动、预设不启动、观察预设启动与否的行为:
- 预设要启动:chkconfig daemon on
- 预设不启动:chkconfig daemon off
- 观察预设为启动否:chkconfig --list daemon
-
执行等级的切换:
当你要从纯文本界面(lrunevel 3)切换到图形界面(runlevel 5),不需要手动启动、关闭该执行等级的相关服务,只要 “init 5” 即可切换。
1.2、systemd 使用的 unit 分类
CentOS 7.x 后该用了 systemd 这个启动服务管理机制:
-
平行处理所有程序,加速开机流程:
旧的 init 启动脚本是 “一项一项任务依序启动” 的模式,因此不相邻的服务也是要一个一个等待。现在的硬件架构与操作系统都支持多核架构了,所以支持并行启动。
-
一经要求就响应的 on-demand 启动方式:
systemd 全部就是仅有一只 systemd 服务搭配 systemctl 指令来处理,无须其他额外的指令支持。此外,systemd 由于常驻内存,因此任何要求(on-demand)都可以立即处理后续的 daemon 启动任务。
-
服务相依性的自我检查:
由于 systemd 可以自定义服务相依性的检查,因此如果 B 服务是架构在 A 服务上面启动的,那当你在没有启动 A 服务的情况下仅手动启动 B 服务时,systemd 会自动帮你启动 A 服务。
-
依 daemon 功能分类:
systemd 旗下管理的服务非常多,为了厘清所有的服务功能,因此,首先 systemd 先定义所有的服务为一个服务单元(unit),并将该 unit 归类到不同的服务类型(type)中去。systemd 将服务单元区分为 service,socket,target,path,timer 等不同类型。
-
将多个 daemons 集合成为一个群组:
-
向下兼容 init 服务脚本。
虽然如此,不过 systemd 也是有些地方无法完全取代 init 的!包括:
- 在 runlevel 的对应上,大概仅有 runlevel 1,3,5 有对应的 systemd 的某些 target 类型而已,没有全部对应;
- 全部的 systemd 都用 systemctl 这个管理程序管理,而 systemctl 支持的语法有限,不像 /etc/init.d/daemon 就是纯脚本可以自定义参数,systemctl 不可自定义参数;
- 如果某个服务启动是管理员自己动手执行启动,而不是使用 systemctl 去启动的,那么 systemd 将无法侦测到该服务,从而无法进一步管理;
- systemd 启动过程中,无法与管理员通过 standard input 传入信息!因此,自行撰写 systemd 的启动设定时,务必要取消互动机制。
1.2.1、systemd 的配置文件的放置位置
基本上,systemd将过去所谓的daemon执行脚本通通称为一个服务单位(unit),而每种服务单位依据功能来区分时,就分类为不同的类型(type)。基本的类型有包括系统服务、数据监听与交换的插槽档服务(socket)、存储系统状态的快照类型、**提供不同类似执行等级分类的操作环境(target)**等等。
/usr/lib/systemd/system/ #每个服务最主要的启动脚本设定,有点类似于以前的/etc/init.d底下的文件;
/run/systemd/system/ #系统执行过程中所产生的服务脚本,这些脚本优先级要比/usr/lib/systemd/system/高;
/etc/systemd/system/ #管理员依据主机系统的需求所建立的执行脚本,其实这个目录优点类似于以前的/etc/rc.d/rc5.d/Sxx,执行优先级比/run/systemd/system/高!
也就是所,到底系统开机会不会执行某些服务其实是看 /etc/systemd/system/ 底下的设定,所以该目录底下就是一大堆链接档。而实际执行的 systemd 启动脚本配置文件,都是在 /usr/lib/systemd/system/ 底下。/etc/systemd/system/ 仅仅是链接到正确地执行脚本配置文件而已。所以想要看执行脚本设定,应该就要看 /usr/lib/systemd/system/ 底下去查阅才行!
1.2.2、systemd 的 unit 类型分类说明
那 /usr/lib/systemd/system/ 以下的数据如何区分上述所谓的不同类型呢?看扩展名即可。
[root@li ~]# ll /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'
-rw-r--r--. 1 root root 318 8月 9 2019 crond.service
-rw-r--r--. 1 root root 492 8月 7 01:30 multi-user.target
drwxr-xr-x. 2 root root 258 8月 17 10:27 multi-user.target.wants
lrwxrwxrwx. 1 root root 17 8月 17 10:27 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 8月 17 10:27 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 8月 17 10:27 runlevel4.target -> multi-user.target
几种常见的 systemd 的服务类型如下:
扩展名 | 主要服务功能 |
---|---|
.service | 一般服务类型:主要是系统服务,包括服务器本身所需要的本地服务以及网络服务都是! |
.socket | 内部程序数据交换的插槽服务 |
.target | 执行环境类型:其实就是一群unit的集合 |
.mount .automount | 文件系统挂载相关服务 |
.path | 侦测特定文件或目录类型 |
.timer | 循环执行的服务 |
2、通过 systemctl 管理服务
2.1、通过 systemctl 管理单一服务的启动/开机启动与观察状态
[root@li ~]# systemctl [command] [unit]
command主要有:
start :立刻启动后面的 unit
stop :立刻关闭后面的 unit
restart :立刻关闭后启动后面的 unit
reload :不关闭后面的 unit 的情况下,重载配置文件,让设定生效
enable :开机自启
disable :取消开机自启
status :显示 unit 的状态
is-active :目前有没有正在运行
is-enable :开机时有没有预设要启动 unit
#1、查看 crond 这个服务的状态信息
[root@li ~]# systemctl status crond.service
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since 三 2020-08-19 15:58:41 CST; 9min ago
Main PID: 664 (crond)
CGroup: /system.slice/crond.service
└─664 /usr/sbin/crond -n
8月 19 15:58:41 li.erver systemd[1]: Started Command Scheduler.
8月 19 15:58:41 li.erver crond[664]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 1...d.)
8月 19 15:58:42 li.erver crond[664]: (CRON) INFO (running with inotify support)
Hint: Some lines were ellipsized, use -l to show in full.
#重点在第 2,3 行
#Loaded:说明开机的时候这个 unit 会不会自启,enabled 为开机自启,disabled 为开机不会自启
#Active:现在这个 unit 的状态是正在执行(running)或没有执行(dead)
#2、正常关闭这个服务
[root@li ~]# systemctl stop crond
[root@li ~]# systemctl status crond.service
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: inactive (dead) since 三 2020-08-19 16:11:52 CST; 2s ago
Process: 664 ExecStart=/usr/sbin/crond -n $CRONDARGS (code=exited, status=0/SUCCESS)
Main PID: 664 (code=exited, status=0/SUCCESS)
8月 19 15:58:41 li.erver systemd[1]: Started Command Scheduler.
8月 19 15:58:41 li.erver crond[664]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 1...d.)
回到 systemctl status crond.service 的第三行,不是有个 Active 的 daemon 现在状态码?除了 running 和 dead 之外,有没有其他状态呢?基本上,常见的几种状态如下:
- active(running):执行
- active(exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行
- active(waiting):正在执行中,不过还要等待其他的事件才能继续处理
- inactive(dead):没有在执行
那么 daemon 的预设状态除了 enable/disable 之外,还有其他的情况吗?
- enabled:开机被执行
- disabled:开机不执行
- static:不可以自己启动,但可能会被其他程序来唤醒
- masked:无论如何都无法启动
2.1.1、服务启动/关闭与观察的练习
因为这台服务器没有打印机,因此我想把 cups 服务整个关掉,是否可以?
#1、先看看 cups 的服务是开的还是关的?
[root@li ~]# systemctl status cups.service
● cups.service - CUPS Printing Service
Loaded: loaded (/usr/lib/systemd/system/cups.service; enabled; vendor preset: enabled)
Active: inactive (dead) since 三 2020-08-19 16:24:19 CST; 1s ago
Process: 10391 ExecStart=/usr/sbin/cupsd -f (code=exited, status=0/SUCCESS)
Main PID: 10391 (code=exited, status=0/SUCCESS)
#有趣的是,竟然是 enable 但还却是 head
#2、那就直接关闭,同时确认没有启动
[root@li ~]# systemctl stop cups.service
[root@li ~]# systemctl disable cups.service
Removed symlink /etc/systemd/system/multi-user.target.wants/cups.path.
Removed symlink /etc/systemd/system/multi-user.target.wants/cups.service.
Removed symlink /etc/systemd/system/sockets.target.wants/cups.socket.
Removed symlink /etc/systemd/system/printer.target.wants/cups.service.
#一口气关掉了 4 个连接文件,说明这 4 个文件有相依赖的关系
[root@li ~]# netstat -tulnp | grep cups
#不会产生任何数据
#3、尝试启动 cups.socket 监听客户端的需求
[root@li ~]# systemctl start cups.socket
[root@li ~]# systemctl status cups.socket cups.service cups.path
● cups.socket - CUPS Printing Service Sockets
Loaded: loaded (/usr/lib/systemd/system/cups.socket; disabled; vendor preset: enabled)
Active: active (listening) since 三 2020-08-19 16:28:35 CST; 22s ago
Listen: /var/run/cups/cups.sock (Stream)
8月 19 16:28:35 li.erver systemd[1]: Listening on CUPS Printing Service Sockets.
● cups.service - CUPS Printing Service
Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
Active: inactive (dead)
8月 19 16:23:32 li.erver systemd[1]: Started CUPS Printing Service.
8月 19 16:24:19 li.erver systemd[1]: Stopping CUPS Printing Service...
8月 19 16:24:19 li.erver systemd[1]: Stopped CUPS Printing Service.
● cups.path - CUPS Printer Service Spool
Loaded: loaded (/usr/lib/systemd/system/cups.path; disabled; vendor preset: enabled)
Active: inactive (dead)
#仅有 cups.socket 在启动
#4、尝试使用 lp 这个指令打印看看
[root@li ~]# echo "testing" | lp
lp: Error - no default destination available.
#实际上就是没有打印机,显示错误也没关系
[root@li ~]# systemctl status cups.service
● cups.service - CUPS Printing Service
Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
Active: active (running) since 三 2020-08-19 16:30:17 CST; 38s ago
[root@li ~]# netstat -tulnp | grep cups
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 12876/cupsd
tcp6 0 0 ::1:631 :::* LISTEN 12876/cupsd
#竟然自己启动了,我们并没有启动它
从上面的案例可知,很多服务之间是相互依赖的。cups 是一种打印服务,这个服务会启动 631 端口来提供网络打印机的打印功能。但是其实我们无须一直启动 631 端口。因此多了一个 cups.socket 的服务,这个服务可以在 “用户有打印需求的时候,才会唤醒 cups.service” 的意思。因此,如果仅仅是 disable/stop cups.service 而忘记其他两个服务的话,那么当用户向其他两个 cups.path 和 cups.socket 提出要求时,cups.service 就会被唤醒!
2.1.2、强迫服务注销(mask)的练习
比较正规的做法是,要关闭 cups.service 时,连同其他两个会唤醒 cups.socket 与 cups.path 通通关闭,那就没事了。比较不正规的做法是,那就强迫 cups.service 注销。
[root@li ~]# systemctl stop cups.service
Warning: Stopping cups.service, but it can still be activated by:
cups.socket #警告就说明了,cups.service 就算是关闭了还是会被唤醒
[root@li ~]# systemctl mask cups.service
Created symlink from /etc/systemd/system/cups.service to /dev/null.
[root@li ~]# systemctl status cups.service
● cups.service
Loaded: masked (/dev/null; bad)
Active: inactive (dead) since 三 2020-08-19 16:37:35 CST; 1min 23s ago
Main PID: 12876 (code=exited, status=0/SUCCESS)
[root@li ~]# systemctl start cups.service
Failed to start cups.service: Unit is masked. #再也无法唤醒
那如何取消注销呢?当然是 unmask 即可:
[root@li ~]# systemctl unmask cups.service
Removed symlink /etc/systemd/system/cups.service.
[root@li ~]# systemctl status cups.service
● cups.service - CUPS Printing Service
Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled; vendor preset: enabled)
Active: inactive (dead) since 三 2020-08-19 16:37:35 CST; 3min 21s ago
Main PID: 12876 (code=exited, status=0/SUCCESS)
2.2、通过 systemctl 观察系统上的所有服务
[root@li ~]# systemctl [command] [--type=TYPE] [--all]
command:
list-units :依据 unit 列出目前启动的 unit。若加上 --all 才会列出没启动的
list-unit-files :依据 /usr/lib/systemd/system 内的文件,将所有文件列表说明
#1、列出系统上所启动的 unit
[root@li ~]# systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION
-.mount loaded active mounted /
boot.mount loaded active mounted /boot
dev-hugepages.mount loaded active mounted Huge Pages File System
dev-mqueue.mount loaded active mounted POSIX Message Queue File System
run-user-0.mount loaded active mounted /run/user/0
...
#2、列出所有已经安装的 unit 有哪些
[root@li ~]# systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
...
假如我不想知道这么多的 unit 项目,我只想知道 service 这种类别的 daemon 而已,而且不论是否已经启动,通通列出来:
[root@li ~]# systemctl list-units --type=service --all
UNIT LOAD ACTIVE SUB DESCRIPTION
auditd.service loaded active running Security Auditing Service
● cloud-init-local.service not-found inactive dead cloud-init-local.service
cpupower.service loaded inactive dead Configure CPU power related setti
crond.service loaded active running Command Scheduler
...
#查询系统上是否有以 cpu 为名的服务
[root@li ~]# systemctl list-units --type=service --all | grep cpu
cpupower.service loaded inactive dead Configure CPU power related settings
2.3、通过 systemctl 管理不同的操作环境(target unit)
如何列出与操作界面比较有关的 target 项目呢?
[root@li ~]# systemctl list-units --type=target --all
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
emergency.target loaded inactive dead Emergency Mode
...
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.
32 loaded units listed.
To show all installed unit files use 'systemctl list-unit-files'.
默认有 32 个 target unit,而跟操作界面相关性比较高的 target 主要有以下几个:
- graphical.target:就是文字加上图形界面,这个项目包含了底下的 multi-user.target 项目!
- multi-user.target:纯文本模式!
- rescue.target:在无法使用 root 登录的情况下,systemd 在开机时会多加一个额外的暂时系统,与你原本的系统无关。这时你可以取得 root 的权限来维护你的系统。但是这时额外的系统,因此可能需要动到 chroot 的方式来取得你原来的系统。
- emergency.target:紧急处理系统的错误,还是需要使用 root 登录的情况,在无法使用 rescue.target 的情况下,可以尝试使用这种模式。
- shutdown.target:就是关机的流程。
- getty.target:可以设定你需要几个 tty 之类的,如果想要降低 tty 的项目,可以修改这个东西的配置文件。
[root@li ~]# systemctl [conmand] [unit.target]
选项与参数:
command:
get-default:取得目前的 target
set-default:设定后面的 target 为默认的操作模式
isolate:切换到后面的模式
#我们没有安装图形界面,应该是纯文本模式
[root@li ~]# systemctl get-default
multi-user.target #纯文本模式
在正常的切换情况下,使用上述的 isolate 方式即可。不过为了方便起见,systemd 也提供了数个简单的指令给我们切换操作模式使用:
[root@li ~]# systemctl poweroff #关机
[root@li ~]# systemctl reboot #重启
[root@li ~]# systemctl suspend #暂停模式
[root@li ~]# systemctl hibernate #休眠模式
[root@li ~]# systemctl rescue #救援模式
[root@li ~]# systemctl emergency #紧急模式
- suspend:暂停模式会将系统的状态保存到内存中,然后关闭大部分的系统硬件,当然并没有实际关机。当用户按下唤醒机器的按键时,系统数据会从内存中恢复,然后重新驱动大部分的硬件。唤醒速度较快。
- hibernate:休眠模式则是将系统状态保存到硬盘中,保存完毕后,将计算机关机。当用户唤醒系统时,系统会开始正常工作,然后将保存到硬盘中的系统状态恢复回来。因为是从硬盘中读取,因此速度较慢。
3、通过 systemctl 分析各服务之间的依赖性
[root@li ~]# systemctl list-dependencies [unit] [--reverse]
选项与参数:
--reverse:反向追踪谁在使用这个 unit 的意思!
#1、列出目前的 target 环境下,用到什么特别的 unit
[root@li ~]# systemctl get-default
multi-user.target
[root@li ~]# systemctl list-dependencies
default.target
● ├─auditd.service
● ├─crond.service
● ├─dbus.service
● ├─firewalld.service
● ├─irqbalance.service
● ├─kdump.service
● ├─network.service
● ├─NetworkManager.service
...
default.target 会用到 basic.target + getty.target + remote-fs.target 这三大项目。那么如何查询谁用到 multi-user.target 呢?
[root@li ~]# systemctl list-dependencies --reverse
default.target
● └─graphical.target
4、与 systemd 的 daemon 运作过程相关的目录简介
-
/usr/lib/systemd/system/:
使用 CentOS 官方提供的软件安装后,默认的启动脚本配置文件都放在这里,这里的文件尽量不要修改,要修改时请到 /etc/systemd/system/ 底下修改。
-
/run/systemd/system/:
系统执行过程中所产生的脚本,这些脚本的执行优先级比 /usr/lib/systemd/system/ 高!
-
/etc/systemd/system/:
管理员依据主机系统的需求所建立的执行脚本,其实这个目录有点像以前的 /etc/rc.d/rc5.d/Sxx 之类的功能。优先级比 /run/systemd/system/ 高!
-
/etc/sysconfig/*:
几乎所有的服务都会将初始化的一些选项设定写入这个目录下。举例来说,网络的设定则是写在 /etc/sysconfig/network-srcipts/ 这个目录下。
-
/var/lib/:
一些会产生数据的服务都会将它的数据写入到 /var/lib/ 目录下。举例来说,数据库管理系统 MySQL 的数据库默认就是写入到 /var/lib/mysql 这个目录下的。
-
/run/:
放置了很多 daemon 的暂存文件,包括 lock file 以及 PID file 等。