# service 命令

# service 命令的使用

Linux 系统一般使用 service 命令来管理服务:

# 启动服务
service network start
# 停止服务
service network stop
# 重启服务
service network restart
# 查看服务状态
service network status

# service 原理

Linux 系统的服务实际上是在后台运行的命令,通常一个程序想要作为系统服务运行,首先需要在 /etc/init.d 目录下存放一个与服务同名的文件,例如 network 服务,查看 /etc/init.d/network 文件,其简化后内容如下:

case "$1" in
start)
    ;;
stop)
    ;;
reload)
    ;;
force-reload|restart)
    ;;
*)
    ;;
esac
exit 0

可见一个系统服务管理程序只要实现对命令行参数 start|stop|restart 等进行处理就可以被 service 命令管理,在使用 service xxx cmd 来管理服务时,其等价于执行 /etc/init.d/xxx cmd

注: /etc/init.d/xxx 文件必须具有可执行权限

# 开机自启动

# chkconfig 命令

在 /etc/init.d 下存放服务的管理文件只是可以让程序作为服务运行,一旦系统重启,就必须手动执行 service xxx start 来启动服务,大多数情况服务需要开机自启动,这时候就要用 chkconfig 命令:

# 添加启动项
chkconfig --add [command]
# 启用 / 禁用启动项
chkconfig [command] on/off

需要注意的是,要使用 chkconfig 命令,文件首行必须是:

#chkconfig: 2345 10 90

其中 2345 表示运行级别,Linux 系统有 0~6 七个运行级别 (见:Linux 运行级别)
10 表示启动优先级,数字越小优先级越高,越早被启动,取值范围 0~100
90 表示退出优先级,数字越小优先级越高,越早被退出,取值范围 0~100

# Linux 运行级别

级别 说明
0 停机,通常不用
1 单用户模式,与 Windows 系统的安全模式类似
2 多用户模式,但没有 NFS 支持
3 完全多用户模式,支持 NFS
4 一般不用,在一些特殊情况下可以用它来做一些事情。例如在笔记本电脑的电池用尽时,可以切换到这个模式来做一些设置
5 有网络支持有 X-Window 支持的多用户模式
6 重新引导系统,即重启,运行命令 init 6 就会重启系统,不建议讲服务的运行级别设置为 6

# rd*.d 目录

事实上要让服务开机自启动,只需要在 /etc/rc.d/rc*.d 目录 (Ubuntu 等系统是在 /etc/rd*.d 目录) 下根据一定规则创建 /etc/init.d 目录中服务文件的软连接即可,其中*表示运行级别,如 rc2.d 目录中表示以运行级别 2 启动。
通常在 rc*.d 目录中有两种文件:

  • 以 K 开头的文件:在系统退出时被调用
  • 以 S 开头的文件:在系统启动时被调用

这两种文件都是对 /etc/init.d/ 目录中的服务文件的软链接,K/S 后是相应服务名,与链接的服务文件一致

如果只是需要开机执行某些简单命令,可以直接在 /etc/rc.d/rc.local 文件中添加需要开机执行的命令

# Systemd

过去 Linux 系统启动是采用 init 进程的,而 init 进程是串行化的,所以启动较慢,而且 init 进程只负责执行脚本,启动脚本需要自行处理各种异常情况,导致启动脚本常常很臃肿,为了解决这些问题,RedHat 推出了 Systemd 初始化系统,其特点:

  • 系统引导时实现服务并行启动
  • 按需启动守护进程
  • 自动化的服务依赖关系管理
  • 同时采用 socket 式与 D-Bus 总线式激活服务
  • 系统状态快照和恢复
  • 利用 Linux 的 cgroups 监视进程
  • 维护挂载点和自动挂载点
  • 各服务间基于依赖关系进行精密控制

# systemctl 命令的使用

# 重启系统
sudo systemctl reboot
# 关闭系统,切断电源
sudo systemctl poweroff
# CPU 停止工作
sudo systemctl halt
# 暂停系统
sudo systemctl suspend
# 让系统进入冬眠状态
sudo systemctl hibernate
# 让系统进入交互式休眠状态
sudo systemctl hybrid-sleep
# 启动进入救援状态(单用户状态)
sudo systemctl rescue
# 服务开机自启动
sudo systemctl enable xxx
# 禁用服务开机自启动
sudo systemctl disable xxx
# 启动服务
sudo systemctl start xxx
# 停止服务
sudo systemctl start xxx
# 重启服务
sudo systemctl restart xxx
# 杀死一个服务的所有子进程
sudo systemctl kill apache.service
# 重新加载一个服务的配置文件
sudo systemctl reload apache.service
# 重载所有修改过的配置文件
sudo systemctl daemon-reload
# 显示某个 Unit 的所有底层参数
systemctl show httpd.service
# 显示某个 Unit 的指定属性的值
systemctl show -p CPUShares httpd.service
# 设置某个 Unit 的指定属性
sudo systemctl set-property httpd.service CPUShares=500

# 添加系统服务

Systemd 可以管理所有系统资源,在 Systemd 中资源被统称为 Unit。Unit 一共分为 12 种:

  • Service unit:系统服务
  • Target unit:多个 Unit 构成的一个组
  • Device Unit:硬件设备
  • Mount Unit:文件系统的挂载点
  • Automount Unit:自动挂载点
  • Path Unit:文件或路径
  • Scope Unit:不是由 Systemd 启动的外部进程
  • Slice Unit:进程组
  • Snapshot Unit:Systemd 快照,可以切回某个快照
  • Socket Unit:进程间通信的 socket
  • Swap Unit:swap 文件
  • Timer Unit:定时器

每一个 Unit 都有一个配置文件,告诉 Systemd 如何启动该 Unit。默认情况下,Systemd 从 /etc/systemd/system 读取配置文件,然而实际上该目录的文件均为 /usr/lib/systemd/system 目录中文件的软链接,systemctl enable 用于在两个目录间建立符号链接,sytemctl diable 则用于撤销链接关系。

# Unit 配置文件

以 network 服务的配置文件为例,其内容如下:

[Unit]
Description=Raise network interfaces
Documentation=man:interfaces(5)
DefaultDependencies=no
Wants=network.target
After=local-fs.target network-pre.target apparmor.service systemd-sysctl.service systemd-modules-load.service
Before=network.target shutdown.target network-online.target
Conflicts=shutdown.target
[Install]
WantedBy=multi-user.target
WantedBy=network-online.target
[Service]
Type=oneshot
EnvironmentFile=-/etc/default/networking
ExecStartPre=-/bin/sh -c '[ "$CONFIGURE_INTERFACES" != "no" ] && [ -n "$(ifquery --read-environment --list --exclude=lo)" ] && udevadm settle'
ExecStart=/sbin/ifup -a --read-environment
ExecStop=/sbin/ifdown -a --read-environment --exclude=lo
RemainAfterExit=true
TimeoutStartSec=5min

了解 ini 文件格式的话,不难发现 Unit 配置文件分为了三节 (section):

  • # Unit

[Unit] 区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。它的主要字段如下:

  • Description:简短描述

  • Documentation:文档地址

  • Requires:当前 Unit 依赖的其他 Unit, 如果它们没有运行,当前 Unit 会启动失败

  • Wants:与当前 Unit 配合的其他 Unit, 如果它们没有运行,当前 Unit 不会启动失败

  • BindsTo:与 Requires 类似,它指定的 Unit 如果退出,会导致当前 Unit 停止运行

  • Before:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之后启动

  • After:如果该字段指定的 Unit 也要启动,那么必须在当前 Unit 之前启动

  • Conflicts:这里指定的 Unit 不能与当前 Unit 同时运行

  • Condition...:当前 Unit 运行必须满足的条件,否则不会运行

  • Assert...:当前 Unit 运行必须满足的条件,否则会报启动失败

  • # Install

[Install] 通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。它的主要字段如下:

  • WantedBy:它的值是一个或多个 Target, 当前 Unit 激活时(enable)符号链接会放入 /etc/systemd/system 目录下面以 Target 名 + .wants 后缀构成的子目录中

  • RequiredBy:它的值是一个或多个 Target, 当前 Unit 激活时,符号链接会放入 /etc/systemd/system 目录下面以 Target 名 + .required 后缀构成的子目录中

  • Alias:当前 Unit 可用于启动的别名

  • Also:当前 Unit 激活(enable)时,会被同时激活的其他 Unit

  • # Service

[Service] 区块是 Service 的配置,只有 Service 类型的 Unit 才有这个区块。它的主要字段如下:

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

Unit 配置文件的完整字段清单,请参考官方文档

# Target

启动计算机的时候,需要启动大量的 Unit。如果每一次启动,都要一一写明本次启动需要哪些 Unit, 显然非常不方便。Systemd 的解决方案就是 Target。
简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于 "状态点", 启动某个 Target 就好比启动到某种状态。
传统的 init 启动模式里面,有 RunLevel 的概念,跟 Target 的作用很类似。不同的是,RunLevel 是互斥的,不可能多个 RunLevel 同时启动,但是多个 Target 可以同时启动。

# 查看当前系统的所有 Target
systemctl list-unit-files --type=target
# 查看一个 Target 包含的所有 Unit
systemctl list-dependencies multi-user.target
# 查看启动时的默认 Target
systemctl get-default
# 设置启动时的默认 Target
sudo systemctl set-default multi-user.target
# 切换 Target 时,默认不关闭前一个 Target 启动的进程,
# systemctl isolate 命令改变这种行为,
# 关闭前一个 Target 里面所有不属于后一个 Target 的进程
sudo systemctl isolate multi-user.target

Target 与 传统 RunLevel 的对应关系如下。

Traditional runlevel New target name Symbolically linked to...
0 runlevel0.target poweroff.target
1 runlevel1.target rescue.target
2 runlevel2.target multi-user.target
3 runlevel3.target multi-user.target
4 runlevel4.target multi-user.target
5 runlevel5.target graphical.target
6 runlevel6.target reboot.target

它与 init 进程的主要差别如下:

  1. 默认的 RunLevel (在 /etc/inittab 文件设置) 现在被默认的 Target 取代,位置是 /etc/systemd/system/default.target, 通常符号链接到 graphical.target (图形界面) 或者 multi-user.target (多用户命令行)。
  2. 启动脚本的位置,以前是 /etc/init.d 目录,符号链接到不同的 RunLevel 目录 (比如 /etc/rc3.d、/etc/rc5.d 等), 现在则存放在 /lib/systemd/system 和 /etc/systemd/system 目录。
  3. 配置文件的位置,以前 init 进程的配置文件是 /etc/inittab, 各种服务的配置文件存放在 /etc/sysconfig 目录。现在的配置文件主要存放在 /lib/systemd 目录,在 /etc/systemd 目录里面的修改可以覆盖原始设置。

# 例子

假设当前在 /opt 目录下有可执行程序 demo, 其用于定时从 Wallpaper 网站抓取一张壁纸并替换当前壁纸,我们想要开机自动执行它,首先在 /usr/lib/systemd/system/ 目录创建 demo.service 文件,根据上面的说明,其内容如下:

[Unit]
Description=demo service
# 强依赖网络服务
Requires=network-online.target
BindsTo=network.target
After=network.target
[Install]
[Service]
Type=simple
ExecStart=/opt/demo
ExecStart=/usr/bin/kill -9 $(/usr/bin/ps aux | grep demo | awk '{print $2}') && /opt/demo
EXECStop=/usr/bin/kill -9 $(/usr/bin/ps aux | grep demo | awk '{print $2}')
Restart=on-failure

写好 demo.service 文件后,需要执行 systemctl daemon-reload 命令来重新加载所有配置文件,然后执行 systemctl enable demo 命令,这样下次开机时 demo 程序就会自动执行。

此文章已被阅读次数:正在加载...更新于

请我喝[茶]~( ̄▽ ̄)~*

Linsan Zhu 微信支付

微信支付

Linsan Zhu 支付宝

支付宝