赞
踩
Systemd 是一系列工具的集合,其作用也远远不仅是启动操作系统,它还接管了后台服务、结束、状态查询,以及日志归档、设备管理、电源管理、定时任务等许多职责,并支持通过特定事件(如插入特定 USB 设备)和特定端口数据触发的 On-demand(按需)任务。
Systemd 的后台服务还有一个特殊的身份——它是系统中 PID 值为 1 的进程。
Systemctl官方手册:https://www.freedesktop.org/software/systemd/man/systemctl.html#
Systemd官方手册:https://www.freedesktop.org/software/systemd/man/systemd.html#
我们提到systemctl就一定需要知道systemd,因为Linux 服务管理有两种方式service和systemctl。而systemd是Linux系统最新的初始化系统(init),作用是提高系统的启动速度,尽可能启动较少的进程,尽可能更多进程并发启动,systemd对应的进程管理命令就是systemctl。值得一提的是,systemctl命令兼容了service哦。
这里咱们梳理一下systemd这个启动服务管理机制有哪些好处(也就是使用systemctl相关命令的好处啦)。
任务 | 旧命令 | 新命令 |
使某服务自动启动 | chkconfig --level 3 httpd on | systemctl enable httpd.service |
使某服务不自动启动 | chkconfig --level 3 httpd off | systemctl disable httpd.service |
检查服务状态 | service httpd status | systemctl status httpd.service (服务详细信息) systemctl is-active httpd.service (仅显示是否 Active) |
显示所有已启动的服务 | chkconfig --list | systemctl list-units --type=service |
启动某服务 | service httpd start | systemctl start httpd.service |
停止某服务 | service httpd stop | systemctl stop httpd.service |
重启某服务 | service httpd restart | systemctl restart httpd.service |
对比表,以apache/httpd为例
优点:
Systemd 提供了 服务按需启动 的能力,使得特定的服务只有在真定被请求时才启动。
在 SysV-init 时代,将每个服务项目编号依次执行启动脚本。Ubuntu 的 Upstart 解决了没有直接依赖的启动之间的并行启动。而 Systemd 通过 Socket 缓存、DBus 缓存和建立临时挂载点等方法进一步解决了启动进程之间的依赖,做到了所有系统服务并发启动。对于用户自定义的服务,Systemd 允许配置其启动依赖项目,从而确保服务按必要的顺序运行。
在 Systemd 之间的主流应用管理服务都是使用 进程树 来跟踪应用的继承关系的,而进程的父子关系很容易通过 两次 fork 的方法脱离。
而 Systemd 则提供通过 CGroup 跟踪进程关系,引补了这个缺漏。通过 CGroup 不仅能够实现服务之间访问隔离,限制特定应用程序对系统资源的访问配额,还能更精确地管理服务的生命周期。
Systemd 是一系列工具的集合, 包括了一个专用的系统日志管理服务:Journald。这个服务的设计初衷是克服现有 Syslog 服务的日志内容易伪造和日志格式不统一等缺点,Journald 用 二进制格式 保存所有的日志信息,因而日志内容很难被手工伪造。Journald 还提供了一个 journalctl 命令来查看日志信息,这样就使得不同服务输出的日志具有相同的排版格式, 便于数据的二次处理。
缺点:
Unit 文件按照 Systemd 约定,应该被放置指定的三个系统目录之一中。这三个目录是有优先级的,如下所示,越靠后的优先级越高。因此,在三个目录中有同名文件的时候,只有优先级最高的目录里的那个文件会被使用。
/usr/lib/systemd/system/(centos),/etc/systemd/system(Ubuntu):每个服务最主要的启动脚本的配置放在这,有点类似以前的/etc/init.d;
/run/systemd/system/:系统执行过程中所产生的服务脚本所在目录,这些脚本的优先级要比/usr/lib/systemd/system/高;
/etc/systemd/system/:管理员根据主机系统的需求所创建的执行脚本所在目录,执行优先级比/run/systemd/system/高;
从上面的功能及优先级次序,我们可以知道,/etc/systemd/system/目录下的相关配置,决定系统了会不会执行某些服务,所以该目录下面一般放着一大堆链接文件,指向目录 /usr/lib/systemd/system/。而/usr/lib/systemd/system/下,则放着实际执行的systemd启动脚本配置文件。因此如果你想要修改某个服务启动的设置,应该去/usr/lib/systemd/system/下面修改。/etc/systemd/system/仅是链接到正确的执行脚本配置文件而已。所以想要看执行脚本设置,应该就得要到/usr/lib/systemd/system/去查阅。
/etc/default/ 这个目录中放置很多服务默认的配置文件。
/var/lib/ 一些会产生数据的服务都会将他的数据写入到 /var/lib/ 目录中,比如 docker 相关的数据文件就放在这个目录下。
/run/ 这个目录放置了好多服务运行时的临时数据,比如 lock file 以及 PID file 等等。
Unit(单元|服务):Systemd 可以管理所有系统资源,不同的资源统称为 Unit(单位)。
在 Systemd 的生态圈中,Unit 文件统一了过去各种不同系统资源配置格式,例如服务的启/停、定时任务、设备自动挂载、网络配置、虚拟内存配置等。而 Systemd 通过不同的文件后缀来区分这些配置文件。
将系统资源划分为12类,将每个系统资源称为一个 Unit。Unit 是 Systemd 管理系统资源的基本单位,使用一个 Unit File 作为 Unit 的单元文件,Systemd 通过单元文件控制 Unit 的启动,例如,MySQL服务被 Systemd 视为一个 Unit,使用一个 mysql.service 作为启动配置文件。
Unit 是 Systemd 管理系统资源的基本单元,可以认为每个系统资源就是一个 Unit,并使用一个 Unit 文件定义。在 Unit 文件中需要包含相应服务的描述、属性以及需要运行的命令。
Target 是 Systemd 中用于指定系统资源启动组的方式,相当于 SysV-init 中的运行级别。
简单说,Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。从这个意义上说,Target 这个概念类似于”状态点”,启动某个 Target 就好比启动到某种状态。
Unit File(单元文件|配置文件):单元文件中包含该单元的描述、属性、启动命令等
Systemd 将系统资源划分为12类,对应12种类型的单元文件。
系统资源类型 | 单元文件扩展名 | 单元文件描述 |
Service | .service | 封装守护进程的启动、停止、重启和重载操作,是最常见的一种 Unit 文件, 为了与 SysV 兼容,我们不仅支持我们自己的服务配置文件,而且还能够读取经典的 SysV init 脚本,特别是我们解析 LSB 标头(如果存在)。 |
Target | .target | 定义 target 信息及依赖关系,一般仅包含 Unit 段。它本身并不实际做任何事情,它只是引用其他单元,从而可以一起控制。这方面的例子是:multi-user.target,它是一个在经典 SysV 系统上基本上扮演运行级别 5 角色的目标 |
Device | .device | 对于 /dev 目录下的硬件设备,主要用于定义设备之间的依赖关系, 如果设备通过 udev 规则为此标记,它将在 systemd 中作为device unit公开。使用udev设置的属性可用作配置源来设置设备单元的依赖关系。 |
Mount | .mount | 定义文件系统的挂载点,可以替代过去的 /etc/fstab 配置文件 |
Automount | .automount | 用于控制自动挂载文件系统,相当于 SysV-init 的 autofs 服务,每个自动挂载 单元都有一个匹配的挂载单元,一旦访问自动挂载目录,它就会启动(即挂载)。 |
Path | .path | 用于监控指定目录或文件的变化,并触发其它 Unit 运行 |
Scope | .scope | 这种 Unit 文件不是用户创建的,而是 Systemd 运行时产生的,描述一些系统服务的分组信息 |
Slice | .slice | 用于表示一个 CGroup 的树,通常用户不会自己创建这样的 Unit 文件 |
Snapshot | .snapshot | 用于表示一个由 systemctl snapshot 命令创建的 Systemd Units 运行状态快照,可以切回某个快照 |
Socket | .socket | 监控来自于系统或网络的数据消息,用于实现基于数据自动触发服务启动 |
Swap | .swap | 定义一个用户做虚拟内存的交换分区 |
Timer | .timer | 用于配置在特定时间触发的任务,替代了 Crontab 的功能 |
对于操作单元文件的命令,如果缺省扩展名,则默认.service扩展名
而操作 target 的命令,例如 isolate,则默认.target扩展名.
所有这些单元之间都可以有依赖关系(正面和负面,即“要求”和“冲突”):设备可以依赖于服务,这意味着一旦设备可用,就会启动某个服务。挂载对挂载它们的设备具有隐式依赖关系。挂载还获得对作为其前缀的挂载的隐式依赖项(即挂载/home/lennart隐式地将依赖项添加到挂载/home)等等。
主要服务功能类型详细说明
.service:一般服务类型(service unit):主要是系统服务,包括服务器本身所需要的本机服务以及网络服务,比较经常被使用到的服务大多是这种类型,所以,这也是最常见的类型。
.socket:内部程序数据交换的插槽服务(socketunit):主要是IPC(Inter-processcommunication)的传输信息插槽(socketfile)功能。这种类型的服务通常在监控信息传递的插槽档,当有通过此插槽传递信息请求链接服务的时候,就依据当时的状态将该用户的请求传送到对应的daemon,若daemon尚未启动,则启动该daemon后再传送用户的请求。使用socket类型的服务一般是比较不会被用到的服务,因此在开机时通常会稍微延迟启动的时间。一般用于本机服务比较多,例如我们的图形界面很多的软件都是通过socket来进行本机程序数据交换的行为。
.target:执行环境类型(target unit):其实是一群unit的集合,例如multi-user.target其实就是一堆服务的集合。.target定义了一些基础的组件,供.service文件调用。
.mount:文件系统挂载相关的服务(automount unit/mount unit):例如来自网络的自动挂载、NFS文件系统挂载等与文件系统相关性较高的程序管理。.mount文件定义了一个挂载点,[Mount]节点里配置了What,Where,Type三个数据项。等同于以下命令:mount -t hugetlbfs /dev/hugepages hugetlbfs
.path:监测特定文件或目录类型(path unit):某些服务需要监测某些特定的目录来提供序列服务,例如最常见的打印服务,就是通过监测打印序列目录来启动打印功能。这时就得要.path的服务类型支持。
.timer:循环执行的服务(timer unit):这个东西有点类似anacrontab,不过是由systemd主动提供的,比anacrontab更加有弹性。
.snapshot: 类似于target单元快照本身实际上不做任何事情,它们的唯一目的是引用其他单元。快照可用于保存/回滚 init 系统的所有服务和单元的状态。它主要有两个预期用例:允许用户临时进入特定状态,例如“紧急外壳”,终止当前服务,并提供一种简单的方法返回之前的状态,再次拉起所有临时拉动的服务下。并简化对系统挂起的支持:仍然有许多服务无法正确处理系统挂起,通常最好在挂起之前关闭它们,然后再恢复它们。
这里我们先查看一下service里面的内容,随便找了一个内容比较多的sshd.service,方便讲解,指令结果如下:
[root@desktop ~]# 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.target Wants=sshd-keygen.target
[Service] Type=notify EnvironmentFile=-/etc/crypto-policies/back-ends/opensshserver.config EnvironmentFile=-/etc/sysconfig/sshd-permitrootlogin EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY $PERMITROOTLOGIN ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s
[Install] WantedBy=multi-user.target |
单元文件的语法来源于 XDG桌面入口配置文件.desktop文件
Unit 文件可以分为三个配置区段:
Unit 段:所有 Unit 文件通用,用来定义 Unit 的元数据,以及配置与其他 Unit 的关系
Install 段:所有 Unit 文件通用,用来定义如何启动,以及是否开机启动
Service 段:服务(Service)类型的 Unit 文件(后缀为 .service)特有的,用于定义服务的具体管理和执行动作
单元文件中的区段名和字段名大小写敏感 每个区段内都是一些等号连接的键值对(键值对的等号两侧不能有空格) |
其中三个部分分别是:
[Unit]:unit本身的说明,以及与其他相关联daemon的设置,包括在什么服务之后才启动此unit之类的设置值;
[Service],[Socket],[Timer],[Mount],[Path]等等:不同的unit type就得要使用相对应的设置项目,我们拿的是sshd.service来举例,所以这边就使用[Service]来设置。这个项目内主要在规范服务启动的脚本、环境配置文件文件名、重新启动的方式等等;
[Install]:这个项目就是将此unit安装到哪个target里面去;
至于配置文件内有些设置规则还是得要说明一下:
[Unit]部分 | |
设置参数 | 参数意义说明 |
Description | 就是当我们使用 systemctl list-units 时,会输出给管理员看的简易说明,当然,使用systemctlstatus 输出的此服务的说明,也是这个项目。 |
Documentation | 这个项目在提供管理员能够进行进一步的文件查询的功能,提供的文件可以是如下的数据:Documentation=http://www.... |
After | 说明此 unit 是在哪个 daemon 启动之后才启动,基本上仅是说明服务启动的顺序而已,并没有强制要求里面的服务一定要启动后此unit才能启动。以 sshd.service 的内容为例,该文件提到 After 后面有network.target 以及 sshd-keygen.service ,但是若这两个 unit 没有启动而强制启动sshd.service 的话,那么 sshd.service 应该还是能够启动的,这与Requires 的设置是有差异的。 |
Before | 与 After 的意义相反,是在什么服务启动前最好启动这个服务。不过这仅是规范服务启动的顺序,并非强制要求。 |
Requires | 强依赖,明确的定义此 unit 需要在哪个 daemon 启动后才能够启动,就是设置服务的关联性,如果在此项设置的前导服务没有启动,那么此unit 就不会被启动。 |
Wants | 弱依赖,与 Requires 刚好相反,规范的是这个 unit 之后最好还要启动什么服务,不过,并没有明确的规范,主要的目的是希望创建让使用者比较好操作的环境。因此,这个Wants后面接的服务如果没有启动,其实不会影响到这个unit 本身。 |
Conflicts | 代表冲突的服务,即这个项目后面接的服务如果有启动,那么我们这个 unit 本身就不能启动,我们 unit 有启动,则此项目后的服务就不能启动,就是冲突性的检查。 |
Binds To | 与 Requires 相似,失败时失败,成功时成功,但是在这些模板中有任意一个出现意外结束或重启时,这个服务也会跟着终止或重启. |
Part Of | 一个 Bind To 作用的子集,仅在列出的任务模块失败或重启时,终止或重启当前服务,而不会随列出模板的启动而启动 |
OnFailure | 当这个模板启动失败时,就会自动启动列出的每个模块 |
用来 Service 的配置,只有 Service 类型的 Unit 才有这个区块。
【启动类型】
说明这个 daemon 启动的方式,会影响到 ExecStart, 一般来说,有下面几种类型:
1、Type=simple :默认值,这个 daemon 主要由 ExecStart 接的指令串来启动,启动的进程为主进程 。启动后常驻于内存中。
服务进程不会 fork,如果该服务要启动其他服务,不要使用此类型启动,除非该服务是 socket 激活型。
2、Type=forking :ExecStart字段将以fork()方式从父进程创建子进程启动,创建后父进程会立即退出,子进程成为主进程。
通常需要指定PIDFile字段,以便 Systemd 能够跟踪服务的主进程。
对于常规的守护进程(daemon),除非你确定此启动方式无法满足需求,使用此类型启动即可。
由 ExecStart 启动的程序通过spawns 延伸出其他子程序来作为此 daemon 的主要服务。原生的父程序在启动结束后就会终止运行。传统的unit 服务大多属于这种项目,例如httpd 这个 WWW 服务,当 httpd 的程序因为运行过久因此即将终结了,则systemd 会再重新生出另一个子程序持续运行后,再将父程序删除。
3、Type=oneshot :与simple 类似,不过这个程序在工作完毕后就结束了,不会常驻在内存中。
适用于只执行一项任务、随后立即退出的服务
通常需要指定RemainAfterExit=yes字段,使得 Systemd 在服务进程退出之后仍然认为服务处于激活状态
4、Type=dbus :与 simple 类似,但这个 daemon 必须要在取得一个D-Bus的名称后,才会继续运行!因此设置这个项目时,通常也要设置BusName= 才行!
5、Type=notify:当前服务启动完毕会发出通知信号,通知 Systemd,然后 Systemd 再启动其他服务。
6、Type=idle :与 simple 类似,意思是,要执行这个daemon必须要所有的工作都顺利执行完毕后才会执行。这类的 daemon通常是开机到最后才执行即可的服务!比较重要的项目大概是simple,forking 与 oneshot 了!毕竟很多服务需要子程序(forking ),而有更多的动作只需要在开机的时候执行一次(oneshot ),例如文件系统的检查与挂载啊等等的。
【启动行为】
1、ExecStart:启动当前服务的命令,可以指定启动脚本的环境配置文件!例如 sshd.service 的配置文件写入到/etc/sysconfig/sshd 当中!你也可以使用 Environment= 后面接多个不同的Shell 变量来给予设置!
ExecStart=/bin/echo execstart1
ExecStart=
ExecStart=/bin/echo execstart2
顺序执行设定的命令,把字段置空,表示清除之前的值
2、ExecStartPre:启动当前服务之前执行的命令
3、ExecStartPost:启动当前服务之后执行的命令
4、ExecReload:重启当前服务时执行的命令,,与 systemctl reload 有关的指令行为
5、ExecStop:停止当前服务时执行的命令,与 systemctl stop 的执行有关,关闭此服务时所进行的指令。
6、ExecStopPost:停止当前服务之后执行的命令
7、RemainAfterExit:当前服务的所有进程都退出的时候,Systemd 仍认为该服务是激活状态。当设置为 RemainAfterExit=1 时,则当这个 daemon 所属的所有程序都终止之后,此服务会再尝试启动。这对于Type=oneshot 的服务很有帮助!
这个配置主要是提供给一些并非常驻内存,而是启动注册后立即退出,然后等待消息按需启动的特殊类型服务使用的
8、TimeoutSec:定义 Systemd 停止当前服务之前等待的秒数,若这个服务在启动或者是关闭时,因为某些缘故导致无法顺利 “ 正常启动或正常结束” 的情况下,则我们要等多久才进入 “ 强制结束 ” 的状态!
注:所有的启动设置之前,都可以加上一个连词号(-),表示"抑制错误",即发生错误的时候,不影响其他命令的执行。比如,EnvironmentFile=-/etc/sysconfig/sshd(注意等号后面的那个连词号),就表示即使/etc/sysconfig/sshd文件不存在,也不会抛出错误。 |
【重启行为】
RestartSec:Systemd 重启当前服务间隔的秒数,与 Restart 有点相关性,如果这个服务被关闭,然后需要重新启动时,大概要sleep 多少时间再重新启动的意思。默认是 100ms (毫秒)。
KillMode:定义 Systemd 如何停止服务,可以是 process,control-group,none 的其中一种,如果是 process则daemon 终止时,只会终止主要的程序( ExecStart 接的后面那串指令),如果是control-group 时,则由此 daemon 所产生的其他control-group的程序,也都会被关闭。如果是 none 的话,则没有程序会被关闭喔!可能的值包括:
Restart:定义何种情况 Systemd 会自动重启当前服务,可能的值包括:
【上下文】
PIDFile:指向当前服务 PID file 的绝对路径。
User:指定运行服务的用户
Group:指定运行服务的用户组
EnvironmentFile:指定当前服务的环境参数文件。该文件内部的key=value键值对,可以用$key的形式,在当前配置文件中获取,例如 sshd.service 的配置文件写入到/etc/sysconfig/sshd 当中!你也可以使用 Environment= 后面接多个不同的Shell 变量来给予设置!
启动sshd,执行的命令是/usr/sbin/sshd -D $OPTIONS,其中的变量$OPTIONS就来自EnvironmentFile字段指定的环境参数文件。 |
这部分配置的目标模块通常是特定运行目标的 .target 文件,用来使得服务在系统启动时自动运行。这个区段可以包含三种启动约束:
[Install]部分 | |
设置参数 | 参数意义说明 |
WantedBy | 和 Unit 段的 Wants 作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。它的值是一个或多个 Target,当前 Unit 激活时(enable)符号链接会放入 /etc/systemd/system 目录下面以 <Target 名> + .wants 后缀构成的子目录中,如 “/etc/systemd/system/multi-user.target.wants/“,这个设置后面接的大部分是 *.targetunit !意思是,这个 unit 本是附挂在哪一个targetunit 下面的!一般来说,大多的服务性质 unit 都是附挂在multi-user.target下面! |
RequiredBy | 和 Unit 段的 Wants 作用相似,只有后面列出的不是服务所依赖的模块,而是依赖当前服务的模块。它的值是一个或多个 Target,当前 Unit 激活时,符号链接会放入 /etc/systemd/system 目录下面以 <Target 名> + .required 后缀构成的子目录中 |
Also | 当目前这个 unit 本身被 enable 时, Also 后面接的 unit 也请 enable。 也就是具有相依性的服务可以写在这里。 |
Alias | 进行一个链接的别名的意思!当 systemctlenable 相关的服务时则此服务会进行链接文件的创建!以multi-user.target 为例,这个伙是用来作为默认操作环境default.target 的规划,因此当你设置成 default.target时,这个/etc/systemd/system/default.target 就会链接到/usr/lib/systemd/system/multi-user.target。 |
通过 systemctl list-units --type=target 命令可以获取当前正在使用的运行目标
# systemctl list-units --type=target
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Encrypted Volumes
getty.target loaded active active Login Prompts
graphical.target loaded active active Graphical Interface
local-fs-pre.target loaded active active Local File Systems (Pre)
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
network.target loaded active active Network
nss-user-lookup.target loaded active active User and Group Name Lookups
paths.target loaded active active Paths
remote-fs-pre.target loaded active active Remote File Systems (Pre)
remote-fs.target loaded active active Remote File Systems
slices.target loaded active active Slices
sockets.target loaded active active Sockets
sound.target loaded active active Sound Card
swap.target loaded active active Swap
sysinit.target loaded active active System Initialization
time-sync.target loaded active active System Time Synchronized
timers.target loaded active active Timers
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
20 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
Unit 文件占位符
在 Unit 文件中,有时会需要使用到一些与运行环境有关的信息,例如节点 ID、运行服务的用户等。这些信息可以使用占位符来表示,然后在实际运行被动态地替换实际的值。
%n:完整的 Unit 文件名字,包括 .service 后缀名
%p:Unit 模板文件名中 @ 符号之前的部分,不包括 @ 符号
%i:Unit 模板文件名中 @ 符号之后的部分,不包括 @ 符号和 .service 后缀名
%t:存放系统运行文件的目录,通常是 “run”
%u:运行服务的用户,如果 Unit 文件中没有指定,则默认为 root
%U:运行服务的用户 ID
%h:运行服务的用户 Home 目录,即 %{HOME} 环境变量的值
%s:运行服务的用户默认 Shell 类型,即 %{SHELL} 环境变量的值
%m:实际运行节点的 Machine ID,对于运行位置每个的服务比较有用
%b:Boot ID,这是一个随机数,每个节点各不相同,并且每次节点重启时都会改变
%H:实际运行节点的主机名
%v:内核版本,即 “uname -r” 命令输出的内容
%%:在 Unit 模板文件中表示一个普通的百分号
Unit 模板
在现实中,往往有一些应用需要被复制多份运行。例如,用于同一个负载均衡器分流的多个服务实例,或者为每个 SSH 连接建立一个独立的 sshd 服务进程。
Unit 模板文件的写法与普通的服务 Unit 文件基本相同,不过 Unit 模板的文件名是以 @ 符号结尾的。通过模板启动服务实例时,需要在其文件名的 @ 字符后面附加一个参数字符串。
示例:apache@.service
1、apache@.service 模板如下
[Unit]
Description=My Advanced Service Template
After=etcd.service docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill apache%i
ExecStartPre=-/usr/bin/docker rm apache%i
ExecStartPre=/usr/bin/docker pull coreos/apache
ExecStart=/usr/bin/docker run --name apache%i -p %i:80 coreos/apache /usr/sbin/apache2ctl -D FOREGROUND
ExecStartPost=/usr/bin/etcdctl set /domains/example.com/%H:%i running
ExecStop=/usr/bin/docker stop apache1
ExecStopPost=/usr/bin/docker rm apache1
ExecStopPost=/usr/bin/etcdctl rm /domains/example.com/%H:%i
[Install]
WantedBy=multi-user.target
2、启动 Unit 模板的服务实例
在服务启动时需要在 @ 后面放置一个用于区分服务实例的附加字符参数,通常这个参数用于监控的端口号或控制台 TTY 编译号。
# systemctl start apache@8080.service
Systemd 在运行服务时,总是会先尝试找到一个完整匹配的 Unit 文件,如果没有找到,才会尝试选择匹配模板。例如上面的命令,System 首先会在约定的目录下寻找名为 apache@8080.service 的文件,如果没有找到,而文件名中包含 @ 字符,它就会尝试去掉后缀参数匹配模板文件。对于 apache@8080.service,systemd 会找到 apache@.service 模板文件,并通过这个模板文件将服务实例化。
在 /usr/lib/systemd/system 下新建服务脚本
vim /usr/lib/systemd/system/zdy.service
[Unit]
Description=描述
Environment=环境变量或参数(系统环境变量此时无法使用)
After=network.target
[Service]
Type=forking
EnvironmentFile=所需环境变量文件或参数文件
ExecStart=启动命令(需指定全路径)
ExecStop=停止命令(需指定全路径)
User=以什么用户执行命令
[Install]
WantedBy=multi-user.target
新建完成后设置自启动
# 添加或修改配置文件后,需要重新加载
systemctl daemon-reload
# 设置自启动,实质就是在 /etc/systemd/system/multi-user.target.wants/ 添加服务文件的链接
systemctl enable zdy
在安装新服务包后,进入安装包路径查找.service单位文件 # find . -name *service* # cp unitservice.service /usr/lib/systemd/system/ # chmod 644 /usr/lib/systemd/system/unitservice.service # systemctl list-unit-files |grep unitservice # systemctl enable unitservice && systemctl start unitservice |
这里我们可以先试用下面这个指令查看一下atd服务的当前状态,指令和结果如下:
[root@desktop ~]# systemctl status atd.service ● atd.service - Deferred execution scheduler Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2021-07-28 09:53:18 CST; 1h 59min ago Docs: man:atd(8) Main PID: 1592 (atd) Tasks: 1 Memory: 280.0K CGroup: /system.slice/atd.service └─1592 /usr/sbin/atd -f
7月 28 09:53:18 desktop.example.com systemd[1]: Started Deferred execution scheduler. 第一行是对 unit 的基本描述。点("●")在支持的终端上使用颜色来概述单位状态。白色表示“未激活”或“失效”状态。红色表示“失败”或“错误”状态,绿色表示“激活”、“重新加载”或“激活”状态。
第二行中的 Loaded 描述操作系统启动时会不会启动这个服务,enabled 表示开机时启动,disabled 表示开机时不启动。而启动该服务的配置文件路径为:/usr/lib/systemd/system/atd.service。
第三行 中的 Active 描述服务当前的状态,active (running) 表示服务正在运行中。如果是 inactive (dead) 则表示服务当前没有运行。后面则是服务的启动时间。“Active:”行显示活动状态。取值通常为“active”或“inactive”。激活可能意味着启动、绑定、插入等等,这取决于单元类型。该单元还可能处于状态变化的过程中,报告“激活”或“失效”状态。当服务以某种方式失败时,比如崩溃、带错误代码退出或超时,就会进入一个特殊的“失败”状态。如果进入失败状态,将记录原因,以供以后参考。
第四行的 Docs 提供了在线文档的地址。 下面的 Main PID 表示进程的 ID,接下来是任务的数量,占用的内存和 CPU 资源。 再下面的 Cgroup 描述的是 cgrpup 相关的信息,笔者会在后续的文章中详细的介绍。 最后是输出的日志信息。 |
看到绿色高亮的那个没有,这就是当前服务的状态。那么服务有哪几种常见的状态呢,这里列举说明一下。
active(running):正有一只或多只程序正在系统中执行的意思;
active(exited):仅执行一次就正常结束的服务,目前并没有任何程序在系统中执行;举例来说,开机或者是挂载时才会进行一次的 quotaon 功能,就是这种模式! Quotaon 不需要一直执行,只在执行一次之后,就交给文件系统去自行处理。通常用 bash shell 写的小型服务,大多是属于这种类型。
active(waiting):正在执行当中,不过还需要等待其他的事件才能继续处理;举例来说,打印的相关服务就是这种状态。
inactive:这个服务目前没有运行;
dead:程序已经清除;
上面是运行结果中,黄底红字的地方,那个是啥?那个其实是这只服务程序的启动状态,也分为一下几种状态。
enabled:这个daemon将在开机时被执行;
disabled:这个daemon在开机时不会被执行;
static:这个daemon不可以自己启动(enable不可),不过可能会被其他的enabled 的服务来唤醒(关联属性的服务);
mask:这个daemon无论如何都无法被启动,因为已经被强制注销(非删除),可通过systemctl unmask方式改回原本状态;
systemctl --version #查看systemctl版本号
systemctl #范列出系统上面有启动的unit
systemctl list-units #列出所有启动unit
systemctl list-unit-files #列出所有已经安装的unit有哪些
systemctl list-units --type=service --all #列出类型为service的所有项目,不论启动与否
systemctl get-default #输入目前机器默认的模式,如图形界面模式或者文本模式
systemctl set-default multi-user.target #设置指定的target为默认的运行级别
systemctl isolate multi-user.target #将目前的操作环境改为纯文本模式,关掉图形界面(不重启的情况)
systemctl isolate graphical.target #将目前的操作环境改为图形界面(不重启的情况)
systemctl poweroff #系统关机
systemctl reboot #重新开机
systemctl suspend #进入暂停模式
systemctl rescue #强制进入救援模式
systemctl hibernate #进入休眠模式
systemctl emergency #强制进入紧急救援模式
systemctl list-dependencies --reverse #查询当前默认的target关联了啥
systemctl list-dependencies graphical.target #查询图形界面模式的target关联了啥
systemctl list-sockets #查看当前的socket服务
systemctl show etcd.service #查看 unit 的详细配置情况
systemctl mask etcd.service #禁用某个服务
systemctl unmask etcd.service #解除禁用某个服务
systemctl start network.service #启动网络服务
systemctl stop network.service #停止网络服务
systemctl restart network.service #重启网络服务
systemctl status network.serivce #查看网络服务状态
systemctl disable network.service #禁止网络服务开机启动
systemctl enable network.service #重新设置网络服务开机启动
systemctl is-active network.service #查看网络服务是否启动
systemctl is-enabled network.service #检查网络服务是否设置为开机启动
bootctl:用于查看和管理系统启动分区
hostnamectl:用于查看和修改系统的主机名和主机信息
journalctl:用于查看系统日志和各类应用服务日志
localectl:用于查看和管理系统的地区信息
loginctl:用于管理系统已登录用户和 Session 的信息
machinectl:用于操作 Systemd 容器
timedatectl:用于查看和管理系统的时间和时区信息
systemd-analyze 显示此次系统启动时运行每个服务所消耗的时间,可以用于分析系统启动过程中的性能瓶颈
systemd-ask-password:辅助性工具,用星号屏蔽用户的任意输入,然后返回实际输入的内容
systemd-cat:用于将其他命令的输出重定向到系统日志
systemd-cgls:递归地显示指定 CGroup 的继承链
systemd-cgtop:显示系统当前最耗资源的 CGroup 单元
systemd-escape:辅助性工具,用于去除指定字符串中不能作为 Unit 文件名的字符
systemd-hwdb:Systemd 的内部工具,用于更新硬件数据库
systemd-delta:对比当前系统配置与默认系统配置的差异
systemd-detect-virt:显示主机的虚拟化类型
systemd-inhibit:用于强制延迟或禁止系统的关闭、睡眠和待机事件
systemd-machine-id-setup:Systemd 的内部工具,用于给 Systemd 容器生成 ID
systemd-notify:Systemd 的内部工具,用于通知服务的状态变化
systemd-nspawn:用于创建 Systemd 容器
systemd-path:Systemd 的内部工具,用于显示系统上下文中的各种路径配置
systemd-run:用于将任意指定的命令包装成一个临时的后台服务运行
systemd-stdio- bridge:Systemd 的内部 工具,用于将程序的标准输入输出重定向到系统总线
systemd-tmpfiles:Systemd 的内部工具,用于创建和管理临时文件目录
systemd-tty-ask-password-agent:用于响应后台服务进程发出的输入密码请求
暂停模式与休眠模式的区别: suspend:暂停模式会将系统的状态保存到内存中,然后关闭掉大部分的系统硬件,当然,并没有实际关机。当用户按下唤醒机器的按钮,系统数据会从内存中回复,然后重新驱动被大部分关闭的硬件,所以唤醒系统的速度比较快。 hibernate:休眠模式则是将系统状态保存到硬盘当中,保存完毕后,将计算机关机。当用户尝试唤醒系统时,系统会开始正常运行,然后将保存在硬盘中的系统状态恢复回来。因为数据需要从硬盘读取,因此唤醒的速度比较慢(如果你使用的是 SSD 磁盘,唤醒的速度也是非常快的)。 |
这里我想特别提一下跟操作界面比较有关的target项目,毕竟常用的模式target有以下几种:
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的项目,可以修改这个东西的配置文件;
SysV-init level | systemctl target | Note |
0 | runlevel0.targatàshutdown.target/poweroff.target | 关闭系统 |
1 | runlevel1.targetàrescure.target | 单用户模式 |
2 | runlevel2.targetàmulti-user.target | 用户定义/域特定运行级别,默认等同于级别3 |
3 | runlevel3.targetàmulti-user.target | 多用户模式 |
4 | runlevel4.targetàmulti-user.target | 用户定义/域特定运行级别,默认等同于级别3 |
5 | runlevel5.targetàgraphical.target | 多用户、图形模式 |
6 | runlevel6.targetàreboot.target | 重启 |
emergency | emergency.target | 急救模式 |
通过systemctl list-units --type=target命令可以获取当前正在使用的运行目标。
正常的模式是 multi-user.target 和 graphical.target 两个,救援方面的模式主要是 rescue.target 以及更严重的 emergency.target。如果要修改可提供登陆的 tty 数量,则修改 getty.target。
当一个新的 Unit 文件被放入 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目录中时,它是不会被自识识别的。
1、服务的激活
systemctl enable:在 /etc/systemd/system/ 建立服务的符号链接,指向 /usr/lib/systemd/system/ 中
systemctl start:依次启动定义在 Unit 文件中的 ExecStartPre、ExecStart 和 ExecStartPost 命令
2、服务的启动和停止
systemctl start:依次启动定义在 Unit 文件中的 ExecStartPre、ExecStart 和 ExecStartPost 命令
systemctl stop:依次停止定义在 Unit 文件中的 ExecStopPre、ExecStop 和 ExecStopPost 命令
systemctl restart:重启服务
systemctl kill:立即杀死服务
3、服务的开机启动和取消
systemctl enable:除了激活服务以外,也可以置服务为开机启动
systemctl disable:取消服务的开机启动
4、服务的修改和移除
systemctl daemon-reload:Systemd 会将 Unit 文件的内容写到缓存中,因此当 Unit 文件被更新时,需要告诉 Systemd 重新读取所有的 Unit 文件
systemctl reset-failed:移除标记为丢失的 Unit 文件。在删除 Unit 文件后,由于缓存的关系,即使通过 daemon-reload 更新了缓存,在 list-units 中依然会显示标记为 not-found 的 Unit。
Target 就是一个 Unit 组,包含许多相关的 Unit 。启动某个 Target 的时候,Systemd 就会启动里面所有的 Unit。
在传统的 SysV-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 与 SysV-init 进程的主要区别:
默认的 RunLevel(在 /etc/inittab 文件设置)现在被默认的 Target 取代,位置是 /etc/systemd/system/default.target,通常符号链接到graphical.target(图形界面)或者multi-user.target(多用户命令行)。
启动脚本的位置,以前是 /etc/init.d 目录,符号链接到不同的 RunLevel 目录 (比如 /etc/rc3.d、/etc/rc5.d 等),现在则存放在 /lib/systemd/system 和 /etc/systemd/system 目录。
配置文件的位置,以前 init 进程的配置文件是 /etc/inittab,各种服务的配置文件存放在 /etc/sysconfig 目录。现在的配置文件主要存放在 /lib/systemd 目录,在 /etc/systemd 目录里面的修改可以覆盖原始设置。
Systemd 通过其标准日志服务 Journald 提供的配套程序 journalctl 将其管理的所有后台进程打印到 std:out(即控制台)的输出重定向到了日志文件。
Systemd 的日志文件是二进制格式的,必须使用 Journald 提供的 journalctl 来查看,默认不带任何参数时会输出系统和所有后台进程的混合日志。
默认日志最大限制为所在文件系统容量的 10%,可以修改 /etc/systemd/journald.conf 中的 SystemMaxUse 来指定该最大限制。
# 查看所有日志(默认情况下 ,只保存本次启动的日志)
$ sudo journalctl
# 查看内核日志(不显示应用日志):--dmesg 或 -k
$ sudo journalctl -k
# 查看系统本次启动的日志(其中包括了内核日志和各类系统服务的控制台输出):--system 或 -b
$ sudo journalctl -b
$ sudo journalctl -b -0
# 查看上一次启动的日志(需更改设置)
$ sudo journalctl -b -1
# 查看指定服务的日志:--unit 或 -u
$ sudo journalctl -u docker.servcie
# 查看指定服务的日志
$ sudo journalctl /usr/lib/systemd/systemd
# 实时滚动显示最新日志
$ sudo journalctl -f
# 查看指定时间的日志
$ 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 行日志:--lines 或 -n
$ sudo journalctl -n
# 显示尾部指定行数的日志
$ sudo journalctl -n 20
# 将最新的日志显示在前面
$ sudo journalctl -r -u docker.service
# 改变输出的格式:--output 或 -o
$ sudo journalctl -r -u docker.service -o json-pretty
# 查看指定进程的日志
$ 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
使用 show 子命令可以查看 unit 的详细配置情况:
[root@desktop ~]# systemctl show etcd.service
或者 systemctl cat etcd.service
Restart=no
NotifyAccess=none
RestartUSec=100ms
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
TimeoutAbortUSec=1min 30s
RuntimeMaxUSec=infinity
WatchdogUSec=0
WatchdogTimestampMonotonic=0
RootDirectoryStartOnly=no
如果我们想暂时的禁用某个 unit,比如 firewalld.service,可以注销这个 unit,注销之后就无法再启动这个服务了:
[root@desktop ~]# systemctl mask firewalld.service
Created symlink /etc/systemd/system/firewalld.service → /dev/null.
从上述中的输出我们可以看到,所谓的注销就是把 firewalld.service 文件链接到 /dev/null 这个空设备中去了。所以就无法再启动该服务了。下面我们尝试执行一次反注销:
[root@desktop ~]# systemctl unmask firewalld.service
Removed /etc/systemd/system/firewalld.service.
unmask 操作就是删除掉 mask 操作中创建的链接。
systemctl 提供了子命令可以查看系统上的 unit,命令格式为:
systemctl [command] [--type=TYPE] [--all]
command 有:
list-units:列出当前已经启动的 unit,如果添加 -all 选项会同时列出没有启动的 unit。
list-unit-files:根据 /lib/systemd/system/ 目录内的文件列出所有的 unit。
--type=TYPE:可以过滤某个类型的 unit。
不带任何参数执行 systemctl 命令会列出所有已启动的 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
# 查看 Unit 配置文件的内容
$ systemctl cat docker.service
# 显示远程主机的某个 Unit 的状态
$ systemctl -H root@rhel7.example.com status httpd.service
systemctl list-units (或者直接 sudo systemctl)
系统默认启动的服务是非常多的,上图只截取了前面几行。下面是对输出的介绍:
UNIT:项目的名称,包括各个 unit 的类别(看扩展名)。
LOAD:开机时 unit 的配置是否被加载。
ACTIVE:目前的状态,须与后续的 SUB 搭配!就是我们用 systemctl status 观察时,active的内容。
DESCRIPTION:描述信息。
注意,systemctl 不加参数,其实等同于 systemctl list-units
[root@desktop ~]# systemctl list-unit-files
UNIT FILE STATE
proc-sys-fs-binfmt_misc.automount static
-.mount generated
boot.mount generated
dev-hugepages.mount static
dev-mqueue.mount static
proc-fs-nfsd.mount static
proc-sys-fs-binfmt_misc.mount static
sys-fs-fuse-connections.mount static
sys-kernel-config.mount static
sys-kernel-debug.mount static
tmp.mount disabled
var-lib-nfs-rpc_pipefs.mount static
systemd-ask-password-console.path static
systemd-ask-password-plymouth.path static
systemd-ask-password-wall.path static
session-2.scope transient
session-4.scope transient
accounts-daemon.service enabled
结果也非常的多,我们仍然只截取一部分结果。这里的 STATE 就是我们前面介绍的 服务的启动状态,有 enable 和 disable、static 和 mask。
比如我们只查看服务类型的unit:
[root@desktop ~]# systemctl list-units --type=service -all
UNIT LOAD ACTIVE SUB JOB DESCRIPTION
accounts-daemon.service loaded active running Accounts Service
atd.service loaded active running Deferred execution scheduler
auditd.service loaded activating start start Security Auditing Service
auth-rpcgss-module.service loaded inactive dead Kernel Module supporting RPCSEC_GSS
● autofs.service not-found inactive dead autofs.service
chronyd.service loaded active running NTP client/server
cockpit-motd.service loaded inactive dead Cockpit motd updater service
cockpit.service loaded inactive dead Cockpit Web Service
如果发现某个 unit 不工作,可以查看是否有 unit 加载失败:
[root@desktop ~]# systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
● kdump.service loaded failed failed Crash recovery kernel arming
● kylin-activation-check.service loaded failed failed run kylin_activation_check at boot time
● kysec-sync-notify.service loaded failed failed Kysec label sync daemon
● lm_sensors.service loaded failed failed Hardware Monitoring Sensors
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
4 loaded units listed.
很多服务之间是有依赖关系的,systemd 的一大亮点就是可以管理 unit 之间的依赖关系。我们可以通过下面的命令来查看 unit 间的依赖关系:
systemctl list-dependencies [unit] [--reverse] #选项 --reverse 会反向追踪是谁在使用这个 unit。
下面让我们看看当前运行的 target 的依赖关系:
[root@desktop ~]# systemctl list-sockets LISTEN UNIT ACTIVATES /dev/rfkill systemd-rfkill.socket systemd-rfkill.service /run/dbus/system_bus_socket dbus.socket dbus.service /run/dmeventd-client dm-event.socket dm-event.service /run/dmeventd-server dm-event.socket dm-event.service /run/initctl systemd-initctl.socket systemd-initctl.service /run/lvm/lvmetad.socket lvm2-lvmetad.socket lvm2-lvmetad.service /run/lvm/lvmpolld.socket lvm2-lvmpolld.socket lvm2-lvmpolld.service /run/rpcbind.sock rpcbind.socket rpcbind.service /run/spice-vdagentd/spice-vdagent-sock spice-vdagentd.socket spice-vdagentd.service /run/systemd/coredump systemd-coredump.socket /run/systemd/journal/dev-log systemd-journald-dev-log.socket systemd-journald.service /run/systemd/journal/socket systemd-journald.socket systemd-journald.service /run/systemd/journal/stdout systemd-journald.socket systemd-journald.service /run/udev/control systemd-udevd-control.socket systemd-udevd.service [::]:9090 cockpit.socket cockpit.service audit 1 systemd-journald-audit.socket systemd-journald.service kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service route 1361 systemd-networkd.socket systemd-networkd.service
18 sockets listed. Pass --all to see loaded but inactive sockets, too. |
我们当前运行在 graphical.target 下,它由一个长长的依赖列表(上图并未展示所有的项目),其中最重要的依赖项目为 multi-user.target。下面我们使用 --reverse 选项查看 multi-user.target unit 被谁使用:
[root@desktop ~]# systemctl list-dependencies multi-user.target --reverse multi-user.target ● └─graphical.target [root@desktop ~]# systemctl get-default graphical.target |
从上面两条命令的执行结果上我们可以确定下面的关系:graphical.target 依赖 multi-user.target。
我们这里只是通过 target unit 介绍了如何查看 unit 之间的依赖关系,实际使用中更多的是检查服务 unit 之间的依赖关系。
daemon-reload 是一个很容易被误用的子命令,主要是因为它名字中包含的 daemon 一词很容易让它和 reload 子命令混淆。
我们在前文简略的介绍了 reload 子命令,它的作用是重新加载某个服务程序的配置文件。这里的程序指的是服务类型 unit 的配置中指定的程序,也就是我们常说的 daemon(提供某种服务的应用程序)。比如服务类型的 unit prometheus.service,提供服务的 daemon 程序在我的机器上是 /usr/local/share/prometheus/prometheus,所以 reload 子命令重新加载的是 prometheus 的配置文件。
如果把 daemon-reload 子命令中的 daemon 理解为 systemd 程序,就可以把这个命令解释为重新加载 systemd 程序的配置文件。而所有的 unit 配置文件都是作为 systemd 程序的配置文件存在的。这样得出的结论就是:
新添加 unit 配置文件时需要执行 daemon-reload 子命令
有 unit 的配置文件发生变化时也需要执行 daemon-reload 子命令
daemon-reload 命令会做很多的事情,其中之一是重新生成依赖树(也就是 unit 之间的依赖关系),所以当你修改了 unit 配置文件中的依赖关系后如果不执行 daemon-reload 命令是不会生效的。
# whereis systemd
systemd: /usr/lib/systemd /etc/systemd /usr/share/systemd /usr/share/man/man1/systemd.1.gz
# whereis systemctl
systemctl: /usr/bin/systemctl /usr/share/man/man1/systemctl.1.gz
# ps -eaf | grep [s]ystemd
root 1 0 0 16:27 ? 00:00:00 /usr/lib/systemd/systemd --switched-root --system --deserialize 23
root 444 1 0 16:27 ? 00:00:00 /usr/lib/systemd/systemd-journald
root 469 1 0 16:27 ? 00:00:00 /usr/lib/systemd/systemd-udevd
root 555 1 0 16:27 ? 00:00:00 /usr/lib/systemd/systemd-logind
dbus 556 1 0 16:27 ? 00:00:00 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation
注意:systemd作为父守护进程运行(PID = 1)。 在上面的命令ps中使用(-e)选择所有进程,( - a)选择除会话前导之外的所有进程和(-f)选择完整格式列表(即-eaf)。
另请注意上面示例中的方括号以及其他示例。 Square Bracket表达式是grep的字符类模式匹配的一部分。
# systemd-analyze
Startup finished in 1.487s (kernel) + 3.196s (initrd) + 3min 5.930s (userspace) = 3min 10.614s
graphical.target reached after 5.831s in userspace
打印所有运行单元,按它们初始化的时间排序。此信息可用于优化启动时间。注意,输出可能具有误导性,因为一个服务的初始化可能非常缓慢,因为它等待另一个服务的初始化完成
# systemd-analyze blame
8.565s mariadb.service
7.991s webmin.service
6.095s postfix.service
4.311s httpd.service
3.926s firewalld.service
3.780s kdump.service
3.238s tuned.service
1.712s network.service
1.394s lvm2-monitor.service
1.126s systemd-logind.service
....
# systemd-analyze critical-chain
The time when unit became active or started is printed after the "@" character.
The time the unit took to start is printed after the "+" character.
graphical.target @5.831s
└─network.service @2min 18.043s +1.117s
└─vmware-tools.service @1.995s +2.029s
└─basic.target @1.719s
└─sockets.target @1.719s
└─cockpit.socket @1.693s +25ms
└─sysinit.target @1.691s
└─systemd-update-utmp.service @1.681s +9ms
└─auditd.service @1.680s
└─systemd-tmpfiles-setup.service @1.570s +23ms
└─local-fs.target @1.567s
└─run-media-root-Kylin\x2dServer\x2d10.mount @1min 16.009s
└─local-fs-pre.target @1.319s
└─lvm2-monitor.service @206ms +1.112s
└─lvm2-lvmetad.service @287ms
└─lvm2-lvmetad.socket @196ms
└─system.slice
└─-.slice
重要:Systemctl接受服务(.service),挂载点(.mount),套接字(.socket)和设备(.device)作为单位。
systemd-run 可以将一个指定的操作变成后台运行的服务。它的效果似乎与直接在命令后加上表示后台运行的 & 符号很相似。然而,它让命令成为服务还意味着,它的生命周期将由 Systemd 控制。具体来说,包括以下好处:
服务的生命击期由 Systemd 接管,不会随着启动它的控制台关闭而结束
可以通过 systemctl 工具管理服务的状态
可以通过 journalctl 工具查看和管理服务的日志信息
可以通过 Systemd 提供的方法限制服务的 CPU、内存、磁盘 IO 等系统资源的使用情况。
1. 什么是守护进程
Linux服务器的主要任务就是为本地或远程用户提供各种服务。通常Linux系统上提供服务的程序是由运行在后台的守护进程(Daemon)来执行。一个实际运行中的Linux系统一般会有多个这样的程序在运行。这些后台守护进程在系统开机后就运行了,并且在时刻地监听前台客户地服务请求,一旦客户发出了服务请求,守护进程便为它们提供服务。Windows系统中的守护进程被称为“服务”。
按照服务类型,守护进程可以分为如下两类:
系统守护进程:如crond(周期任务)、rsyslogd(日志服务)、cpus等;
网络守护进程:如sshd、httpd、xinetd(托管)等。
2. 什么是守护进程
系统初始化进程是一个特殊的的守护进程,其PID为1,它是所有其他守护进程的父进程或者祖先进程。也就是说,系统上所有的守护进程都是由系统初始化进程进行管理的(如启动、停止等)。
在Linux的发展历史过程中,使用过3种Linux初始化系统。
SysVinit
为 UNIX System V 系统创建的;
RHEL/CentOS 5及之前的版本一直使用。
Upstart
由Ubuntu创建的;
RHEL/CentOS 6 使用Upstart。
Systemd
先进的初始化系统;
RHEL/CentOS 7使用Systemd。
如果用两个比喻来形容两类守护进程的话,一般会用银行的业务处理窗口来类比:
独立启动守护进程:银行里有一种单服务的窗口,像取钱,存钱等窗口,这些窗口边上始终会坐着一个人,如果有人来取钱或存钱,可以直接到相应的窗口去办理,这个处理单一服务的始终存在的人就是独立启动的守护进程。
超级守护进程:银行里还有一种窗口,提供综合服务,像汇款,转账,提款等业务;这种窗口附近也始终坐着一个人(xinet),她可能不提供具体的服务,提供具体服务的人在里面闲着聊天啊,喝茶啊,但是当有人来汇款时他会大声喊一句,小王,有人汇款啦,然后里面管汇款的小王会立马跑过来帮忙办完汇款业务。其他的人继续聊天,喝茶。这些负责具体业务的人我们就称之为超级守护进程。当然可能汇款人会有一些规则,可能不能往北京汇款,他就会提早告诉xinet,所以如果有人来汇款想汇往北京的话,管理员就直接告诉他这个我们这里办不到的,于是就根本不会去喊汇款员了,相当于提供了一层管理机制。
针对这种窗口还存在多线程和单线程的区别:
多线程:将所有用户的要求都提上来,里面的人都别闲着了,都一起干活吧;
单线程:大家都排好队了,一个一个来,里面的人同一时间只有一个人在工作。
1. 独立运行(stand-alone)的守护进程
独立运行的守护进程由init脚本负责管理,所有独立运行的守护进程的脚本在/etc/rc.d/init.d/目录下。系统服务都是独立运行的守护进程,包括syslogd和cron等。独立运行的守护进程的工作方式称做stand-alone,它是UNIX传统的C/S模式的访问模式。
2.xinetd模式运行独立的守护进程
从守护进程的概念可以看出,对于系统所要通过的每一种服务,都必须运行一个监听某个端口连接所发生的守护进程,这意味着资源浪费。为了解决这个问题,Linux引进了"网络守护进程服务程序"的概念。也就是xinted(extended internet daemon)。xinetd能够同时监听多个指定的端口,在接受用户请求时,它能够根据用户请求的端口的不同,启动不同的网络服务进程来处理这些用户请求。可以把xinetd看做一个管理启动服务的管理服务器,它决定把一个客户请求交给哪个程序处理,然后启动相应的守护进程。xinetd无时不在运行并监听它所管理的所有端口上的服务。当某个要连接它管理的某项服务的请求到达时,xinetd就会为该服务启动合适的服务器。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。