第10章 服务管理
在RHEL7以后,系统的守护进程从以前的init换成了现在的systemd。本章中我们通过systemctl工具来管理服务。
8 学习目标:
l 熟练在RHEL7中掌握systemd
l 熟练在RHEL7中管理服务
l 掌握在RHEL7中配置服务
10.1 systemd的概述
10.1.1 什么是daemon和服务
在RHEL7,守护进程已经从RHEL6的init换成了systemd。而systemd和service是什么呢?提供某种网络功能,完成这个服务的功能,那就是服务。英文叫做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)等等。而这么多的类型放置在以下的目录中。
l /usr/lib/systemd/system/:每个服务最主要的启动脚本设定,类似于以前/etc/init.d/目录。
l /run/systemd/system/:系统执行过程中所产生的服务脚本,这些脚本要比/usr/lib/systemd/system/高。
l /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服务为例)
l 服务的启动/关闭/重启:systemctl start/stop/restart service_name
[root@server ~]# systemctl start httpd
[root@server ~]# systemctl stop httpd
[root@server ~]# systemctl restart httpd
l 服务的开机自启与取消: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 服务状态的查询、隔离、服务列表与依赖关系
l 服务状态的查询: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.
l 服务的隔离与取消: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'
l 服务的服务列表: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
…
l 服务的依赖关系: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 系统已图形化或者命令行的方式启动
l 系统当前已什么方式启动:systemctl get-default
[root@server ~]# systemctl get-default
graphical.target #图形化
l 重启之后进入命令行: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'
l 进入命令行立刻生效:systemctl isolate multi-user.target
[root@server ~]# systemctl isolate multi-user.target
l 进入图形化立刻生效: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 脚本的结构
从上一节的例子,我们可以大概把整个脚本文件分为三个部分。
l [Unit]:unit的本身说明,以及其他相依daemon的设定,包括在什么服务之后才启动此unit之类的设定值。
l [service]、[socket]、[timer]、[mount]、[path]:不同的unit类型就得要使用相对应的设定项目。我们拿的是sshd.service来当范本,所以这边就使用[service]来设定。这个项目内主要在规范服务的启动脚本、环境设定文件名、重新启动的方式等等。
l [install]:这个项目就是将此unit安装到哪个target里面的意思。
还有一些规范需要说明的:
l 设定项目通常是可以重复的,例如我可以重复设定两个after在设定文件中,不过,后面的设定会代替前面的。
l 如果设定参数需要有“是/否”的项目(布灵值,boolean)你可以使用 1, yes, true, on 代表启动,用 0, no, false, off 代表关闭
l 空白行、开头为 # 或 ; 的那一行,都代表注解!
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!一般来说,有底下几种类型: l simple:预设值,这个 daemon 主要由 ExecStart 接的指令串来启动,启动后常驻于记录中。 l forking:由 ExecStart 启动的程序透过 spawns 延伸出其他子程序来作为此 daemon 的主要服务。原生的父程序在启动结束后就会终止运作。 传统的 unit 服务大多属于这种项目,例如 httpd 这个 WWW 服务,当 httpd 的程序因为运作过久因此即将终结了,则 systemd 会再重新生出另一个子程序持续运作后, 再将父程序删除。 l oneshot:与 simple 类似,不过这个程序在工作完毕后就结束了,不会常驻在记录中。 l dbus:与 simple 类似,但这个 daemon 必须要在取得一个 D-Bus 的名称后,才会继续运作!因此设定这个项目时,通常也要设定 BusName= 才行! l 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
# 因此执行完毕就完毕了,不会缓存在记录中!
总结
l 早期的服务管理使用 systemV 的机制,透过 /etc/init.d/*, service, chkconfig, setup 等指令来管理服务的启动/关闭/预设启动;
l 从 RHEL 7.x 开始,採用 systemd 的机制,此机制最大功能为平行处理,并採单一指令管理 (systemctl),开机速度加快!
l systemd 将各服务定义为 unit,而 unit 又分类为 service, socket, target, path, timer 等不同的类别,方便管理与维护
l 启动/关闭/重新启动的方式为: systemctl [start|stop|restart] unit.service
l 设定预设启动/预设不启动的方式为: systemctl [enable|disable] unit.service
l 查询系统所有启动的服务用 systemctl list-units --type=service 而查询所有的服务 (含不启动) 使用 systemctl list-unit-files --type=service
l systemd 取消了以前的 runlevel 概念 (虽然还是有相容的 target),转而使用不同的 target 操作环境。常见操作环境为 multi-user.targer 与 graphical.target。 不重新开机而转不同的操作环境使用 systemctl isolate unit.target,而设定预设环境则使用 systemctl set-default unit.target
l systemctl 系统预设的设定档主要放在 /usr/lib/systemd/system,管理员若要修改或自行设计时,则建议放在 /etc/systemd/system/ 目录下。
l 管理员应使用 man systemd.unit, man systemd.service, man systemd.timer 查询 /etc/systemd/system/ 底下配置文件的语法, 并使用 systemctl daemon-reload 载入后,才能自行撰写服务与管理服务!
l 除了 atd 与 crond 之外,可以 透过 systemd.timer 亦即 timers.target 的功能,来使用 systemd 的时间管理功能。
l 一些不需要的服务可以关闭!