A daemon, or system service, is a background process usually started during the boot sequence. Daemons typically run independent of users, waiting for events to occur and providing services in response. source1
A “Service” could refer to either a Daemon or a Service. A daemon is a subset of services that always run in memory waiting to service a request. A non-daemon service generally is handled by xinetd (eXtended InterNET services daemon). xinetd listens for the request, then starts the required service to handle the request. After the request has been serviced the service is then stopped again. source2
Typical non-daemon services: rsync vsftpd
Typical daemonized services: MySQL Apache
然而对于一般的Linux使用者来说,并不需要区分daemon与service。
systemd即为system daemon,是linux下的一种init软件,开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销的效果,最终代替常用的System V与BSD风格init程序。source3
从CentOS 7.x以后,红帽系列的distribution放弃了沿用多年的System V开机启动服务的流程,改用systemd的启动服务管理机制。systemd包括常驻内存的systemd服务与systemctl指令。与System V的init启动脚本相比,其好处在于:
systemd的配置文件目录
systemd将以前的daemon执行脚本通称为一个服务单位(unit)。每种服务单位依据功能来区分时,可以分为不同的类型(type)。基本的类型有系统服务、数据监听与交换的套接字服务(socket)、存储系统状态的快照(snapshot)、提供不同类似执行等级分类的操作环境(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
中的设置,但实际中该目录下都是一些链接文件,实际执行的脚本都在/usr/lib/systemd/system
目录下。
systemd的unit类型分类说明
通过文件扩展名可以区分/usr/lib/systemd/system/
目录下不同服务的类型。
扩展名 | 主要服务功能 |
---|---|
.service | 一般服务类型,主要是系统服务,包括服务器本身所需要的本地服务以及网络服务,也是最常见的类型 |
.socket | 内部程序数据交换的套接字服务,可以看作是为不同进程间提供双向通信功能(Inter-process communication)的端点 |
.target | 执行环境类型,其实是一群服务单元的集合,执行.target就是执行集合中包含的一堆.service和.socket等服务 |
.mount .automount |
文件系统挂载相关的服务,例如来自网络的自动挂载、NFS文件系统挂载等等 |
.path | 侦测特定文件或目录类型,比如打印服务就需要侦测打印队列目录来启动打印功能 |
.timer | 循环执行的服务,功能与anacrontab类似,但是更加灵活 |
相比System V的service, chkconfig, setup, init指令,systemd仅依赖systemctl一个指令来管理服务。
通过systemctl管理单一服务的启动、开机启动的指令格式为systemctl [command] [unit]
。其中,command主要有:
需要注意的是,不要使用kill指令关闭服务,否则systemctl会无法继续监控该服务。systemctl status
的输出中,常见的服务状态有:
systemctl unmask
指令改回原来的状态。通过systemctl查看系统上所有服务的指令格式为systemctl [command] [--type=TYPE] [--all]
。其中,command有
--all
才会列出未启动的服务;/usr/lib/systemd/system/
内的文件,将所有文件列表说明。--type=TYPE
即是指服务单元的类型,包括service, socket, target等等。
列出与操作界面有关的target的指令为systemctl list-units --type=target --all
。CentOS 7中与操作界面相关性较高的主要有
查看与修改操作界面相关的target的指令格式为systemctl [command] [unit.target]
。其中,command包括
systemctl也提供了其他指令来切换操作模式。
[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
[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分析服务之间依赖性的指令为systemctl list-dependencies [unit] [--reverse]
。其中--reverse
表示反向追踪谁在使用该服务单元。
除了之前提到的systemd配置文件目录以外,与系统服务运行有关的目录还包括:
/usr/lib/systemd/system/
/run/systemd/system/
/etc/systemd/system/
/etc/sysconfig/*
:几乎所有服务都会将初始化的一些选项设定写入该目录下;/var/lib/
:一些会产生数据的服务会将数据写入到该目录下;/run/
:该目录下存放了很多系统服务的暂存文件,包括lock file和PID file。/etc/services
中设置了网络服务、对应的网路协议(tcp、udp)与端口。一般不建议通过该文件来直接修改服务的端口号。使用netstat
指令也可以查看打开的端口。如果有不需要开启的网络服务,可以使用systemctl stop
指令关闭服务(及其使用的端口)。
以vsftpd服务为例,其对应的配置文件包括:
/usr/lib/systemd/system/vsftpd.service
:官方释出的预设配置文件,建议不要修改;/etc/systemd/system/vsftpd.service.d/custom.conf
:该文件中的设定会被累加到/usr/lib/systemd/system/vsftpd.service
文件中;/etc/systemd/system/vsftpd.service.wants/*
:依赖文件的链接,wants表示在vsftpd.service启动之后才能启动的其它服务;/etc/systemd/system/vsftpd.service.requires/*
:依赖文件的链接,requires表示在启动vsftpd.service之前需要先启动的其它服务。以sshd服务为例,其配置文件sshd.service的内容如下:
[root@study ~]$ cat /usr/lib/systemd/system/sshd.service
[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]
WantedBy=multi-user.target
注意到,该配置文件内容被分为了三个部分:
此外,有几个重要的设定规则如下:
[Unit]部分常见的设定参数如下:
[Unit]参数 | 意义 |
---|---|
Description | 使用systemctl list-units 时会输出的简单说明 |
Documentation | 提供进一步的文件查询功能,可以是如下内容: Documentation=http://www…, Documentation=man:sshd(8), 或Documentation=file:/etc/ssh/sshd_config |
After | 说明此Unit在哪些服务启动之后才会启动。仅说明服务的启动顺序,并不是实际上的强制设定(与Requires不同) |
Before | 与After刚好相反,但也仅仅是说明启动顺序 |
Requires | 明确定义此Unit必须在哪些服务启动后才能启动。如果后面接的服务没有启动,该Unit就不会被启动 |
Wants | 与Requires刚好相反,定义最好在该Unit启动之后再启动的其他服务。如果后面接的服务没有启动,不会影响到该Unit本身 |
Conflicts | 冲突的服务,即不能与该Unit同时运行的其它服务 |
[Service]部分常见的设定参数如下:
[Service]参数 | 意义 |
---|---|
Type | 该服务启动的方式,会影响到ExecStart。可以分为: simple,默认值,邮ExecStart启动,且启动后常驻内存; forking,由ExecStart启动的程序通过spawns延伸出其他子程序来作为此服务的主要服务,其原生的父程序在启动结束后就会终止运行;oneshot,与simple类似,但该程序在工作完成后就会结束,不会常驻在内存中; dbus,与simple类似,但此服务必须在取得一个D-Bus名称后才会继续运行;idle,与simple类似,但是必须要等到所有工作都顺利执行完毕后该服务才会执行,通常是开机过程中最后执行的服务。 |
EnvironmentFile | 指定启动脚本的环境配置文件 |
ExecStart | 实际执行此服务的指令或脚本,与systemctl start有关 |
ExecStop | 关闭此服务时所执行的指令或脚本,与systemctl stop有关 |
ExecReload | 重载配置文件,与systemctl reload有关 |
Restart | 设定为1时,当此服务终止后,会自动再次启动该服务 |
RemainAfterExit | 设定为1时,当此服务所属的所有程序都终止以后,此服务会自动尝试启动 |
TimeoutSec | 此服务出现无法正常启动或关闭时,在进入强制结束状态前需要等待的时间 |
KillMode | 可以是以下三种模式中的一种: process,此服务终止时,只会停止主要的程序(ExecStart中的指令); control-group,由该服务产生的其他control-group程序也都会被关闭; none,没有程序会被关闭 |
RestartSec | 此服务被关闭后需要重启时,重启前需要等待的时间,预设为100ms |
[Install]部分常见的设定参数如下:
[Install]参数 | 意义 |
---|---|
WantedBy | 后面接的大部分是*.target unit,表示该服务附挂在哪一个tagrget unit底下。一般是multi-user.target |
Also | 当目前该服务被设定为开机自启(enabled)时,后面接的服务也会被enable,通常是具有依赖性的其它服务 |
Alias | 设定别名 |
假设我们要创建一个备份服务。
# 创建备份脚本
[root@study ~]$ vim /backups/backup.sh
#! /bin/bash
source="/etc /home /root /var/lib /var/spool/{cron.at.mail}"
target="/backups/backup-system-$(data +%Y-%m-%d).tar.gz"
[ ! -d /backups ] && mkdir /backups
tar -zcvf ${target} ${source} &> /backups/backup.log
[root@study ~]$ chmod a+x /backups/backup.sh
# 创建服务配置文件
[root@study ~]$ vim /etc/systemd/system/backup.service
[Unit]
Description=backup my server
Requires=atd.service # 因为用到了at指令
[Service]
Type=simple
ExecStart=/bin/bash -c " echo /backups/backup.sh | at now"
[Install]
WantedBy=multi-user.target
[root@study ~]$ systemctl daemon-reload # 重载服务配置文件
[root@study ~]$ systemctl start backup.service # 运行一次备份服务
[root@study ~]$ systemctl status backup.service
backup.service - backup my server
Loaded: loaded (/etc/systemd/system/backup.service; disabled)
Acitve: inactive (dead) # 备份服务执行完就停止了,并不会常驻内存
假设上面创建的backup.service服务需要定期执行,可以使用systemd的timer来处理。要使用timer功能,必须具备以下条件:
.timer文件的参数设定
可以在/etc/systemd/system/
下建立timer文件,其基本参数包括:
OnCalendar时间格式
基本的时间格式为“星期几 YYYY-MM-DD HH:MM:SS”,例如Thu 2020-12-25 14:30:00
。
也可以使用时间间隔,包括毫秒ms、秒s、分钟m、小时h、天数d、周数w、月month(s)、年y。比如,隔5天12小时30分钟可以表示为30m 12h 5d
,或者30min 12hours 5day
。
还可以使用口语化的时间表达方式,包括now、today、tomorrow、hourly、daily、weekly、monthly、+3h10m、2020-12-30等。
假设我们需要前面创建的备份服务backup.service每周日凌晨2点运行一次,创建对应的timer文件如下。
[root@study ~]$ vim /etc/systemd/system/backup.timer
[Unit]
Description=backup my server timer
[Timer]
OnCalendar=Sun *-*-* 02:00:00
Persistent=true
Unit=backup.service
[Install]
WantedBy=multi-user.target
[root@study ~]$ systemctl daemon-reload # 重载服务配置文件
[root@study ~]$ systemctl enable backup.timer
[root@study ~]$ systemctl start backup.timer
[root@study ~]$ systemctl show backup.timer
NextElapseUSecRealtime=50y 11month 3w 6d 23h 59min ## 下一次执行需要等待的时间,与1970-01-01 00:00:00比较