10章 服务管理

RHEL7以后,系统的守护进程从以前的init换成了现在systemd。本章中我们通过systemctl工具管理服务

8  学习目标:

熟练在RHEL7中掌握systemd

熟练在RHEL7中管理服务

掌握在RHEL7中配置服务

10.1 systemd的概述

10.1.1  什么daemon服务

RHEL7守护进程已经从RHEL6init成了systemd。systemdservice是什么提供某种网络功能,完成这个服务的功能,那就是服务。英文叫做service。我们经常会在网上看一些资料,应该常常看到“启动某某daemon来提供某种功能”,那么daemon是什么呢?

简单的说,系统为了提供某些功能必须要要提供一些服务不论是系统本身还是网络方面)这个服务称为service。但是service的提供总是需要程序来运作吧,否则如何运行呢?所以达成service运作程序我们叫做daemon。事实上,我们不必去吧daemon和service分很清楚,只要知道每个service的背后都有一个daemon能运行就好了。

10.1.2  systemd

systemd 是 Linux 下一个与 SysV 和 LSB 初始化脚本兼容的系统和服务管理器。systemd 使用 socket 和 D-Bus 来开启服务,提供基于守护进程的按需启动策略,保留了 Linux cgroups 的进程追踪功能,支持快照和系统状态恢复,维护挂载和自挂载点,实现了各服务间基于从属关系的一个更为精细的逻辑控制,拥有前卫的并行性能。RHEL7后已经不用init来管理服务了但是来绿到某些脚本没办法直接塞入systemd中,因此有一些被保留。

10.1.3  服务的分类

基本上systemd将过去所谓daemon执行脚本统统成为一个服务单元unit),而每种服务单元依据功能区分为不同的类型基本类型包括系统服务、资料的监听交换的插槽服务socket)、存储系统状态的快照类型、提供不同类型执行等级分类操作环境target)等等。这么多的类型放置在以下的目录中。

/usr/lib/systemd/system/:每个服务最主要启动脚本设定类似于以前/etc/init.d/目录。

/run/systemd/system/:系统执行过程中产生的服务脚本,这些脚本要比/usr/lib/systemd/system/

/etc/system/system/管理员依据主系统需求所建立的执行脚本,类似以前/etc/init.d/$xx之类的功能,优先级高于/run/systemd/system/

也就是说,到底系统开机会不会执行某些服务其实是看/etc/system/system/底下的设定,所以该目录底下一大堆连接文件。而实际执行的systemd启动脚本文件其实都是放在/usr/lib/systemd/system/。因此你想要修改某个服务启动设定得去/usr/lib/system/system/修改/etc/system/system/只是连接/usr/lib/systemd/system/正确的执行脚本而已。所以,我们要看服务的脚本,只需到/usr/lib/systemd/system/看。

[root@server system]# ll /usr/lib/systemd/system/

total 1180

-rw-r--r--. 1 root root  275 Jan 10  2015 abrt-ccpp.service

-rw-r--r--. 1 root root  380 Jan 10  2015 abrtd.service

-rw-r--r--. 1 root root  361 Jan 10  2015 abrt-oops.service

-rw-r--r--. 1 root root  266 Jan 10  2015 abrt-pstoreoops.service

-rw-r--r--. 1 root root  262 Jan 10  2015 abrt-vmcore.service

-rw-r--r--. 1 root root  311 Jan 10  2015 abrt-xorg.service

-rw-r--r--. 1 root root  421 Jan 30  2014 accounts-daemon.service

-rw-r--r--. 1 root root  645 Feb 17  2015 anaconda-direct.service

-rw-r--r--. 1 root root  185 Feb 17  2015 anaconda-nm-config.service

-rw-r--r--. 1 root root  660 Feb 17  2015 anaconda-noshell.service

-rw-r--r--. 1 root root  387 Feb 17  2015 anaconda.service

-rw-r--r--. 1 root root  684 Feb 17  2015 anaconda-shell@.service

-rw-r--r--. 1 root root  322 Feb 17  2015 anaconda-sshd.service

-rw-r--r--. 1 root root  312 Feb 17  2015 anaconda.target

drwxr-xr-x. 2 root root 4096 Feb 21 14:56 anaconda.target.wants

 

10.1.4  服务的类别说明

/usr/lib/systemd/system/ 以下的资料如何区分上述所谓的不同的类型 (type)

[root@server system]# ll /usr/lib/systemd/system/ | grep -E '(vsftpd|multi|cron)'

-rw-r--r--. 1 root root  284 Jul  8  2014 crond.service

-rw-r--r--. 1 root root  567 Jan 10  2015 multipathd.service

-rw-r--r--. 1 root root  524 Dec 22  2014 multi-user.target

drwxr-xr-x. 2 root root 4096 Feb 21 09:42 multi-user.target.wants

lrwxrwxrwx. 1 root root   17 Feb 21 09:41 runlevel2.target -> multi-user.target

lrwxrwxrwx. 1 root root   17 Feb 21 09:41 runlevel3.target -> multi-user.target

lrwxrwxrwx. 1 root root   17 Feb 21 09:41 runlevel4.target -> multi-user.target

我们可以知道crond其实算是系统服务multi-user要算是执行环境相关的类型根据文件的后缀名,们可以找到比较常见systemd的服务类型。

后缀名

主要服务功能

.service

一般服务类型:主要是系统服务,包括服务器本身所需要的的本机服务以及网络服务经常使用的服务大多都是这种类型。

.socket

内部程序资料交换的插槽服务:主要IPC传输讯息插槽功能。这种服务类型一般比较不会被用

.target

执行环境类型:其实是一群unit的集合

.mount

.automount

档案系统挂载相关的服务。

.path

侦测特定档案或目标类型

.timer

循环执行的服务

 

10.2  服务的管理

10.2.1  服务启动/重启、关闭与开机自动启动

(以httpd服务为例

服务的启动/关闭/重启:systemctl start/stop/restart service_name

[root@server ~]# systemctl start httpd

[root@server ~]# systemctl stop httpd

[root@server ~]# systemctl restart httpd

服务的开机自启与取消systemctl enadble/disable service_name

 [root@server ~]# systemctl enable httpd.service

ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants/httpd.service'

[root@server ~]# systemctl disable httpd.service

rm '/etc/systemd/system/multi-user.target.wants/httpd.service'

[root@server ~]#

10.2.2  服务状态的查询隔离、服务列表依赖关系

服务状态的查询:systemctl status service_name

[root@server ~]# systemctl status httpd.service

httpd.service - The Apache HTTP Server

   Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled)

   Active: active (running) since Mon 2017-02-27 18:01:57 CST; 18min ago

 Main PID: 13435 (httpd)

   Status: "Total requests: 0; Current requests/sec: 0; Current traffic:   0 B/sec"

   CGroup: /system.slice/httpd.service

           ├─13435 /usr/sbin/httpd -DFOREGROUND

           ├─13436 /usr/sbin/httpd -DFOREGROUND

           ├─13437 /usr/sbin/httpd -DFOREGROUND

           ├─13438 /usr/sbin/httpd -DFOREGROUND

           ├─13439 /usr/sbin/httpd -DFOREGROUND

           └─13440 /usr/sbin/httpd -DFOREGROUND

 

Feb 27 18:01:47 server httpd[13435]: AH00557: httpd: apr_sockaddr_info_get() failed for server

Feb 27 18:01:47 server httpd[13435]: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1. Set the 'Serv...is message

Feb 27 18:01:57 server systemd[1]: Started The Apache HTTP Server.

Hint: Some lines were ellipsized, use -l to show in full.

服务隔离与取消:systemctl mask/unmask service_name

[root@server ~]# systemctl mask httpd.service

ln -s '/dev/null' '/etc/systemd/system/httpd.service'

[root@server ~]# systemctl unmask httpd.service

rm '/etc/systemd/system/httpd.service'

服务服务列表:systemctl list-unit-files --type=service --all

[root@server ~]# systemctl list-unit-files --type=service --all

UNIT FILE                                   STATE   

abrt-ccpp.service                           enabled

abrt-oops.service                           enabled

abrt-pstoreoops.service                     disabled

abrt-vmcore.service                         enabled

abrt-xorg.service                           enabled

abrtd.service                               enabled

accounts-daemon.service                     enabled

anaconda-direct.service                     static  

anaconda-nm-config.service                  static  

anaconda-noshell.service                    static  

服务的依赖关系systemctl list-dependencies

[root@server ~]# systemctl list-dependencies

default.target

├─accounts-daemon.service

├─gdm.service

├─rhnsd.service

├─rtkit-daemon.service

├─systemd-readahead-collect.service

├─systemd-readahead-replay.service

├─systemd-update-utmp-runlevel.service

└─multi-user.target

  ├─abrt-ccpp.service

  ├─abrt-oops.service

  ├─abrt-vmcore.service

  ├─abrt-xorg.service

  ├─abrtd.service

  ├─atd.service

  ├─auditd.service

10.2.3  系统图形化或者命令行的方式启动

系统当前已什么方式启动:systemctl get-default

[root@server ~]# systemctl get-default

graphical.target #图形化

重启之后进入命令行systemctl set-default multi-user.target

[root@server ~]# systemctl set-default multi-user.target

rm '/etc/systemd/system/default.target'

ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'

进入命令行立刻生效systemctl isolate multi-user.target

[root@server ~]#  systemctl isolate multi-user.target

进入图形化立刻生效:systemctl isolate graphical.target

[root@server ~]# systemctl isolate graphical.target

10.2.4  用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 强制进入紧急救援模式

10.3  服务启动脚本的参数

10.3.1  服务启动脚本的内容

(以sshd.service为例

们知道了怎么使用服务脚本,现在了解一下的内容吧

[root@server ~]# cat /usr/lib/systemd/system/sshd.service

[Unit] #这个项目与 unit 的解释、执行服务的依赖性有关

Description=OpenSSH server daemon

After=network.target sshd-keygen.service

Wants=sshd-keygen.service

 

[Service] #这个项目与实际执行的指令参数有关

EnvironmentFile=/etc/sysconfig/sshd

ExecStart=/usr/sbin/sshd -D $OPTIONS

ExecReload=/bin/kill -HUP $MAINPID

KillMode=process

Restart=on-failure

RestartSec=42s

 

[Install] #这个项目明此unit要挂载那个 target底下

WantedBy=multi-user.target

10.3.2  脚本的结构

从上一节的例子,我们可以大概把整个脚本文件分为三个部分。

[Unit]unit的本身说明,以及其他相依daemon的设定,包括在什么服务之后才启动此unit之类的设定值。

[service][socket][timer][mount][path]:不同的unit类型就得要使用相对应的设定项目。我们拿的是sshd.service来当范本,所以这边就使用[service]来设定。这个项目内主要在规范服务的启动脚本、环境设定文件名、重新启动的方式等等。

[install]:这个项目就是将此unit安装到哪个target里面的意思。

还有一些规范需要说明的:

设定项目通常是可以重复的,例如我可以重复设定两个after在设定文件中,不过,后面的设定会代替前面的。

如果设定参数需要有/的项目(布灵值boolean)你可以使用 1, yes, true, on 代表启动,用 0, no, false, off 代表关闭

空白行、开头 # ; 的那一行,都代表注解!

10.3.3  服务启动脚本的参数

每个部份里面还有很多的设定细项,我们使用一个简单的表格来说明每个项目好了

[Unit] 部份

设定参数

参数说明

Description

就是当我们使用 systemctl list-units 时,会出給管理员多看的简易说明!当然,使用 systemctl status 输出的此服务的说明,也是这个项目

Documentation

这个项目在提供管理员能够进行下一步的文件查询的功能!提供的文件可以是如下的资料

· Documentation=http://www....

· Documentation=man:sshd(8)

· Documentation=file:/etc/ssh/sshd_config

After

输入简体字,点下面繁体说明此 unit 是在哪个 daemon 启动之后才启动的意思!基本上仅是说明服务启动的顺序而已,并没有强制要求里头的服务一定要启动后此 unit 才能启动。 以 sshd.service 的内容为例,该文件提到 After 后面有 network.target 以及 sshd-keygen.service,但是若这两个 unit 没有启动而强制启动 sshd.service 的话, 那么 sshd.service 应该还是能够启动的!这与 Requires 的设定是有差异的喔!字按钮进行在线转换

Before

After 的意义相反,是在什么服务启动前最好启动这个服务的意思。不过这仅是规范服务启动的顺序,并非强制要求的意思。

Requires

明确的定义此 unit 需要在哪个 daemon 启动后才能够启动!就是设定相依服务!如果在此项设定的前导服务没有启动,那么此 unit 就不会被启动!

Wants

Requires 刚好相反,规范的是这个 unit 之后最好还要启动什么服务比较好的意思!不过,并没有明确的规范就是了!主要的目的是希望建立让使用者比较好操作的环境。 因此,这个 Wants 后面接的服务如果没有启动,其实不会影响到这个 unit 本身!

Conflicts

代表冲突的服务!亦即这个项目后面接的服务如果有启动,那么我们这个 unit 本身就不能启动!我们 unit 有启动,则此项目后的服务就不能启动! 就是冲突性的检查。

接下来了解一下在 [Service] 当中有哪些项目可以使用!

[Service] 部份

设定参数

参数说明

Type

说明这个 daemon 启动的方式,会影响到 ExecStart!一般来说,有底下几种类型:

simple:预设值,这个 daemon 主要由 ExecStart 接的指令串来启动,启动后常驻于记录中。

forking:由 ExecStart 启动的程序透过 spawns 延伸出其他子程序来作为此 daemon 的主要服务。原生的父程序在启动结束后就会终止运作。 传统的 unit 服务大多属于这种项目,例如 httpd 这个 WWW 服务,当 httpd 的程序因为运作过久因此即将终结了,则 systemd 会再重新生出另一个子程序持续运作后, 再将父程序删除。

oneshot:与 simple 类似,不过这个程序在工作完毕后就结束了,不会常驻在记录中。

dbus:与 simple 类似,但这个 daemon 必须要在取得一个 D-Bus 的名称后,才会继续运作!因此设定这个项目时,通常也要设定 BusName= 才行!

idle:与 simple 类似,意思是,要执行这个 daemon 必须要所有的工作都顺利执行完毕后才会执行。这类的 daemon 通常是开机到最后才执行即可的服务!

比较重要的项目大概是 simple, forking oneshot 了!毕竟很多服务需要子程序 (forking),而有更多的动作只需要在开机的时候执行一次(oneshot),例如档案系统的检查与挂载啊等等的。

EnvironmentFile

可以指定启动脚本的环境设定文件!例如 sshd.service 的设定文件写入到 /etc/sysconfig/sshd 当中!你也可以使用 Environment= 后面接多个不同的 Shell 变数来给予设定!

ExecStart

就是实际执行此 daemon 的指令或脚本程式。你也可以使用 ExecStartPre (之前) 以及 ExecStartPost (之后) 两个设定项目来在实际启动服务前,进行额外的指令行为。 但是你得要特别注意的是,指令串仅接受『指令 参数 参数...』的格式,不能接受 <, >, >>, |, & 等特殊字符,很多的 bash 语法也不支援喔! 所以,要使用这些特殊的字符时,最好直接写入到指令脚本里面去!不过,上述的语法也不是完全不能用,亦即,若要支援比较完整的 bash 语法,那你得要使用 Type=oneshot 才行 其他的 Type 才不能支援这些字符。

ExecStop

systemctl stop 的执行有关,关闭此服务时所进行的指令。

ExecReload

systemctl reload 有关的指令行为

Restart

当设定 Restart=1 时,则当此 daemon 服务终止后,会再次的启动此服务。举例来说,如果你在 tty2 使用文字界面登入,操作完毕后登出,基本上,这个时候 tty2 就已经结束服务了。 但是你会看到萤幕又立刻产生一个新的 tty2 的登入画面等待你的登入!那就是 Restart 的功能!除非使用 systemctl 强制将此服务关闭,否则这个服务会源源不绝的一直重复产生!

RemainAfterExit

当设定为 RemainAfterExit=1 时,则当这个 daemon 所属的所有程序都终止之后,此服务会再尝试启动。这对于 Type=oneshot 的服务很有帮助!

TimeoutSec

若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利『正常启动或正常结束』的情况下,则我们要等多久才进入『强制结束』的状态!

KillMode

可以是 process, control-group, none 的其中一种,如果是 process daemon 终止时,只会终止主要的程序 (ExecStart 接的后面那串指令),如果是 control-group 时, 则由此 daemon 所产生的其他 control-group 的程序,也都会被关闭。如果是 none 的话,则没有程序会被关闭喔!

RestartSec

Restart 有点相关性,如果这个服务被关闭,然后需要重新启动时,大概要 sleep 多少时间再重新启动的意思。预设是 100ms (毫秒)

最后,再来看看那麽 Install 内还有哪些项目可用?

[Install] 部份

设定参数

参数说明

WantedBy

这个设定后面接的大部分是 *.target unit !意思是,这个 unit 本身是附挂在哪一个 target unit 底下的!一般来说,大多的服务性质的 unit 都是附挂在 multi-user.target 底下!

Also

当目前这个 unit 本身被 enable 时,Also 后面接的 unit 也请 enable 的意思!也就是具有相依性的服务可以写在这裡呢!

Alias

进行一个连结的别名的意思!当 systemctl enable 相关的服务时,则此服务会进行连结档的建立!以 multi-user.target 为例,这个家伙是用来作为预设操作环境 default.target 的规划, 因此当你设定用成 default.target 时,这个 /etc/systemd/system/default.target 就会连结到 /usr/lib/systemd/system/multi-user.target

 

 

10.4  做自己的服务

10.4.1  编写一个脚本

我们先编写一个脚本/backups/backup.sh位置/backups/

[root@server ~]# vim /backups/backup.sh

 

#!/bin/bash

source="/etc /home /root /var/lib /var/spool/{cron,at,mail}"

target="/backups/backup-system-$(date +%Y-%m-%d).tar.gz"

[ ! -d /backups ] && mkdir /backups

tar -zcvf ${target} ${source} &> /backups/backup.log

 

[root@server ~]# chmod a+x /backups/backup.sh

[root@server ~]# ll /backups/backup.sh

-rwxr-xr-x. 1 root root 221 Feb 27 19:13 /backups/backup.sh

10.4.2  编写一个启动脚本

接着,我们编写一个backup.service启动脚本,位置在/etc/systemd/system/

[root@server ~]# vim /etc/systemd/system/backup.service

 

[Unit]

Description=backup my server

Requires=atd.service

[Service]

Type=simple

ExecStart=/bin/bash -c " echo /backups/backup.sh | at now"

[Install]

WantedBy=multi-user.target

#因为 ExecStart 里面有用到 at 这个指令,因此, atd.service 就是一定要的服务!

 

[root@server ~]# systemctl daemon-reload

[root@server ~]# systemctl start backup.service

[root@server ~]# systemctl status backup.service

backup.service - backup my server

   Loaded: loaded (/etc/systemd/system/backup.service; disabled)

   Active: inactive (dead)

 

Feb 27 19:16:37 server systemd[1]: Starting backup my server...

Feb 27 19:16:37 server systemd[1]: Started backup my server.

Feb 27 19:16:37 server bash[2528]: job 1 at Mon Feb 27 19:16:00 2017

# 为什么 Active inactive 呢?这是因为我们的服务谨是一个简单 script

# 因此执行完毕就完毕了,不会缓存在记录

 

总结

早期的服务管理使用 systemV 的机制,透过 /etc/init.d/*, service, chkconfig, setup 等指令来管理服务的启动/关闭/预设启动;

RHEL 7.x 开始,採用 systemd 的机制,此机制最大功能为平行处理,并採单一指令管理 (systemctl),开机速度加快!

systemd 将各服务定义为 unit,而 unit 又分类为 service, socket, target, path, timer 等不同的类别,方便管理与维护

启动/关闭/重新启动的方式为: systemctl [start|stop|restart] unit.service

设定预设启动/预设不启动的方式为: systemctl [enable|disable] unit.service

查询系统所有启动的服务用 systemctl list-units --type=service 而查询所有的服务 (含不启动) 使用 systemctl list-unit-files --type=service

systemd 取消了以前的 runlevel 概念 (虽然还是有相容的 target),转而使用不同的 target 操作环境。常见操作环境为 multi-user.targer graphical.target。 不重新开机而转不同的操作环境使用 systemctl isolate unit.target,而设定预设环境则使用 systemctl set-default unit.target

systemctl 系统预设的设定档主要放在 /usr/lib/systemd/system,管理员若要修改或自行设计时,则建议放在 /etc/systemd/system/ 目录下。

管理员应使用 man systemd.unit, man systemd.service, man systemd.timer 查询 /etc/systemd/system/ 底下配置文件的语法, 并使用 systemctl daemon-reload 载入后,才能自行撰写服务与管理服务!

除了 atd crond 之外,可以 透过 systemd.timer 亦即 timers.target 的功能,来使用 systemd 的时间管理功能。

一些不需要的服务可以关闭!