261 lines
15 KiB
Markdown
261 lines
15 KiB
Markdown
---
|
||
title: systemctl命令的使用
|
||
tags:
|
||
- Linux
|
||
- Service
|
||
- 命令
|
||
- systemd
|
||
- systemctl
|
||
categories:
|
||
- - DevOps
|
||
- 系统管理
|
||
keywords: 'Service,命令,systemd,systemctl,daemon,服务,管理'
|
||
date: 2021-05-15 22:28:36
|
||
---
|
||
|
||
systemd是为了替换Linux系统中init进程而提出来的,是为系统的启动和管理提供直接服务的,而从它的名字也可以看出来,作为一个守护进程,systemd就是用来守护整个系统的。在systemd提供的一整套工具中,最常用的就是systemctl命令。<!-- more -->
|
||
|
||
## systemd要解决的问题
|
||
|
||
init进程是Linux用来启动服务的传统进程。一般需要自己配置`/etc/init.d`的服务,都是使用init进程启动的。
|
||
|
||
使用init来启动服务不是那么容易的,首先init服务是串行的,不是并行的,不能同时运行多个进程。其次,init进程是通过脚本来启动服务,所以脚本的编写就会变得十分复杂。
|
||
|
||
systemd成功的解决了init进程的这些问题,虽然systemd引入了一个十分庞大复杂的架构体系。systemd目前在大多数的Linux发行版中都得到了应用,并且取代了init进程成为了系统的1号进程(PID: 1)。我们日常最经常用到的功能就是systemd中的系统管理功能,也就是systemctl命令。
|
||
|
||
除了systemctl命令以外,systemd还提供了许多其他的命令,用来管理系统的每个方面。例如`systemd-analyze`可以用来分析系统启动耗时,`hostnamectl`可以用来查看主机信息。
|
||
|
||
## 可以被管理的系统资源
|
||
|
||
作为系统的1号进程,可以管理系统中的所有资源,systemd将这些资源划分成了不同的Unit,具体可见下表。
|
||
|
||
| Unit名称 | 对应系统资源 | 文件命名后缀 |
|
||
|---|---|---|
|
||
| Service Unit | 系统服务 | `.service` |
|
||
| Target Unit | 由多个Unit组成的一个组 | `.target` |
|
||
| Device Unit | 硬件设备 | `.device` |
|
||
| Mount Unit | 文件系统的挂载点 | `.mount` |
|
||
| Automount Unit | 自动挂载点 | `.automount` |
|
||
| Path Unit | 文件或路径 | `.path` |
|
||
| Scope Unit | 不由systemd启动的外部进程 | `.scope` |
|
||
| Slice Unit | 资源控制组 | `.slice` |
|
||
| Snapshot Unit | systemd快照 | |
|
||
| Socket Unit | 进程间通信的套接字 | `.socket` |
|
||
| Swap Unit | 交换区文件 | `.swap` |
|
||
| Timer Unit | 任务计划 | `.timer` |
|
||
|
||
其实Unit文件在系统中就是ini格式的纯文本文件,其中书写了所有Unit对象的信息。
|
||
|
||
### Unit资源加载路径
|
||
|
||
systemd会从一组在编译是就已经设定好的路径中加载Unit文件,并且不同的路径的优先级不一样,高优先级目录中的Unit文件会覆盖地优先级目录中的同名文件。鉴于systemd可以以系统实例和用户实例两种模式运行,所以会有两种Unit文件加载顺序。
|
||
|
||
以系统实例模式(`--system`)运行时:
|
||
|
||
| 系统单元目录 | 目录所包含内容 | 优先级 |
|
||
|---|---|---|
|
||
| `/etc/systemd/system.control` | 通过dbus API创建的永久系统单元 | 0 |
|
||
| `/etc/systemd/system.control` | 通过dbus API创建的临时系统单元 | 1 |
|
||
| `/etc/systemd/transient` | 动态配置的临时单元(系统与全局用户共用) | 2 |
|
||
| `/etc/systemd/generator.early` | 生成的高优先级单元(系统与全局用户共用) | 3 |
|
||
| `/etc/systemd/system` | 本地配置的系统单元 | 4 |
|
||
| `/run/systemd/system` | 运行时配置的系统单元 | 5 |
|
||
| `/run/systemd/generator` | 生成的中优先级系统单元 | 6 |
|
||
| `/usr/local/lib/systemd/system` | 本地软件包安装的系统单元 | 7 |
|
||
| `/usr/lib/systemd/system` | 发行版软件包安装的系统单元 | 8 |
|
||
| `/run/systemd/generator.late` | 生成的低优先级系统单元 | 9 |
|
||
|
||
当systemd以用户实例模式(`--user`)运行时,所使用的目录的基本上与以系统实例模式类似,只是`system`目录一般都换成`user`目录,系统单元也替换成用户单元,并且会受到环境变量`$XDG_CONFIG_HOME`和`$XDG_RUNTIME_HOME`的影响。
|
||
|
||
一般来说,需要开机不登录就可以运行的程序,都需要存放在系统服务里,即`/usr/lib/systemd/system`目录里,如果需要用户登录以后才可以运行的程序,可以放在相应的用户实例模式目录中,即`/usr/lib/systemd/usr`目录里。
|
||
|
||
> 所有的优先级描述,数字越小优先级越高。
|
||
|
||
## systemctl命令功能
|
||
|
||
systemctl命令就是针对这些Unit进行管理。
|
||
|
||
### 命令格式
|
||
|
||
```bash
|
||
systemctl [OPTIONS] COMMAND [UNIT]
|
||
```
|
||
|
||
正如systemctl命令格式中所描述的一样,systemctl命令的功能是通过不同的子命令来实现的。
|
||
|
||
### 列举Unit
|
||
|
||
列举Unit可以采用以下命令格式:
|
||
|
||
```bash
|
||
systemctl list-units [pattern]
|
||
```
|
||
|
||
直接运行这个命令可以列出目前已经存在于内存中的Unit,如果需要继续列出其他的Unit,那么就需要增加`pattern`了。常用的`pattern`有以下这些。
|
||
|
||
- `--all`,所有的Unit,包括没有找到配置文件和启动失败的。
|
||
- `--failed`,仅列出加载失败的Unit。
|
||
- `--type`,仅列出指定类型的Unit。这里的`type`值可以使用以上表格中的Unit名称(不带Unit字样且使用小写)。
|
||
- `--state`,列出拥有指定状态的Unit。可以使用的状态有:
|
||
- `active`
|
||
- `reloading`
|
||
- `inactive`
|
||
- `failed`
|
||
- `activating`
|
||
- `deactivating`
|
||
|
||
其他相似的列举命令还有:
|
||
|
||
- `list-sockets`,列举所有内存中的套接字Unit。
|
||
- `list-timers`,列举所有内存中的定时任务Unit。
|
||
- `list-unit-files`,列举目前系统中已经安装的Unit文件。
|
||
- `is-active`, 列举所有已经激活的Unit。
|
||
- `is-failed`,列举所有加载失败的Unit。
|
||
|
||
### 查看Unit状态
|
||
|
||
查看Unit状态需要使用`status`命令,格式为:
|
||
|
||
```bash
|
||
systemctl status [pattern|PID]
|
||
```
|
||
|
||
这里的`pattern`则是各个Unit文件的名称了,但是不需要包括文件后缀。例如`systemctl status bluetooth`。`status`命令将会列出指定Unit的全部信息。对于Unit的状态是通过Unit名称前面的图标来表现的。
|
||
|
||
### 启用和禁用Unit
|
||
|
||
支持systemd程序在安装的时候,一般都会在`/usr/lib/systemd/system`目录中添加一个Unit配置文件,这时就可以使用systemctl提供的命令来完成启用和禁用的任务。
|
||
|
||
systemctl中用于支持启用和禁用Unit的命令是以下两个:
|
||
|
||
- `enable`,启用Unit配置。
|
||
- `disable`,禁用Unit配置。
|
||
|
||
这两个命令在使用的时候均只需要书写Unit配置文件的文件名即可,不需要书写文件名后缀。这两个命令的主要是操作`/etc/systemd/system`目录中的符号链接。当调用`enable`命令的时候,systemctl会在`/etc/systemd/system`目录中创建一个指向`/usr/lib/systemd/system`中文件的符号链接。而调用`disable`命令的时候,systemctl会撤销`/etc/systemd/system`目录中的符号链接。
|
||
|
||
> 开机的时候,systemd只会执行`/etc/systemd/system`目录中的配置文件。所以如果要修改系统服务的配置,只需要修改这个目录中的文件即可。
|
||
|
||
### 控制Unit状态
|
||
|
||
控制Unit的状态应该是日常使用systemctl命令最频繁的地方了。常用的Unit状态控制命令主要有以下这些:
|
||
|
||
- `start`,启动Unit。
|
||
- `stop`,停止Unit。
|
||
- `reload`,重新加载Unit的配置。
|
||
- `restart`,重新启动Unit。
|
||
- `try-restart`,尝试重新启动Unit,如果Unit启动失败,不会报错。
|
||
- `reload-or-restart`,重新加载Unit的配置,如果Unit不支持`reload`,那么则以重新启动代替。
|
||
- `try-reload-or-restart`,尝试重新加载Unit的配置,如果Unit既不能重新加载配置也不能重新启动,那么便什么也不做。
|
||
- `kill`,强行终止Unit的运行。
|
||
- `clean`,清理Unit的配置、缓存等一切运行痕迹。
|
||
- `freeze`,挂起并冻结Unit的所有进程。
|
||
- `thraw`,解封被冻结的Unit。
|
||
|
||
## 编写一个Unit配置文件
|
||
|
||
要编写一个Unit配置文件,最快的学习方法就是参考系统本身已经存在的配置文件。要查看Unit配置文件,并不需要实地去保存有配置文件的目录中使用编辑器打开,而是可以借助systemctl提供的命令:`systemctl cat [Unit]`。
|
||
|
||
Unit配置文件就是一个ini格式的文本文件,其中可以分为三个区块:Unit、Sevice和Install。每个区块都是以下形式的键值对。
|
||
|
||
```ini
|
||
[Section]
|
||
Directive=value
|
||
Directive=value
|
||
```
|
||
|
||
### Unit区块
|
||
|
||
Unit区块通常是配置文件的第一个区块,主要用来定义Unit的元信息和与其他Unit的关系。例如会形成以下这样的配置项。
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=A Sample Service
|
||
Requires=sshd.service
|
||
```
|
||
|
||
以上示例表示这个Unit描述是`A Sample Service`,依赖于`sshd.service`运行。在Unit区块里可以用来定义Unit元信息的项目主要有以下这些。
|
||
|
||
- `Description`,Unit的简短描述。
|
||
- `Documentation`,Unit的文档所在位置。
|
||
- `Required`,当前Unit所依赖于的其他Unit,只有在这些Unit启动之后,当前的Unit才会开始启动。如果列在这里被依赖的Unit没有启动,那么这些Unit会先被启动。
|
||
- `Wants`,与当前Unit配合的其他Unit,如果哪些Unit不存在,当前Unit也不会出现启动失败的情况。
|
||
- `Requesite`,与`Required`类似,但是如果列在这里的Unit没有启动,那么当前的Unit会启动失败。
|
||
- `BindsTo`,当前Unit所要绑定到的其他Unit,会随目标Unit一同启动,也会随之停止。
|
||
- `PartOf`,与`Required`类似,但是如果列在这里的Unit发生了停止或者重启事件,那么当前Unit也会跟随做相同的操作。
|
||
- `Before`,指示当前Unit必须在指定Unit之前启动。
|
||
- `After`,指示当前Unit必须在指定Unit之后启动。
|
||
- `Conflicts`,指示当前Unit不能与指定Unit一同运行。
|
||
- `OnFailure`,指示当当前Unit处于`failed`状态的时候,需要启动哪些Unit来进行处理。
|
||
- `FailureAction`,`SuccessAction`,指示当当前Unit处于相应的状态时,要激活哪些系统或者用户活动,可以取以下值。
|
||
- `none`,不做任何动作,可在用户模式中使用。
|
||
- `reboot`,重启系统。
|
||
- `reboot-force`,强制重启系统。
|
||
- `reboot-immediate`,强制立刻重启系统。
|
||
- `poweroff`,关闭系统。
|
||
- `poweroff-force`,强制隔壁系统。
|
||
- `exit`,退出程序,可在用户模式中使用。
|
||
- `exit-force`,强制退出,可在用户模式中使用。
|
||
|
||
除了以上这些配置项以外,还有一系列的配置项是用来定义Unit的启动条件的,这些配置项通过对一些条件的定义确定了Unit的启动时机。常用的条件配置项都是`Condition...`前缀格式的。,默认情况下配置项中所列举的条件都是与的关系,但是也可以使用`Condition...=|...`格式来将配置项变为或的关系,如果在配置值前使用了`!`,那么这个条件就会成为一个否定条件。
|
||
|
||
`Condition...`配置项可以常用的条件后缀主要有以下这些:
|
||
|
||
- `Architecture`,系统架构,常用值有`x86`、`x86-64`、`arm`、`arm-be`、`arm64`等。
|
||
- `Virtualization`,判断系统是否运行在虚拟化环境中,常用值有`qemu`、`kvm`、`vmware`、`microsoft`、`oracle`、`docker`、`podman`、`rkt`等。
|
||
- `Host`,判断系统的Hostname是否是指定值。
|
||
- `KernelVersion`,判断系统内核的版本,可以使用`<`、`>`等关系比较符。
|
||
- `Environment`,判断制定的环境变量是否已经设置。
|
||
- `Security`,判断指定的安全技术已经在系统中被启用,常用的值有`selinux`、`apparmor`、`audit`等。
|
||
- `Capability`,判断服务管理器是否拥有指定的能力。
|
||
- `ACPower`,判断系统是否使用的是外接电源。
|
||
- `FirstBoot`,判断系统是否是第一次启动。
|
||
- `PathExists`,判断指定的路径是否存在。
|
||
- `PathIsDirectory`,判断指定的路径是否是一个目录。
|
||
- `PathIsSymbolicLink`,判断指定路径是否是一个符号链接。
|
||
- `PathIsMountPoint`,判断指定路径是否是一个挂载点。
|
||
- `PathIsReadWrite`,判断指定路径是否是可读写的。
|
||
- `PathIsEncrypted`,判断指定路径是否已被加密。
|
||
- `DirectoryNotEmpty`,判断指定路径是否非空。
|
||
- `FileNotEmpty`,判断指定文件是否非空。
|
||
- `FileIsExecutable`,判断指定文件是可执行的。
|
||
- `Memory`,判断系统中所安装的内存容量是否满足要求,可以使用`<`、`>`等关系比较符。
|
||
- `CPUs`,判断系统中所安装的CPU数量是否满足要求,可以使用`<`、`>`等关系比较符。
|
||
|
||
> 如果一个配置项目需要有多个值,那么可以直接用空格分隔书写。
|
||
|
||
通过对于Unit元信息的配置,可以确定Unit的启动条件,使Unit在启动的时候不至于因为缺少必要的资源而出现启动失败。
|
||
|
||
### Service区块
|
||
|
||
Service区块是Service Unit专有的配置区块,其中配置的是要启动何种程序以及程序要如何启动、如何停止、如何重启等。常用的配置项有以下这些。
|
||
|
||
- `Type`,程序以何种方式启动,可以取以下值。
|
||
- `simple`,普通方式。
|
||
- `forking`,程序以`fork()`方式启动。
|
||
- `oneshot`,程序只执行一次,systemd会等待程序执行结束再继续启动其他服务。
|
||
- `dbus`,程序会等待DBus信号以后启动。
|
||
- `notify`,程序启动后会发出通知信号,systemd才会去继续启动其他服务。
|
||
- `idle`,程序会等待其他任务都执行结束才会开始执行。
|
||
- `ExecStart`,要启动的程序及其参数。配置值前可以添加以下符号来实现一些特殊的功能,这些符号中功能不相近的可以同时使用。
|
||
- `@`,指示将第二个参数映射给`argv[0]`。
|
||
- `-`,报错信息将会被压制,只会被记录。
|
||
- `:`,环境变量不会被应用进去。
|
||
- `+`,程序会拥有最大权限。
|
||
- `!`,程序会使用提升的权限执行。
|
||
- `ExecStartPre`,`ExecStartPost`,指示在主程序启动之前或者之后启动其他的程序。
|
||
- `ExecReload`,指定执行`systemctl reload`的时候如何激活程序的重载功能,命令中可以使用`$MAINPID`来引用程序的PID。
|
||
- `ExecStop`,指定执行`systemctl stop`时使用何命令来停止程序的运行。
|
||
- `ExecStopPost`,指定在程序停止之后还需要执行的命令。
|
||
- `RestartSec`,指定重新启动程序的时间间隔。
|
||
- `TimeoutStartSec`,指定启动程序之前需要等待的时间。
|
||
- `TimeoutStopSec`,指定停止程序之前需要等待的时间。
|
||
- `Restart`,程序的重启策略,可取值有`no`、`on-success`、`on-failure`、`on-abnormal`、`on-watchdog`、`on-abort`和`always`。
|
||
- `OOMPolicy`,设定程序出现Out-Of-Memory状态时系统可以采取的策略,可取值有`continue`、`stop`、`kill`。
|
||
|
||
### Install区块
|
||
|
||
Install区块是被`systemctl enable`和`systemctl diasble`命令使用确定Unit要被如何安装和卸载的。这个区块中可以使用的配置项有以下这些。
|
||
|
||
- `Alias`,定义Unit的别名。Unit的别名可以在其他的Unit定义文件中使用,但是要求一个Unit的别名必须拥有相同的后缀。并且如果一个Unit拥有多个别名,那么在执行`systemctl enable`命令的时候,将会创建多个符号链接。
|
||
- `WantedBy`,`RequiredBy`,会在`.wants`和`.requires`命名的Target目录中创建当前Unit的符号链接,使当前Unit可以被指定的Target所包含。
|
||
- `Also`,设置与当前Unit一同被安装和卸载的Unit。 |