【BASH】回顾与知识点梳理(三十三)

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

三十三. 认识系统服务 (daemons)

在 Unix-Like 的系统中,你会常常听到 daemon 这个字眼!那么什么是传说中的 daemon 呢?这些 daemon 放在什么地方?他的功能是什么?该如何启动这些 daemon ?又如何有效的将这些 daemon 管理妥当?此外,要如何视察这些daemon 开了多少个 ports ?又这些 ports 要如何关闭?还有还有,晓得你系统的这些 port 各代表的是什么服务吗? 这些都是最基础需要注意的呢!尤其是在架设网站之前,这里的观念就显的更重要了。

从 CentOS 7.x 这一版之后,传统的 init 已经被舍弃,取而代之的是 systemd 这个家伙~这家伙跟之前的 init 有什么差异? 优缺点为何?如何管理不同种类的服务类型?以及如何取代原本的『执行等级』等等,很重要的改变喔!

33.1 什么是 daemon 与服务 (service)

我们曾经谈过『服务』这东西! 当时的说明是『常驻在记体体中的程序,且可以提供一些系统或网络功能,那就是服务』。而服务一般的英文说法是『service』。

简单的说,系统为了某些功能必须要提供一些服务 (不论是系统本身还是网络方面),这个服务就称为 service 。 但是 service 的提供总是需要程序的运作吧!否则如何执行呢?所以达成这个 service 的程序我们就称呼他为 daemon 啰! 举例来说,达成循环型例行性工作排程服务 (service) 的程序为 crond 这个 daemon 啦!这样说比较容易理解了吧!

daemon 既然是一只程序执行后的程序,那么 daemon 所处的那个原本的程序通常是如何命名的呢 (daemon 程序的命名方式)。 每一个服务的开发者,当初在开发他们的服务时,都有特别的故事啦!不过,无论如何,这些服务的名称被建立之后,被挂上 Linux 使用时,通常在服务的名称之后会加上一个 d ,例如例行性命令的建立的 at, 与 cron 这两个服务, 他的程序文件名会被取为 atd 与 crond,这个 d 代表的就是daemon 的意思。

早期 System V 的 init 管理行为中 daemon 的主要分类 (Optional)

那个很纯种的 Unix 版本~ 在那种年代底下,我们启动系统服务的管理方式被称为 SysV 的 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 总管才会去唤醒相对应的服务程序。当该要求结束时,这个服务也会被结束掉~ 因为透过xinetd 所总管,因此这个家伙就被称为 super daemon。好处是可以透过 super daemon 来进行服务的时程、联机需求等的控制,缺点是唤醒服务需要一点时间的延迟。
  • 服务的相依性问题:
    服务是可能会有相依性的~例如,你要启动网络服务,但是系统没有网络, 那怎么可能可以唤醒网络服务呢?如果你需要联机到外部取得认证服务器的联机,但该联机需要另一个 A 服务的需求,问题是,A 服务没有启动, 因此,你的认证服务就不可能会成功启动的!这就是所谓的服务相依性问题。init 在管理员自己手动处理这些服务时,是没有办法协助相依服务的唤醒的!

  • 执行等级的分类:
    上面说到 init 是开机后核心主动呼叫的, 然后 init 可以根据用户自定义的执行等级 (runlevel) 来唤醒不同的服务,以进入不同的操作界面。基本上 Linux 提供 7 个执行等级,分别是 0, 1, 2…6 , 比较重要的是

    • 1)单人维护模式
    • 3)纯文本模式
    • 5)文字加图形界面

    而各个执行等级的启动脚本是透过/etc/rc.d/rc[0-6]/SXXdaemon 连结到 /etc/init.d/daemon , 连结档名 (SXXdaemon) 的功能为: S 为启动该服务,XX 是数字,为启动的顺序。由于有 SXX 的设定,因此在开机时可以『依序执行』所有需要的服务,同时也能解决相依服务的问题。这点与管理员自己手动处理不太一样就是了。

  • 制定执行等级默认要启动的服务:
    若要建立如上提到的 SXXdaemon 的话,不需要管理员手动建立连结档, 透过如下的指令可以来处理默认启动、预设不启动、观察预设启动否的行为:

    • 预设要启动: chkconfig daemon on
    • 预设不启动: chkconfig daemon off
    • 观察预设为启动否: chkconfig --list daemon
  • 执行等级的切换行为:
    当你要从纯文本界面 (runlevel 3) 切换到图形界面 (runlevel 5), 不需要手动启动、关闭该执行等级的相关服务,只要『 init 5 』即可切换,init 这小子会主动去分析 /etc/rc.d/rc[35].d/ 这两个目录内的脚本, 然后启动转换 runlevel 中需要的服务~就完成整体的 runlevel 切换。

基本上 init 主要的功能都写在上头了,重要的指令包括 daemon 本身自己的脚本(/etc/init.d/daemon) 、xinetd 这个特殊的总管程序 (super daemon)、设定预设开机启动的 chkconfig,以及会影响到执行等级的 init N 等。虽然 CentOS 7 已经不使用 init 来管理服务了,不过因为考虑到某些脚本没有办法直接塞入 systemd 的处理,因此这些脚本还是被保留下来, 所以,我们在这里还是稍微介绍了一下。

systemd 使用的 unit 分类

从 CentOS 7.x 以后,Red Hat 系列的 distribution 放弃沿用多年的 System V 开机启动服务的流程,就是前一小节提到的 init 启动脚本的方法, 改用 systemd 这个启动服务管理机制~那么 systemd 有什么好处呢?

  • 平行处理所有服务,加速开机流程:
    旧的 init 启动脚本是『一项一项任务依序启动』的模式,因此不相依的服务也是得要一个一个的等待。但目前我们的硬件主机系统与操作系统几乎都支持多核心架构了, 没道理未相依的服务不能同时启动啊!systemd 就是可以让所有的服务同时启动,因此你会发现到,系统启动的速度变快了!
  • 一经要求就响应的 on-demand 启动方式:
    systemd 全部就是仅有一只 systemd 服务搭配 systemctl 指令来处理,无须其他额外的指令来支持。不像systemV 还要 init, chkconfig, service… 等等指令。 此外, systemd 由于常驻内存,因此任何要求(on-demand) 都可以立即处理后续的 daemon 启动的任务。
  • 服务相依性的自我检查:
    由于 systemd 可以自定义服务相依性的检查,因此如果 B 服务是架构在 A 服务上面启动的,那当你在没有启动 A 服务的情况下仅手动启动 B 服务时, systemd 会自动帮你启动 A 服务喔!这样就可以免去管理员得要一项一项服务去分析的麻烦~(如果读者不是新手,应该会有印象,当你没有启动网络, 但却启动NIS/NFS 时,那个开机时的 timeout 甚至可达到 10~30 分钟…)
  • 依 daemon 功能分类:
    systemd 旗下管理的服务非常多,包山包海啦~为了厘清所有服务的功能,因此,首先 systemd 先定义所有的服务为一个服务单位 (unit),并将该 unit 归类到不同的服务类型 (type) 去。 旧的 init 仅分为 stand alone 与 super daemon 实在不够看,systemd 将服务单位 (unit) 区分为 service, socket, target, path, snapshot, timer 等多种不同的类型(type), 方便管理员的分类与记忆。
  • 将多个 daemons 集合成为一个群组:
    如同 systemV 的 init 里头有个 runlevel 的特色,systemd 亦将许多的功能集合成为一个所谓的 target 项目,这个项目主要在设计操作环境的建置, 所以是集合了许多的 daemons,亦即是执行某个 target 就是执行好多个 daemon 的意思!
  • 向下兼容旧有的 init 服务脚本:
    基本上, systemd 是可以兼容于 init 的启动脚本的,因此,旧的 init 启动脚本也能够透过 systemd 来管理,只是更进阶的 systemd 功能就没有办法支持就是了。

虽然如此,不过 systemd 也是有些地方无法完全取代 init 的!包括:

  • 在 runlevel 的对应上,大概仅有 runlevel 1, 3, 5 有对应到 systemd 的某些 target 类型而已,没有全部对应;
  • 全部的 systemd 都用 systemctl 这个管理程序管理,而 systemctl 支持的语法有限制,不像/etc/init.d/daemon 就是纯脚本可以自定义参数,systemctl 不可自定义参数。
  • 如果某个服务启动是管理员自己手动执行启动,而不是使用 systemctl 去启动的 (例如你自己手动输入crond 以启动 crond 服务),那么 systemd 将无法侦测到该服务,而无法进一步管理。
  • systemd 启动过程中,无法与管理员透过 standard input 传入讯息!因此,自行撰写 systemd 的启动设定时,务必要取消互动机制~(连透过启动时传进的标准输入讯息也要避免!)

不过,光是同步启动服务脚本这个功能就可以节省你很多开机的时间~同时 systemd 还有很多特殊的服务类型 (type) 可以提供更多有趣的功能!确实值得学一学~ 而且 CentOS 7 已经用了 systemd 了!想不学也不行啊~哈哈哈!好~既然要学,首先就得要针对 systemd 管理的 unit 来了解一下。

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/ 底下的喔!因此如果你想要修改某个服务启动的设定,应该要去/usr/lib/systemd/system/ 底下修改才对! /etc/systemd/system/ 仅是连结到正确的执行脚本配置文件而已。所以想要看执行脚本设定,应该就得要到 /usr/lib/systemd/system/ 底下去查阅才对!

systemd 的 unit 类型分类说明

那 /usr/lib/systemd/system/ 以下的数据如何区分上述所谓的不同的类型 (type) 呢?很简单!看扩展名!举例来说,我们来瞧瞧上一章谈到的 vsftpd 这个范例的启动脚本设定, 还有 crond 与纯文本模式的 multi-user 设定:

[root@study ~]# ll /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'
-rw-r--r--. 1 root root 284 730 2014 crond.service			#
-rw-r--r--. 1 root root 567 36 06:51 multipathd.service
-rw-r--r--. 1 root root 524 36 13:48 multi-user.target	#
drwxr-xr-x. 2 root root 4096 54 17:52 multi-user.target.wants
lrwxrwxrwx. 1 root root 17 54 17:52 runlevel2.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 54 17:52 runlevel3.target -> multi-user.target
lrwxrwxrwx. 1 root root 17 54 17:52 runlevel4.target -> multi-user.target
-rw-r--r--. 1 root root 171 610 2014 vsftpd.service			#
-rw-r--r--. 1 root root 184 610 2014 vsftpd@.service
-rw-r--r--. 1 root root 89 610 2014 vsftpd.target
# 比较重要的是上头提供的那三行特殊字体的部份!

所以我们可以知道 vsftpd 与 crond 其实算是系统服务 (service),而 multi-user 要算是执行环境相关的类型 (target type)。根据这些扩展名的类型, 我们大概可以找到几种比较常见的 systemd 的服务类型如下:

扩展名主要服务功能
.service一般服务类型 (service unit):主要是系统服务,包括服务器本身所需要的本地服务以及网络服务都是!比较经常被使用到的服务大多是这种类型! 所以,这也是最常见的类型了!
.socket内部程序数据交换的插槽服务 (socket unit):主要是 IPC (Inter-process communication) 的传输讯息插槽文件 (socket file) 功能。 这种类型的服务通常在监控讯息传递的插槽文件,当有透过此插槽文件传递讯息来说要链接服务时,就依据当时的状态将该用户的要求传送到对应的 daemon, 若 daemon 尚未启动,则启动该daemon 后再传送用户的要求。
使用 socket 类型的服务一般是比较不会被用到的服务,因此在开机时通常会稍微延迟启动的时间 (因为比较没有这么常用嘛!)。一般用于本地服务比较多,例如我们的图形界面很多的软件都是透过 socket 来进行本机程序数据交换的行为。 (这与早期的xinetd 这个 super daemon 有部份的相似喔!)
.target执行环境类型 (target unit):其实是一群 unit 的集合,例如上面表格中谈到的 multi-user.target 其实就是一堆服务的集合~也就是说, 选择执行 multi-user.target 就是执行一堆其他 .service 或/及 .socket 之类的服务就是了!
.mount
.automount
文件系统挂载相关的服务 (automount unit / mount unit):例如来自网络的自动挂载、NFS 文件系统挂载等与文件系统相关性较高的程序管理。
.path侦测特定文件或目录类型 (path unit):某些服务需要侦测某些特定的目录来提供队列服务,例如最常见的打印服务,就是透过侦测打印队列目录来启动打印功能! 这时就得要 .path 的服务类型支持了!
.timer循环执行的服务 (timer unit):这个东西有点类似 anacrontab 喔!不过是由 systemd 主动提供的,比 anacrontab 更加有弹性!

其中又以 .service 的系统服务类型最常见了!因为我们一堆网络服务都是透过这种类型来设计的啊!接下来,让我们来谈谈如何管理这些服务的启动与关闭。

33.2 透过 systemctl 管理服务

基本上, systemd 这个启动服务的机制,主要是透过一只名为 systemctl 的指令来处理的!跟以前systemV 需要 service / chkconfig / setup / init 等指令来协助不同, systemd 就是仅有 systemctl 这个指令来处理而已呦!所以全部的行为都得要使用 systemctl 的意思啦!有没有很难?其实习惯了之后,鸟哥是觉得 systemctl 还挺好用的!^_^

透过 systemctl 管理单一服务 (service unit) 的启动/开机启动与观察状态

一般来说,服务的启动有两个阶段,一个是『开机的时候设定要不要启动这个服务』, 以及『你现在要不要启动这个服务』,这两者之间
有很大的差异喔!举个例子来说,假如我们现在要『立刻取消 atd 这个服务』时,正规的方法 (不要用 kill) 要怎么处理?

[root@study ~]# systemctl [command] [unit]
command 主要有:
	start :立刻启动后面接的 unit
	stop :立刻关闭后面接的 unit
	restart :立刻关闭后启动后面接的 unit,亦即执行 stop 再 start 的意思
	reload :不关闭后面接的 unit 的情况下,重载配置文件,让设定生效
	enable :设定下次开机时,后面接的 unit 会被启动
	disable :设定下次开机时,后面接的 unit 不会被启动
	status :目前后面接的这个 unit 的状态,会列出有没有正在执行、开机预设执行否、登录等信息等!
	is-active :目前有没有正在运作中
	is-enable :开机时有没有预设要启用这个 unit
# 范例一:看看目前 atd 这个服务的状态为何?
[root@study ~]# systemctl status atd.service
atd.service - Job spooling tools
 Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)	#2
 Active: active (running) since Mon 2015-08-10 19:17:09 CST; 5h 42min ago	#3
Main PID: 1350 (atd)
 CGroup: /system.slice/atd.service
 └─1350 /usr/sbin/atd -f
Aug 10 19:17:09 study.centos.vbird systemd[1]: Started Job spooling tools.
# 重点在第二、三行喔~
# Loaded:这行在说明,开机的时候这个 unit 会不会启动,enabled 为开机启动,disabled 开机不会启动
# Active:现在这个 unit 的状态是正在执行 (running) 或没有执行 (dead)
# 后面几行则是说明这个 unit 程序的 PID 状态以及最后一行显示这个服务的登录文件信息!
# 登录文件信息格式为:『时间』 『讯息发送主机』 『哪一个服务的讯息』 『实际讯息内容』
# 所以上面的显示讯息是:这个 atd 预设开机就启动,而且现在正在运作的意思!

好!再回到 systemctl status atd.service 的第三行,不是有个 Active 的 daemon 现在状态吗?除了running 跟 dead 之外, 有没有其他的状态呢?有的~基本上有几个常见的状态:

  • active (running):正有一只或多只程序正在系统中执行的意思,举例来说,正在执行中的 vsftpd 就是这种模式。
  • active (exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行。 举例来说,开机或者是挂载时才会进行一次的 quotaon 功能,就是这种模式! quotaon 不须一直执行~只须执行一次之后,就交给文件系统去自行处理啰!通常用 bash shell 写的小型服务,大多是属于这种类型 (无须常驻内存)。
  • active (waiting):正在执行当中,不过还再等待其他的事件才能继续处理。举例来说,打印的队列相关服务就是这种状态! 虽然正在启动中,不过,也需要真的有队列进来 (打印作业) 这样他才会继续唤醒打印机服务来进行下一步打印的功能。
  • inactive:这个服务目前没有运作的意思。

既然 daemon 目前的状态就有这么多种了,那么 daemon 的预设状态有没有可能除了 enable/disable 之外,还有其他的情况呢?当然有!

  • enabled:这个 daemon 将在开机时被执行
  • disabled:这个 daemon 在开机时不会被执行
  • static:这个 daemon 不可以自己启动 (enable 不可),不过可能会被其他的 enabled 的服务来唤醒 (相依属性的服务)
  • mask:这个 daemon 无论如何都无法被启动!因为已经被强制注销 (非删除)。可透过 systemctl unmask 方式改回原本状态
服务启动/关闭与观察的练习
  • 找到系统中名为 chronyd 的服务,观察此服务的状态,观察完毕后,将此服务设定为: 1)开机不会启动 2)现在状况是关闭的情况!
    回答:我们直接使用指令的方式来查询与设定看看:
    [root@node-135 vsftpd]# systemctl disable chronyd
    Removed symlink /etc/systemd/system/multi-user.target.wants/chronyd.service.
    [root@node-135 vsftpd]# systemctl stop chronyd
    
    看得很清楚~其实就是从 /etc/systemd/system 底下删除一条连结文件而已~
  • 因为我根本没有打印机安装在服务器上,目前也没有网络打印机,因此我想要将 cups 服务整个关闭,是否可以呢?
    回答:同样的,眼见为凭,我们就动手作看看:
    # 1. 先看看 cups 的服务是开还是关?
    [root@study ~]# systemctl status cups.service
    cups.service - CUPS Printing Service
     Loaded: loaded (/usr/lib/systemd/system/cups.service; enabled)
     Active: inactive (dead) since Tue 2015-08-11 19:19:20 CST; 3h 29min ago
    # 有趣得很!竟然是 enable 但是却是 inactive 耶!相当特别!
    
    # 2. 那就直接关闭,同时确认没有启动喔!
    [root@study ~]# systemctl stop cups.service
    [root@study ~]# systemctl disable cups.service
    rm '/etc/systemd/system/multi-user.target.wants/cups.path'
    rm '/etc/systemd/system/sockets.target.wants/cups.socket'
    rm '/etc/systemd/system/printer.target.wants/cups.service'
    # 也是非常特别!竟然一口气取消掉三个连结档!也就是说,这三个文件可能是有相依性的问题喔!
    [root@study ~]# netstat -tlunp | grep cups
    # 现在应该不会出现任何数据!因为根本没有 cups 的任务在执行当中~所以不会有 port 产生
    
    # 3. 尝试启动 cups.socket 监听客户端的需求喔!
    [root@study ~]# systemctl start cups.socket
    [root@study ~]# systemctl status cups.service cups.socket cups.path
    cups.service - CUPS Printing Service
     Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
     Active: inactive (dead) since Tue 2015-08-11 22:57:50 CST; 3min 41s ago
    cups.socket - CUPS Printing Service Sockets
     Loaded: loaded (/usr/lib/systemd/system/cups.socket; disabled)
     Active: active (listening) since Tue 2015-08-11 22:56:14 CST; 5min ago
    cups.path - CUPS Printer Service Spool
     Loaded: loaded (/usr/lib/systemd/system/cups.path; disabled)
     Active: inactive (dead)
    # 确定仅有 cups.socket 在启动,其他的并没有启动的状态!
    
    # 4. 尝试使用 lp 这个指令来打印看看?
    [root@study ~]# echo "testing" | lp
    lp: Error - no default destination available. # 实际上就是没有打印机!所以有错误也没关系!
    [root@study ~]# systemctl status cups.service
    cups.service - CUPS Printing Service
     Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
     Active: active (running) since Tue 2015-08-11 23:03:18 CST; 34s ago
    [root@study ~]# netstat -tlunp | grep cups
    tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 25881/cupsd
    tcp6 0 0 ::1:631 :::* LISTEN 25881/cupsd
    # 见鬼!竟然 cups 自动被启动了!明明我们都没有驱动他啊!怎么回事啊?
    

上面这个范例的练习在让您了解一下,很多服务彼此之间是有相依性的!cups 是一种打印服务,这个打印服务会启用 port 631 来提供网络打印机的打印功能。 但是其实我们无须一直启动 631 埠口吧?因此,多了一个名为 cups.socket 的服务,这个服务可以在『用户有需要打印时,才会主动唤醒cups.service 』的意思! 因此,如果你仅是 disable/stop cups.service 而忘记了其他两个服务的话,那么当有用户向其他两个 cups.path, cups.socket 提出要求时, cups.service 就会被唤醒!所以,你关掉也没用!

强迫服务注销 (mask) 的练习

比较正规的作法是,要关闭 cups.service 时,连同其他两个会唤醒 service 的 cups.socket 与cups.path 通通关闭,那就没事了! 比较不正规的作法是,那就强迫 cups.service 注销吧!透过 mask 的方式来将这个服务注销看看!

# 1. 保持刚刚的状态,关闭 cups.service,启动 cups.socket,然后注销 cups.servcie
[root@study ~]# systemctl stop cups.service
[root@study ~]# systemctl mask cups.service
ln -s '/dev/null' '/etc/systemd/system/cups.service'
# 喔耶~其实这个 mask 注销的动作,只是让启动的脚本变成空的装置而已!
[root@study ~]# systemctl status cups.service
cups.service
 Loaded: masked (/dev/null)
 Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 52s ago
[root@study ~]# systemctl start cups.service
Failed to issue method call: Unit cups.service is masked. # 再也无法唤醒!

上面的范例你可以仔细推敲一下~原来整个启动的脚本配置文件被连结到 /dev/null 这个空装置~因此,无论如何你是再也无法启动这个 cups.service 了! 透过这个 mask 功能,你就可以不必管其他相依服务可能会启动到这个想要关闭的服务了!虽然是非正规,不过很有效! ^_^

那如何取消注销呢?当然就是 unmask 即可啊

[root@study ~]# systemctl unmask cups.service
rm '/etc/systemd/system/cups.service'
[root@study ~]# systemctl status cups.service
cups.service - CUPS Printing Service
 Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
 Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 4min 35s ago
# 好佳在有恢复正常!
透过 systemctl 观察系统上所有的服务

系统上面有多少的服务存在呢?这个时候就得要透过 list-units 及 list-unit-files 来观察了! 细部的用法如下:

[root@study ~]# systemctl [command] [--type=TYPE] [--all]
command:
	 list-units :依据 unit 列出目前有启动的 unit。若加上 --all 才会列出没启动的。
	 list-unit-files :依据 /usr/lib/systemd/system/ 内的文件,将所有文件列表说明。
--type=TYPE:就是之前提到的 unit type,主要有 service, socket, target 等
# 范例一:列出系统上面有启动的 unit
[root@study ~]# systemctl
UNIT LOAD ACTIVE SUB DESCRIPTION
proc-sys-fs-binfmt_mis... loaded active waiting Arbitrary Executable File Formats File System
sys-devices-pc...:0:1:... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:1-0... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:0-1... loaded active plugged QEMU_DVD-ROM
.....(中间省略).....
vsftpd.service loaded active running Vsftpd ftp daemon
.....(中间省略).....
cups.socket loaded failed failed CUPS Printing Service Sockets
.....(中间省略).....
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.
141 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
# 列出的项目中,主要的意义是:
# UNIT :项目的名称,包括各个 unit 的类别 (看扩展名)
# LOAD :开机时是否会被加载,默认 systemctl 显示的是有加载的项目而已喔!
# ACTIVE :目前的状态,须与后续的 SUB 搭配!就是我们用 systemctl status 观察时,active 的项目!
# DESCRIPTION :详细描述啰
# cups 比较有趣,因为刚刚被我们玩过,所以 ACTIVE 竟然是 failed 的喔!被玩死了! ^_^
# 另外,systemctl 都不加参数,其实预设就是 list-units 的意思!

# 范例二:列出所有已经安装的 unit 有哪些?
[root@study ~]# systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
dev-hugepages.mount static
dev-mqueue.mount static
proc-fs-nfsd.mount static
.....(中间省略).....
systemd-tmpfiles-clean.timer static
336 unit files listed.

使用 systemctl list-unit-files 会将系统上所有的服务通通列出来~而不像 list-units 仅以 unit 分类作大致的说明。 至于 STATE 状态就是前两个小节谈到的开机是否会加载的那个状态项目啰!主要有enabled / disabled / mask / static 等等。

假设我不想要知道这么多的 unit 项目,我只想要知道 service 这种类别的 daemon 而已,而且不论是否已经启动,通通要列出来! 那该如何是好?

[root@study ~]# systemctl list-units --type=service --all
# 只剩下 *.service 的项目才会出现喔!
# 范例一:查询系统上是否有以 cpu 为名的服务?
[root@study ~]# systemctl list-units --type=service --all | grep cpu
cpupower.service loaded inactive dead Configure CPU power related settings
# 确实有喔!可以改变 CPU 电源管理机制的服务哩!
透过 systemctl 管理不同的操作环境 (target unit)

透过上个小节我们知道系统上所有的 systemd 的 unit 观察的方式,那么可否列出跟操作界面比较有关的 target 项目呢? 很简单啊!就这样搞一下:

[root@node-135 vsftpd]# 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
  final.target              loaded    inactive dead   Final Step
  getty-pre.target          loaded    inactive dead   Login Prompts (Pre)
  getty.target              loaded    active   active Login Prompts
  graphical.target          loaded    inactive dead   Graphical Interface
  initrd-fs.target          loaded    inactive dead   Initrd File Systems
  initrd-root-fs.target     loaded    inactive dead   Initrd Root File System
  initrd-switch-root.target loaded    inactive dead   Switch Root
  initrd.target             loaded    inactive dead   Initrd Default Target
  local-fs-pre.target       loaded    active   active Local File Systems (Pre)
  local-fs.target           loaded    active   active Local File Systems
  multi-user.target         loaded    active   active Multi-User System
  network-online.target     loaded    active   active Network is Online
  network-pre.target        loaded    inactive dead   Network (Pre)
  network.target            loaded    active   active Network
  nss-user-lookup.target    loaded    inactive dead   User and Group Name Lookups
  paths.target              loaded    active   active Paths
  remote-fs-pre.target      loaded    inactive dead   Remote File Systems (Pre)
  remote-fs.target          loaded    active   active Remote File Systems
  rescue.target             loaded    inactive dead   Rescue Mode
  shutdown.target           loaded    inactive dead   Shutdown
  slices.target             loaded    active   active Slices
  sockets.target            loaded    active   active Sockets
  sound.target              loaded    active   active Sound Card
  swap.target               loaded    active   active Swap
  sysinit.target            loaded    active   active System Initialization
● syslog.target             not-found inactive dead   syslog.target
  time-sync.target          loaded    inactive dead   System Time Synchronized
  timers.target             loaded    active   active Timers
  umount.target             loaded    inactive dead   Unmount All Filesystems

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'.

喔!在我们的 CentOS 7.9 的预设情况下,就有 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 的项目,可以修改这个东西的配置文件!

正常的模式是 multi-user.target 以及 graphical.target 两个,救援方面的模式主要是 rescue.target 以及更严重的 emergency.target。 如果要修改可提供登入的 tty 数量,则修改 getty.target 项目。基本上,我们最常使用的当然就是 multi-user 以及 graphical 啰! 那么我如何知道目前的模式是哪一种?又得要如何修改呢?底下来玩一玩吧!

[root@study ~]# systemctl [command] [unit.target]
选项与参数:
command:
	 get-default :取得目前的 target
	 set-default :设定后面接的 target 成为默认的操作模式
	 isolate :切换到后面接的模式
# 范例一:我们的测试机器默认是图形界面,先观察是否真为图形模式,再将默认模式转为文字界面
[root@study ~]# systemctl get-default 
graphical.target # 果然是图形界面喔!
[root@study ~]# systemctl set-default multi-user.target
[root@study ~]# systemctl get-default 
multi-user.target

# 范例二:在不重新启动的情况下,将目前的操作环境改为纯文本模式,关掉图形界面
[root@study ~]# systemctl isolate multi-user.target

# 范例三:若需要重新取得图形界面呢?
[root@study ~]# systemctl isolate graphical.target

在正常的切换情况下,使用上述 isolate 的方式即可。不过为了方便起见, systemd 也提供了数个简单的指令给我们切换操作模式之用喔! 大致上如下所示:

[root@study ~]# systemctl poweroff 系统关机
[root@study ~]# systemctl reboot 重新启动
[root@study ~]# systemctl suspend 进入暂停模式
[root@study ~]# systemctl hibernate 进入休眠模式
[root@study ~]# systemctl rescue 强制进入救援模式
[root@study ~]# systemctl emergency 强制进入紧急救援模式

关机、重新启动、救援与紧急模式这没啥问题,那么什么是暂停与休眠模式呢?

  • suspend:暂停模式会将系统的状态数据保存到内存中,然后关闭掉大部分的系统硬件,当然,并没有实际关机喔! 当用户按下唤醒机器的按钮,系统数据会重内存中回复,然后重新驱动被大部分关闭的硬件,就开始正常运作!唤醒的速度较快。
  • hibernate:休眠模式则是将系统状态保存到硬盘当中,保存完毕后,将计算机关机。当用户尝试唤醒系统时,系统会开始正常运作, 然后将保存在硬盘中的系统状态恢复回来。因为数据是由硬盘读出,因此唤醒的效能与你的硬盘速度有关。
透过 systemctl 分析各服务之间的相依性

我们在本章一开始谈到 systemd 的时候就有谈到相依性的问题克服,那么,如何追踪某一个 unit 的相依性呢? 举例来说好了,我们怎么知道 graphical.target 会用到 multi-user.target 呢?那graphical.target 底下还有哪些东西呢? 底下我们就来谈一谈:

[root@study ~]# systemctl list-dependencies [unit] [--reverse]
选项与参数:
--reverse :反向追踪谁使用这个 unit 的意思!
# 范例一:列出目前的 target 环境下,用到什么特别的 unit
[root@study ~]# systemctl get-default
multi-user.target
[root@study ~]# systemctl list-dependencies
default.target
├─abrt-ccpp.service
├─abrt-oops.service
├─vsftpd.service
├─basic.target
│ ├─alsa-restore.service
│ ├─alsa-state.service
.....(中间省略).....
│ ├─sockets.target
│ │ ├─avahi-daemon.socket
│ │ ├─dbus.socket
.....(中间省略).....
│ ├─sysinit.target
│ │ ├─dev-hugepages.mount
│ │ ├─dev-mqueue.mount
.....(中间省略).....
│ └─timers.target
│ └─systemd-tmpfiles-clean.timer
├─getty.target
│ └─getty@tty1.service
└─remote-fs.target

根据线条联机的流程,我们也能够知道, multi-user.target 其实还会用到 basic.target + getty.target + remote-fs.target 三大项目, 而
basic.target 又用到了 sockets.target + sysinit.target + timers.target… 等一堆~所以啰,从这边就能够清楚的查询到每种 target 模式底下还有的相依模式。 那么如果要查出谁会用到 multi-user.target 呢?就这么作!

[root@study ~]# systemctl list-dependencies --reverse
default.target
└─graphical.target

reverse 本来就是反向的意思,所以加上这个选项,代表『谁还会用到我的服务』的意思~所以看得出来, multi-user.target 主要是被 graphical.target 所使用喔! 好~那再来,graphical.target 又使用了多少的服务呢?可以这样看:

[root@study ~]# systemctl list-dependencies graphical.target
graphical.target
├─accounts-daemon.service
├─gdm.service
├─network.service
├─rtkit-daemon.service
├─systemd-update-utmp-runlevel.service
└─multi-user.target
 ├─abrt-ccpp.service
 ├─abrt-oops.service
.....(底下省略).....

所以可以看得出来,graphical.target 就是在 multi-user.target 底下再加上 accounts-daemon, gdm, network, rtkit-deamon, systemd-update-utmp-runlevel 等服务而已! 这样会看了吗?了解 daemon 之间的相关性也是很重要的喔!出问题时,可以找到正确的服务相依流程!

与 systemd 的 daemon 运作过程相关的目录简介

我们在前几小节曾经谈过比较重要的 systemd 启动脚本配置文件在 /usr/lib/systemd/system/, /etc/systemd/system/ 目录下,那还有哪些目录跟系统的 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/*:
    几乎所有的服务都会将初始化的一些选项设定写入到这个目录下,举例来说,mandb 所要更新的 man page 索引中,需要加入的参数就写入到此目录下的 man-db 当中喔!而网络的设定则写在/etc/sysconfig/network-scripts/ 这个目录内。所以,这个目录内的文件也是挺重要的;
  • /var/lib/:
    一些会产生数据的服务都会将他的数据写入到 /var/lib/ 目录中。举例来说,数据库管理系统 Mariadb 的数据库默认就是写入 /var/lib/mysql/ 这个目录下啦!
  • /run/:
    放置了好多 daemon 的暂存档,包括 lock file 以及 PID file 等等。

我们知道 systemd 里头有很多的本机会用到的 socket 服务,里头可能会产生很多的 socket file ~那你怎么知道这些 socket file 放置在哪里呢? 很简单!还是透过 systemctl 来管理!

[root@node-135 vsftpd]# systemctl list-sockets
LISTEN                      UNIT                         ACTIVATES
/dev/log                    systemd-journald.socket      systemd-journald.service
/run/dbus/system_bus_socket dbus.socket                  dbus.service
/run/dmeventd-client        dm-event.socket              dm-event.service
/run/dmeventd-server        dm-event.socket              dm-event.service
/run/lvm/lvmetad.socket     lvm2-lvmetad.socket          lvm2-lvmetad.service
/run/lvm/lvmpolld.socket    lvm2-lvmpolld.socket         lvm2-lvmpolld.service
/run/systemd/initctl/fifo   systemd-initctl.socket       systemd-initctl.service
/run/systemd/journal/socket systemd-journald.socket      systemd-journald.service
/run/systemd/journal/stdout systemd-journald.socket      systemd-journald.service
/run/systemd/shutdownd      systemd-shutdownd.socket     systemd-shutdownd.service
/run/udev/control           systemd-udevd-control.socket systemd-udevd.service
kobject-uevent 1            systemd-udevd-kernel.socket  systemd-udevd.service

12 sockets listed.
Pass --all to see loaded but inactive sockets, too.

这样很清楚的就能够知道正在监听本地服务需求的 socket file 所在的文件名位置啰!

网络服务与端口口对应简介

系统所有的功能都是某些程序所提供的,而程序则是透过触发程序而产生的。同样的,系统提供的网络服务当然也是这样的! 只是由于网络牵涉到 TCP/IP 的概念,所以显的比较复杂一些就是了。

当客户端联机过来我们的主机时, 我们主机是如何分辨不同的服务要求呢?那就是透过埠号 (端口号,port number) 啦!系统上面有没有什么设定可以让服务与埠号对应在一起呢?那就是 /etc/services 啦!

[root@study ~]# cat /etc/services
....(前面省略)....
ftp 21/tcp
ftp 21/udp fsp fspd
ssh 22/tcp # The Secure Shell (SSH) Protocol
ssh 22/udp # The Secure Shell (SSH) Protocol
....(中间省略)....
http 80/tcp www www-http # WorldWideWeb HTTP
http 80/udp www www-http # HyperText Transfer Protocol
....(底下省略)....
# 这个文件的内容是以底下的方式来编排的:
# <daemon name> <port/封包协议> <该服务的说明>

请特别注意!虽然有的时候你可以藉由修改 /etc/services 来更改一个服务的埠号,不过并不建议如此做, 因为很有可能会造成一些协议的错误情况!这里特此说明一番呦!(除非你要架设一个地下网站,否则的话,使用 /etc/services 原先的设定就好啦!)

关闭网络服务

除了本地服务之外,其实你一定要观察的,反而是网络服务喔!虽然网络服务默认有 SELinux 管理,不过,在鸟哥的立场上, 我还是建议非必要的网络服务就关闭他!那么什么是网络服务呢?基本上,会产生一个网络监听端口口 (port) 的程序,你就可以称他是个网络服务了! 那么如何观察网络端口口?就这样追踪啊!

[root@study ~]# netstat -tlunp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
tcp6 0 0 :::555 :::* LISTEN 29113/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1340/sshd
tcp6 0 0 ::1:25 :::* LISTEN 2387/master
udp 0 0 0.0.0.0:5353 0.0.0.0:* 750/avahi-daemon: r
udp 0 0 0.0.0.0:36540 0.0.0.0:* 750/avahi-daemon: r

如上表所示,我们的系统上至少开了 22, 25, 555, 5353, 36540 这几个埠口~而其中 5353, 36540 是由avahi-daemon 这个东西所启动的!接下来我们使用 systemctl 去观察一下,到底有没有 avahi-daemon 为开头的服务呢?

[root@study ~]# systemctl list-units --all | grep avahi-daemon
avahi-daemon.service loaded active running Avahi mDNS/DNS-SD Stack
avahi-daemon.socket loaded active running Avahi mDNS/DNS-SD Stack Activation Socket

透过追查,知道这个 avahi-daemon 的目的是在局域网络进行类似网芳的搜寻,因此这个服务可以协助你在区网内随时了解即插即用的装置! 包括笔记本电脑等,只要连上你的区网,你就能够知道谁进来了。问题是,你可能不要这个协议啊!所以,那就关闭他吧!

[root@study ~]# systemctl stop avahi-daemon.service
[root@study ~]# systemctl stop avahi-daemon.socket
[root@study ~]# systemctl disable avahi-daemon.service avahi-daemon.socket
[root@study ~]# netstat -tlunp
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
tcp6 0 0 :::555 :::* LISTEN 29113/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1340/sshd
tcp6 0 0 ::1:25 :::* LISTEN 2387/master

一般来说,你的本地服务器至少需要 25 号埠口,而 22 号埠口则最好加上防火墙来管理远程联机登入比较妥当~因此,上面的埠口中, 除了 555 是我们上一章因为测试而产生的之外,这样的系统能够被爬墙的机会已经少很多了! ^_^!OK!现在如果你的系统里面有一堆网络端口口在监听, 而你根本不知道那是干麻用的,鸟哥建议你,现在就透过上面的方式,关闭他吧!

补充说明

【Unit】区块

Description:简短描述
Documentation:文档地址,比如:http:\\www.xxx.com
Requires:当前 Unit 依赖的其他 Unit,如果它们没有运行,当前 Unit 会启动失败
Wants:与当前 Unit 配合的其他 Unit,如果它们没有运行,当前 Unit 不会启动失败
BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行
Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动
After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动
Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行
 
单位文件可能还包含许多Condition…=和 Assert…=设置。在启动设备之前,systemd将验证指定条件是否正确。如果不是,则将跳过该单元的启动(几乎无提示):
Condition...:当前 Unit 运行必须满足的条件,否则不会运行
Assert...:当前 Unit 运行必须满足的条件,否则会报启动失败

【Service】区块

Type:定义启动时的进程行为。它有以下几种值:
Type=simple:默认值,执行ExecStart指定的命令,启动主进程
Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出
Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行
Type=dbus:当前服务通过D-Bus启动
Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
Type=idle:若有其他任务执行完毕,当前服务才会运行
ExecStart:启动当前服务的命令
ExecStartPre:启动当前服务之前执行的命令
ExecStartPost:启动当前服务之后执行的命令
ExecReload:重启当前服务时执行的命令
ExecStop:停止当前服务时执行的命令
ExecStopPost:停止当其服务之后执行的命令
RestartSec:自动重启当前服务间隔的秒数
Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数

【Install】区块

Alias:当前 Unit 可用于启动的别名
WantedBy/RequiredBy:可以多次使用此选项,也可以使用空格分隔的单位名称列表;
WantedBy:它的值是一个或多个 Target,当前Unit激活时(enable)符号链接会放入/etc/systemd/system目录下面,以Target名+.wants后缀构成的子目录中。
RequiredBy:它的值是一个或多个 Target,当前Unit激活时,符号链接会放入/etc/systemd/system目录下面以Target名+.required后缀构成的子目录中
Also:当前Unit激活(enable)时,会被同时激活的其他 Unit
DefaultInstance:在模板单元文件中,这指定了如果在没有任何显式设置实例的情况下启用了模板,则应为哪个实例启用该单元。此选项在非模板单元文件中无效。指定的字符串必须可用作实例标识符。

该系列目录 --> 【BASH】回顾与知识点梳理(目录)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值