一、后台任务
//www.greatytc.com/p/954550c2b528
&
先说工作任务
Ctrl+z
可以把一个前台运行的程序放在后台。
先编辑一个 a.sh
的小程序
while true
do
echo "$(date +%s) I love her" >> /root/bin/love.txt
sleep 3
done
运行这个程序
sh a.sh
此时,你会发现这个程序是卡在当前的终端的,这个就是程序在前台运行的。
这种情况下,这个程序不终止的话,当前终端就无法执行别的命令了。
此时,可以按下 Ctrl+z
把这个程序放到后台,但是,这个程序会进入 停止状态。
jobs
命令会查看到当前后台的工作任务
jobs
fg %工作号
就是可以把后台的工作任务调到前台继续运行
bg %工作号
会让后天处于停止状态的任务(进程) 继续运行于后台
bg %1
使用如下方式,可以让一个程序,在一开始运行时就在后台运行。
命令 选项 参数 &
sh a.sh &
daemon 守护进程
计算机想要提供一些功能给用户使用,需要一个程序,并把进程运行起来。
之前说过,程序运行起来就是进程了,进程都有生命周期的。
运行 等待 休眠 结束
计算机提供的某一项功能需要长期的运行,就像一个网站,你什么时间访问他,都会得到响应。
这样就需要把提供这类功能的进程长期的放在内存中,不让他结束。
这类的进程通常成为服务,那谁来管理这些进程呢?就是控制这些服务进程的启动、重启、停止。
就是叫守护进程的进程, 在 CentOS7 中是 systemd
, CentOS5/6 是 init
。
也可以说服务 service 通常都是以守护进程的方式启动的,都是在后台运行的。
早期的 System V
在一开始 那个很纯种的 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
服务启动的分类:独立启动和超级守护进程总管程序管理
服务的相依性问题
假如启动一个 HTTP 服务,那他就依赖于 网络服务,就是网络服务必须先被启动。执行等级的分类
init 是开机后核心主动调用的, 然后 init 可以根据使用者自订的执行等级 (runlevel) 来唤醒不同的服务,以进入不同的操作界面。
Linux 提供 7 个等级(0-6)
比较重要的:
- 0 关机
- 1 单用户模式(root)
- 3 带网络服务的多用户纯文本模式
- 5 图形界面
- 6 重启
使用命令 init 级别的数字
可以进入相应的运行级别
- 指定级别默认启动的服务
可以使用如下方式设置某个服务在每个运行级别是否是默认启动状态
chkconfig --list // 查看所有的服务运行级级别的状态
chkconfig --level 3 mysqld off // 设置 mysqld 服务在运行级别 3 默认不启动
chkconfig --level 3 --level 5 mysqld on // 设置 mysqld 服务在运行级别 3 和 5 中默认启动
虽然 CentOS 7 已经不使用 init 来管理服务了,不过因为考虑到某些脚本没有办法直接塞入 systemd 的处理,因此这些脚本还是被保留下来, 所以,我们在这里还是稍微介绍了一下。
CentOS7当前的 systemd
从 CentOS 7.x 以后,Red Hat 系列的 distribution(发行版本) 放弃沿用多年的 System V 开机启动服务的流程,就是前面提到的 init 启动脚本的方法, 改用 systemd 这个启动服务管理机制。
systemd 的优点
-
并行启动服务
旧的 init 启动脚本是一项一项任务依序启动的模式,因此没有依赖关系的服务也是得要一个一个的启动的。
目前我们的硬件主机系统与操作系统几乎都支持多核心架构了,所以应该支持并行启动。systemd 就是可以让所有的服务同时启动。
-
请求得到立刻回复
systemd 由于常驻内存,因此任何要求 (on-demand) 都可以立即处理后续的 daemon 启动的任务.
-
服务相依性的自我检查
例如,你部署了 FTP 服务,并且明确配置了它要依赖于 network (网络) 服务,但是你的 network 服务并没有启动,此时,你要启动 FTP 服务,systemd 会帮你启动 network 服务。
-
依 daemon 功能分类
systemd 将服务单位 (unit) 区分为 service, socket, target, path, snapshot, timer 等多种不同的类型(type), 方便系统管理员分类与记忆。
-
向下相容旧有的 init 服务脚本
基本上, systemd 是可以相容于 init 的启动脚本的,因此,旧的 init 启动脚本也能够通过 systemd 来管理,只是更进阶的 systemd 功能就没有办法支持了。
-
多个 daemons 集合成为一个群组 target
systemd 的配置文件放置目录
systemd 将过去所谓的 daemon 执行脚本通通称为一个服务单位 (unit),而每种服务单位依据功能来区分时,就分类为不同的类型 (type)。
配置文件都放在下面的路径中
-
/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/ 高!
而实际执行的 systemd
启动脚本配置文件, 其实都是放置在 /usr/lib/systemd/system/
下面。
因此如果你想要修改某个服务启动的设置,应该要去 /usr/lib/systemd/system/
下面修改才对!
systemd 的 unit 类型分类说明
一个服务执行的脚本就成为一个 unit (服务单位)
通过扩展名区分 unit 的类型
-
.service 一般服务类型 (service unit)
主要是系统服务,包括服务器本身所需要的本机服务以及网络服务都是!比较经常被使用到的服务大多是这种类型! 所以,这也是最常见的类型了!
-
.socket 内部程序数据交换的 socket 服务 (socket unit)
主要是 IPC (Inter-process communication) 的传输讯息 socket file 功能。 一般用于本机服务比较多,例如我们的图形界面很多的软件都是通过 socket 来进行本机程序数据交换的行为。
-
.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
更加有弹性!
通过 systemctl 管理服务
systemd 启动服务的机制,主要是通过 systemctl
的命令完成所有的操作。
命令语法: systemctl [command] [unit]
command 主要有:
status :查看这个 unit 的状态!
start :立刻启动
stop :立刻停止
restart :先执行 stop 再执行 start 的意思
enable :设置下次开机时,启动后面接的 unit
disable :设置下次开机时,不启动后面接的 unit
reload :不关闭后面接的 unit 的情况下,重新载入配置文件,让设置生效
示例操作
查看 atd.server 的状态
[root@shark ~]# systemctl status atd.service
● atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
Active: active (running) since 一 2019-07-29 22:41:37 CST; 46min ago
Main PID: 1162 (atd)
CGroup: /system.slice/atd.service
└─1162 /usr/sbin/atd -f
7月 29 22:41:37 shark.sharkyun.com systemd[1]: Started Job spooling tools.
7月 29 22:41:37 shark.sharkyun.com systemd[1]: Starting Job spooling tools...
关键的是第二行和第三行
第二行中的enabled
表示下次开机,会自动启动此服务。
第三行中的loaded(running)
表示目前是运行状态。
先关闭 atd.server, 在看其状态
[root@shark ~]# systemctl status atd.service
● atd.service - Job spooling tools
Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
Active: inactive (dead) since 一 2019-07-29 23:31:09 CST; 1s ago
Process: 1162 ExecStart=/usr/sbin/atd -f $OPTS (code=exited, status=0/SUCCESS)
Main PID: 1162 (code=exited, status=0/SUCCESS)
7月 29 22:41:37 shark.sharkyun.com systemd[1]: Started Job spooling tools.
7月 29 22:41:37 shark.sharkyun.com systemd[1]: Starting Job spooling tools...
7月 29 23:31:09 shark.sharkyun.com systemd[1]: Stopping Job spooling tools...
7月 29 23:31:09 shark.sharkyun.com systemd[1]: Stopped Job spooling tools.
第三行中的
inactive (dead)
表示目前没有运行
关于 Active 的状态:
- active (running):正在运行
- active (exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行。 举例来说,开机或者是挂载时才会进行一次的 quotaon 功能,就是这种模式!(无须常驻内存)。
- active (waiting):正在执行当中,不过还再等待其他的事件才能继续处理。举例来说,打印的队列相关服务就是这种状态!
- inactive:这个服务目前没有运行的意思。
关于daemon (服务) 的默认状态
- enabled:这个 daemon 将在开机时被执行
- disabled:这个 daemon 在开机时不会被执行
- mask:这个 daemon 无论如何都无法被启动!因为已经被强制注销 (非删除)。可通过 systemctl unmask 方式改回原本状态
- static:这个 daemon 不可以自己启动 (enable 不可),不过可能会被其他的 enabled 的服务来唤醒 (相依属性的服务)
强制注销
被注销的服务是服务再次启动的
别担心,可以使用unmask
取消注销
命令
systemctl status cups
输出
● cups.service
Loaded: masked (/dev/null; bad) # 注意这里
Active: inactive (dead)
取消注销
systemctl unmask cups.service
通过 systemctl 管理不同的操作环境 (target unit)
列出跟运行级别有关的 target
systemctl list-units --type=target --all
几个比较重要的 target unit
-
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 的数量,可以修改这个东西的配置文件!
查看当前模式和修改默认模式
命令语法:
systemctl [command] [unit.target]
选项与参数:
command:
get-default :查看默认的 target
set-default :设置后面接的 target 成为默认的模式
isolate :切换到后面接的模式
示例
# 获取到当前默认的启动模式
[root@shark ~]# systemctl get-default
graphical.target # 图形模式
# 设置默认启动模式为 字符模式(就是黑和白)
[root@shark ~]# systemctl set-default multi-user.target
Removed symlink /etc/systemd/system/default.target.
Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/multi-user.target.
# 再次检查当前默认的启动模式
[root@shark ~]# systemctl get-default
multi-user.target
在不重新开机的情况下,将目前的操作环境改为纯文本模式,关掉图形界面
systemctl isolate multi-user.target
系统服务和端口
head -50 /etc/services
添加自定义服务到 systemd
systemctl 配置文件的设置项目简介
先看一个 sshd.service
的实例
[root@shark ~]# cat /usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
[Service]
Type=notify
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 本身的说明,以及与其他相依 daemon 的设置,包括在什么服务之后才启动此 unit 之类的设置值;
-
[Service], [Socket], [Timer], [Mount], [Path]..
不同的 unit type 就得要使用相对应的设置项目。
我们拿的是 sshd.service 来当范本,所以这边就使用 [Service] 来设置。 这个项目内主要在规范服务启动的脚本、环境配置文件文件名、重新启动的方式等等。
-
[Install]
这个项目就是将此 unit 安装到哪个 target 里面去的意思!
示例
下面的示例是,写一个 shell 脚本,之后让 systemd 去管理这个脚本程序。
编写脚本和环境文件
在自己用户的家目录下的 bin
目录下编写脚本 love.sh
, 写入下面的内容
while true
do
echo "$(date +%s) I love her" >> /root/bin/love.txt
echo "$(date +%s) ${name} love her" >> /root/bin/love.txt
sleep 3
done
脚本的意思是
每 3 秒钟向/root/bin/love.txt
文件中写上两句话
注意${name}
是一个配置文件的中变量
编写这个脚本程序的配置文件 /root/bin/love.conf
name=shark-user
作为服务添加到 systemd
编译 /etc/
文件,添加如下内容
[Unit]
Description=Love server daemon
[Service]
Type=simple
ExecStart=/bin/bash /root/bin/love.sh
ExecStop=/bin/kill -9 $(ps -ef |grep '[a].sh' |awk '{print $2}')
EnvironmentFile=/root/bin/love.conf
[Install]
WantedBy=multi-user.target
控制服务启停
systemctl daemon-reload // 程序加载 让 systemd 加载 love.service 服务
systemctl start love.service // 启动
systemctl status love.service // 查看状态
验证程序的执行结果, 持续观察 /root/bin/love.txt
文件,看有没有被持续写入内容,并且观察变量有没有生效。
tail -f /root/bin/love.txt
输出
1564567167 I love her
1564567167 shark-user love her
1564567170 I love her
1564567170 shark-user love her
1564567173 I love her
1564567173 shark-user love her
1564567176 I love her
1564567176 shark-user love her
1564567179 I love her
1564567179 shark-user love her