systemctl 命令完全指南&基本使用方法
一、前言
最近在做一些服务的时候发现systemctl真的是很有用的东西,使用这个机制可以帮我们解决很多问题,现在把systemctl这个机制梳理一遍,整理相关常用命令。
二、systemd和systemctl
我们提到systemctl就一定需要知道systemd,因为Linux 服务管理有两种方式service和systemctl。而systemd是Linux系统最新的初始化系统(init),作用是提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动,systemd对应的进程管理命令就是systemctl。值得一提的是,systemctl命令兼容了service。
历史上,Linux 的启动一直采用init进程。使用 sudo /etc/init.d/apache2 start
或者 service apache2 start
命令用来启动服务,这种方法有两个缺点。
- 一是启动时间长。init进程是串行启动,只有前一个进程启动完,才会启动下一个进程。
- 二是启动脚本复杂。init进程只是执行启动脚本,不管其他事情。脚本需要自己处理各种情况,这往往使得脚本变得很长。
Systemd 就是为了解决这些问题而诞生的。它的设计目标是,为系统的启动和管理提供一套完整的解决方案。
根据 Linux 惯例,字母d是守护进程(daemon)的缩写。 Systemd 这个名字的含义,就是它要守护整个系统。
使用了 Systemd,就不需要再用init了。Systemd 取代了initd,成为系统的第一个进程(PID 等于 1),其他进程都是它的子进程。
#检查你的系统中是否安装有systemd并确定当前安装的版本
systemctl --version
三、systemd的配置文件目录
/usr/lib/systemd/system/
:每个服务最主要的启动脚本的配置放在这,有点类似以前的/etc/init.d
;/run/systemd/system/
:系统执行过程中所产生的服务脚本所在目录,这些脚本的优先级要比/usr/lib/systemd/system/
高;/etc/systemd/system/
:管理员根据主机系统的需求所创建的执行脚本所在目录,执行优先级比/run/systemd/system/
高;
从上面的功能及优先级次序,我们可以知道,/etc/systemd/system/
目录下的相关配置,决定系统了会不会执行某些服务,所以该目录下面一般放着一大堆链接文件。而/usr/lib/systemd/system/下,则放着实际执行的systemd启动脚本配置文件。因此如果你想要修改某个服务启动的设置,应该去 /usr/lib/systemd/system/
下面修改。/etc/systemd/system/
仅是链接到正确的执行脚本配置文件而已。所以想要看执行脚本设置,应该就得要到 /usr/lib/systemd/system/
去查阅。
四、主要服务功能类型
- .service:一般服务类型(service unit):主要是系统服务,包括服务器本身所需要的本机服务以及网络服务,比较经常被使用到的服务大多是这种类型,所以,这也是最常见的类型。
- .socket:内部程序数据交换的插槽服务(socketunit):主要是IPC(Inter-processcommunication)的传输信息插槽(socketfile)功能。这种类型的服务通常在监控信息传递的插槽档,当有通过此插槽传递信息请求链接服务的时候,就依据当时的状态将该用户的请求传送到对应的daemon,若daemon尚未启动,则启动该daemon后再传送用户的请求。使用socket类型的服务一般是比较不会被用到的服务,因此在开机时通常会稍微延迟启动的时间。一般用于本机服务比较多,例如我们的图形界面很多的软件都是通过socket来进行本机程序数据交换的行为。
- .target:执行环境类型(target unit):其实是一群unit的集合,例如multi-user.target其实就是一堆服务的集合。
- .mount:文件系统挂载相关的服务(automount unit/mount unit):例如来自网络的自动挂载、NFS文件系统挂载等与文件系统相关性较高的程序管理。
- .path:监测特定文件或目录类型(path unit):某些服务需要监测某些特定的目录来提供序列服务,例如最常见的打印服务,就是通过监测打印序列目录来启动打印功能。这时就得要.path的服务类型支持。
- .timer:循环执行的服务(timer unit):这个东西有点类似anacrontab,不过是由systemd主动提供的,比anacrontab更加有弹性。
五、服务状态
这里我们可以先试用下面这个指令查看一下atd服务的当前状态,指令和结果如下:
#防火墙状态
systemctl status firewalld
那个高亮就是当前服务的状态。服务有哪几种常见的状态呢,这里列举说明一下:
- active(running):正有一只或多只程序正在系统中执行的意思;
- active(exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行;
- active(waiting):正在执行当中,不过还需要等待其他的事件才能继续处理;
- inactive:这个服务目前没有运行;
- dead:程序已经清除;
上面是运行结果中,我圈出了一个地方,那个其实是这只服务程序的启动状态,也分为一下几种状态。
- enabled:这个daemon将在开机时被执行;
- disabled:这个daemon在开机时不会被执行;
- static:这个daemon不可以自己启动(enable不可),不过可能会被其他的enabled 的服务来唤醒(关联属性的服务);
- mask:这个daemon无论如何都无法被启动,因为已经被强制注销(非删除),可通过systemctlunmask方式改回原本状态;
六、系统管理
Systemd 并不是一个命令,而是一组命令,涉及到系统管理的方方面面。
6.1 systemctl
systemctl
是 Systemd 的主命令,用于管理系统。
# 重启系统
sudo systemctl reboot
# 关闭系统,切断电源
sudo systemctl poweroff
# CPU停止工作
sudo systemctl halt
# 暂停系统
sudo systemctl suspend
# 让系统进入冬眠状态
sudo systemctl hibernate
# 让系统进入交互式休眠状态
sudo systemctl hybrid-sleep
# 启动进入救援状态(单用户状态)
sudo systemctl rescue
# 获取当前某个服务的CPU分配额(如httpd)
systemctl show -p CPUShares httpd.service
#将某个服务(httpd.service)的CPU分配份额限制为2000 CPUShares/
systemctl set-property httpd.service CPUShares=2000
systemctl show -p CPUShares httpd.service
#注意:当你为某个服务设置CPUShares,会自动创建一个以服务名命名的目录(如 httpd.service),里面包含了一个名为90-CPUShares.conf的文件,该文件含有CPUShare限制信息,你可以通过以下方式查看该文件:
vi /etc/systemd/system/httpd.service.d/90-CPUShares.conf
6.2 systemd-analyze
systemd-analyze
命令用于查看启动耗时。
# 查看启动耗时
systemd-analyze
# 查看每个服务的启动耗时
systemd-analyze blame
# 显示瀑布状的启动过程流
systemd-analyze critical-chain
# 显示指定服务的启动流
systemd-analyze critical-chain atd.service
6.3 hostnamectl
hostnamectl
命令用于查看当前主机的信息。
# 显示当前主机的信息
hostnamectl
# 设置主机名。
sudo hostnamectl set-hostname rhel7
6.4 localectl
localectl
命令用于查看本地化设置。
# 查看本地化设置
localectl
# 设置本地化参数。
sudo localectl set-locale LANG=en_GB.utf8
sudo localectl set-keymap en_GB
6.5 timedatectl
timedatectl
命令用于查看当前时区设置。
# 查看当前时区设置
timedatectl
# 显示所有可用的时区
timedatectl list-timezones
# 设置当前时区
sudo timedatectl set-timezone America/New_York
sudo timedatectl set-time YYYY-MM-DD
sudo timedatectl set-time HH:MM:SS
6.6 loginctl
loginctl
命令用于查看当前登录的用户。
# 列出当前session
loginctl list-sessions
# 列出当前登录用户
loginctl list-users
# 列出显示指定用户的信息
loginctl show-user ruanyf
七、Unit
7.1 含义
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
systemctl list-units
# 列出所有Unit,包括没有找到配置文件的或者启动失败的
systemctl list-units --all
# 列出所有没有运行的 Unit
systemctl list-units --all --state=inactive
# 列出所有加载失败的 Unit
systemctl list-units --failed
# 列出所有正在运行的、类型为 service 的 Unit
systemctl list-units --type=service
7.2 Unit 的状态
systemctl status
命令用于查看系统状态和单个 Unit 的状态。
# 显示系统状态
systemctl status
# 显示单个 Unit 的状态
sysystemctl status bluetooth.service
# 显示远程主机的某个 Unit 的状态
systemctl -H root@rhel7.example.com status httpd.service
除了status
命令,systemctl
还提供了三个查询状态的简单方法,主要供脚本内部的判断语句使用。
# 显示某个 Unit 是否正在运行
systemctl is-active application.service
# 显示某个 Unit 是否处于启动失败状态
systemctl is-failed application.service
# 显示某个 Unit 服务是否建立了启动链接
systemctl is-enabled application.service
7.3 Unit 管理
对于用户来说,最常用的是下面这些命令,用于启动和停止 Unit(主要是 service)。
# 立即启动一个服务
sudo systemctl start apache.service
# 立即停止一个服务
sudo systemctl stop apache.service
# 重启一个服务
sudo systemctl restart apache.service
# 杀死一个服务的所有子进程
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
#激活服务并在启动时启用或禁用服务(即系统启动时自动启动服务)
systemctl is-active httpd.service #激活
systemctl enable httpd.service #自启
systemctl disable httpd.service #禁用
7.4 依赖关系
Unit 之间存在依赖关系:A 依赖于 B,就意味着 Systemd 在启动 A 的时候,同时会去启动 B。
systemctl list-dependencies
命令列出一个 Unit 的所有依赖。
systemctl list-dependencies nginx.service
上面命令的输出结果之中,有些依赖是 Target 类型(详见下文),默认不会展开显示。如果要展开 Target,就需要使用--all
参数。
systemctl list-dependencies --all nginx.service
八、Unit 的配置文件
8.1 概述
每一个 Unit 都有一个配置文件,告诉 Systemd 怎么启动这个 Unit 。
Systemd 默认从目录/etc/systemd/system/
读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录/usr/lib/systemd/system/
,真正的配置文件存放在那个目录。
systemctl enable
命令用于在上面两个目录之间,建立符号链接关系。
如果配置文件里面设置了开机启动,systemctl enable
命令相当于激活开机启动。
与之对应的,systemctl disable
命令用于在两个目录之间,撤销符号链接关系,相当于撤销开机启动。
sudo systemctl enable clamd@scan.service
# 等同于
sudo ln -s '/usr/lib/systemd/system/clamd@scan.service' '/etc/systemd/system/multi-user.target.wants/clamd@scan.service'
sudo systemctl disable clamd@scan.service
配置文件的后缀名,就是该 Unit 的种类,比如sshd.socket
。如果省略,Systemd 默认后缀名为.service
,所以sshd
会被理解成sshd.service
8.2 配置文件的状态
systemctl list-unit-files
命令用于列出所有配置文件。
# 列出所有配置文件
systemctl list-unit-files
# 列出指定类型的配置文件
systemctl list-unit-files --type=service
这个命令会输出一个列表,这个列表显示每个配置文件的状态,一共有四种。
- enabled:已建立启动链接
- disabled:没建立启动链接
- static:该配置文件没有
[Install]
部分(无法执行),只能作为其他配置文件的依赖 - masked:该配置文件被禁止建立启动链接
注意,从配置文件的状态无法看出,该 Unit 是否正在运行。这必须执行前面提到的systemctl status
命令。
systemctl status bluetooth.service
一旦修改配置文件,就要让 SystemD 重新加载配置文件,然后重新启动,否则修改不会生效。
sudo systemctl daemon-reload
sudo systemctl restart httpd.service
8.3 配置文件格式
配置文件就是普通的文本文件,可以用文本编辑器打开。
systemctl cat
命令可以查看配置文件的内容。
[Unit]
Description=ATD daemon
[Service]
Type=forking
ExecStart=/usr/bin/atd
[Install]
WantedBy=multi-user.target
从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,是用方括号表示的区别名,比如[Unit]。注意,配置文件的区块名和字段名,都是大小写敏感的。
每个区块内部是一些等号连接的键值对,键值对的等号两侧不能有空格。
8.4 配置文件的区块
[Unit]
区块通常是配置文件的第一个区块,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系。[Install]
通常是配置文件的最后一个区块,用来定义如何启动,以及是否开机启动。[Service]
区块用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。
[Unit]
- Description,服务的描述
- Documentation,文档介绍
- After,该服务要在什么服务启动之后启动,比如Mysql需要在network和syslog启动之后再启动
[Install]
- WantedBy,值是一个或多个Target,当前Unit激活时(enable)符号链接会放入/etc/systemd/system目录下面以Target名+.wants后缀构成的子目录中
- RequiredBy,它的值是一个或多个Target,当前Unit激活(enable)时,符号链接会放入/etc/systemd/system目录下面以Target名+.required后缀构成的子目录中
- Alias,当前Unit可用于启动的别名
- Also,当前Unit激活(enable)时,会被同时激活的其他Unit
[Service]
- Type,定义启动时的进程行为。它有以下几种值。
- Type=simple,默认值,执行ExecStart指定的命令,启动主进程
- Type=forking,以 fork 方式从父进程创建子进程,创建后父进程会立即退出
- Type=oneshot,一次性进程,Systemd 会等当前服务退出,再继续往下执行
- Type=dbus,当前服务通过D-Bus启动
- Type=notify,当前服务启动完毕,会通知Systemd,再继续往下执行
- Type=idle,若有其他任务执行完毕,当前服务才会运行
- ExecStart,启动当前服务的命令
- ExecStartPre,启动当前服务之前执行的命令
- ExecStartPost,启动当前服务之后执行的命令
- ExecReload,重启当前服务时执行的命令
- ExecStop,停止当前服务时执行的命令
- ExecStopPost,停止当其服务之后执行的命令
- RestartSec,自动重启当前服务间隔的秒数
- Restart,定义何种情况 Systemd 会自动重启当前服务,可能的值包括always(总是重启)、on-success、on-failure、on-abnormal、on-abort、on-watchdog
- TimeoutSec,定义 Systemd 停止当前服务之前等待的秒数
- Environment,指定环境变量
Unit 配置文件的完整字段清单,请参考官方文档。
8.5 创建配置文件
如果我们要创建一个Unit服务,我们应该如何创建配置文件呢?
我们自己配置Unit服务(后续使用Systemctl进行启动和管理),可以配置到:
/usr/lib/systemd/system/
:推荐地址。/run/systemd/system/
:系统执行过程中所产生的服务脚本,这些脚本的优先级比上面的高。/etc/systemd/system/
:管理员根据主机系统的需求所建立的执行脚本,优先级比上面的高。
虽然,我推荐配置到/usr/lib/systemd/system/,但是还是要更加实际开发过程中遇到的情况做出改变
举例,创建一个nginx的Unit服务,所以我这里创建一个:
#创建
touch /usr/lib/systemd/system/nginx.service
#编辑
vi /usr/lib/systemd/system/nginx.service
[Unit]
Description=nginx
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/usr/local/nginx/sbin/nginx -s quit
PrivateTmp=true
[Install]
WantedBy=multi-user.target
8.5.1 Demo:Aria2交互
我们有时候会使用Aria2进行任务的下载。所以Linux服务器上会启动一个Aria2 RPC交互,怎么设置个开机自启或者后台运行
[Unit]
Description=Aria2
After=network.target
[Service]
User=root
Type=simple
ExecStart=/etc/aria2/aria2c --conf-path=/etc/aria2/aria2.conf
[Install]
WantedBy=multi-user.target
其中:
After
:在网络启动后运行。Type
:使用simple
,即使ExecStart启动不成功,Unit任务也会继续执行。ExecStart
: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...
Runlevel 0 | runlevel0.target -> poweroff.target
Runlevel 1 | runlevel1.target -> rescue.target
Runlevel 2 | runlevel2.target -> multi-user.target
Runlevel 3 | runlevel3.target -> multi-user.target
Runlevel 4 | runlevel4.target -> multi-user.target
Runlevel 5 | runlevel5.target -> graphical.target
Runlevel 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
目录里面的修改可以覆盖原始设置。
十、日志管理
Systemd 统一管理所有 Unit 的启动日志。带来的好处就是,可以只用journalctl
一个命令,查看所有日志(内核日志和应用日志)。日志的配置文件是/etc/systemd/journald.conf
。
journalctl
功能强大,用法非常多。
# 查看所有日志(默认情况下 ,只保存本次启动的日志)
sudo journalctl
# 查看内核日志(不显示应用日志)
sudo journalctl -k
# 查看系统本次启动的日志
sudo journalctl -b
sudo journalctl -b -0
# 查看上一次启动的日志(需更改设置)
sudo journalctl -b -1
# 查看指定时间的日志
sudo journalctl --since="2012-10-30 18:17:16"
sudo journalctl --since "20 min ago"
sudo journalctl --since yesterday
sudo journalctl --since "2015-01-10" --until "2015-01-11 03:00"
sudo journalctl --since 09:00 --until "1 hour ago"
# 显示尾部的最新10行日志
sudo journalctl -n
# 显示尾部指定行数的日志
sudo journalctl -n 20
# 实时滚动显示最新日志
sudo journalctl -f
# 查看指定服务的日志
sudo journalctl /usr/lib/systemd/systemd
# 查看指定进程的日志
sudo journalctl _PID=1
# 查看某个路径的脚本的日志
sudo journalctl /usr/bin/bash
# 查看指定用户的日志
sudo journalctl _UID=33 --since today
# 查看某个 Unit 的日志
sudo journalctl -u nginx.service
sudo journalctl -u nginx.service --since today
# 实时滚动显示某个 Unit 的最新日志
sudo journalctl -u nginx.service -f
# 合并显示多个 Unit 的日志
journalctl -u nginx.service -u php-fpm.service --since today
# 查看指定优先级(及其以上级别)的日志,共有8级
# 0: emerg
# 1: alert
# 2: crit
# 3: err
# 4: warning
# 5: notice
# 6: info
# 7: debug
sudo journalctl -p err -b
# 日志默认分页输出,--no-pager 改为正常的标准输出
sudo journalctl --no-pager
# 以 JSON 格式(单行)输出
sudo journalctl -b -u nginx.service -o json
# 以 JSON 格式(多行)输出,可读性更好
sudo journalctl -b -u nginx.serviceqq
-o json-pretty
# 显示日志占据的硬盘空间
sudo journalctl --disk-usage
# 指定日志文件占据的最大空间
sudo journalctl --vacuum-size=1G
# 指定日志文件保存多久
sudo journalctl --vacuum-time=1years