Linux 下服务管理命令 systemctl 详解

对于Linux用户而言,systemctl想必并不陌生。在管理服务时,它堪称首选命令,启动、停止服务或是查看服务状态,都不在话下。然而,实话实说,倘若仅使用这些基础功能,那不过是触及了systemctl的冰山一角。不妨将systemctl比作一部智能手机,你若仅用它来打电话,便会错过其蕴藏的诸多强大功能。

在本文中,我们将深入探索,解锁高级技术与工具,大幅提升你的服务管理技能,这些技术远超基础操作范畴。准备好开启升级之旅了吗?让我们即刻出发!

一、systemd概述

Systemd是Linux系统中最新一代的初始化系统(init)。其核心设计目标在于克服sysvinit与生俱来的缺陷,显著提升系统启动速度,为系统启动与管理构建一套完备的解决方案。依照Linux的惯例,字母d是守护进程(daemon)的缩写。Systemd这一命名,寓意着它将守护整个系统。

采用Systemd后,便无需再使用init。Systemd取代了initd,成为系统的首个进程(进程ID为1),其他进程皆为其子进程。我们可通过以下命令查看Systemd的版本:

# systemctl --version

systemd 219
+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN

Systemd的优势在于功能极为强大,使用便捷;缺点则是体系庞大复杂。实际上,至今仍有不少人反对使用systemd,原因就在于其过度复杂,与操作系统的其他部分紧密耦合,背离了“保持简单,保持愚蠢”的http://www.ruanyifeng.com/blog/2009/06/unix_philosophy.html

Linux服务结构

二、systemctl命令简介

systemctl作为Systemd的核心命令,肩负着管理系统的重任。从功能层面来看,systemctl整合了servicechkconfig这两个命令的功能:

任务 旧指令 新指令
使某任务自动启动 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

三、systemctl 常用命令

  1. 查看服务状态:

    • systemctl status <service>:显示指定服务的运行状态、日志信息和依赖关系。
    • systemctl is-active <service>:检查指定服务是否处于激活状态(运行中)。
    • systemctl is-enabled <service>:检查指定服务是否已启用(将在系统引导时自动启动)。
    • systemctl is-failed <service>:检查指定服务是否处于失败状态。
  2. 管理服务:

    • systemctl start <service>:启动指定服务。
    • systemctl stop <service>:停止指定服务。
    • systemctl restart <service>:重新启动指定服务。
    • systemctl reload <service>:重新加载指定服务的配置文件。
    • systemctl enable <service>:启用指定服务,使其在系统引导时自动启动。
    • systemctl disable <service>:禁用指定服务,使其不会在系统引导时启动。
  3. 管理服务单元:

    • systemctl list-units:列出所有已知的服务单元并显示其当前状态。
    • systemctl list-unit-files:列出所有已安装的服务单元文件。
    • systemctl show <unit>:显示指定服务单元的详细信息。
  4. 系统操作:

    • systemctl poweroff:关闭系统。
    • systemctl reboot:重启系统。
    • systemctl suspend:将系统置于挂起状态(睡眠模式)。
    • systemctl hibernate:将系统置于休眠状态(保存当前状态到磁盘)。
  5. 日志查询:

    • systemctl status <service/unit>.service:显示服务或单元的当前状态和日志。
    • journalctl -u <service/unit>.service:查看指定服务或单元的日志。

四、为何仅依赖systemctl远远不够

首先需要明确,systemctl无疑是一款极为强大的工具。对于简单任务而言,它表现得游刃有余。然而,倘若你仅仅利用它来启动和停止服务,那么你将错失systemd潜藏的全部巨大潜能。下面为你揭示那些被忽略的关键方面:

  1. 可见性受限systemctl status能够提供某个瞬间的状态快照,但当你需要实时更新信息或者查阅历史日志时,它便显得力不从心了。
  2. 日志功能基础:虽然journalctl能够提供帮助,但其操作较为复杂。例如,如何依据时间、服务类别或者错误类型对日志进行精准过滤呢?
  3. 手动操作负担重:怎样实现任务自动化,或者在无需人工干预的情况下妥善处理服务故障呢?

接下来,让我们借助高级技术,将你的服务管理水平提升到全新高度,使你宛如一位Linux高手。

1. 借助journalctl精通日志管理

若你仅仅依靠systemctl status <service>来排查问题,那么你便遗漏了一个极为强大的工具——journalctl。该命令能够为你呈现来自systemd日志的详尽记录,其中存储着所有系统和服务的日志信息。journalctl堪称systemctl最佳搭档,它为你打开了系统日志的大门,然而大多数人并未充分挖掘其价值。

  • 它允许你按照服务、时间或者日志严重程度对日志进行筛选,从而让你在故障排查过程中拥有更强的掌控力。
  • 它有助于你探寻服务失败的根本原因,不仅能够展示服务自身的输出,还能呈现依赖项或者相关服务的日志。

按服务过滤日志

倘若你期望查看特定服务的日志,可使用以下命令:

sudo journalctl -u <service - name>

实时日志跟踪

通过添加-f标志,你能够实时跟踪日志

sudo journalctl -u <service - name> -f

按时间范围过滤

想要查看过去一小时的日志、特定日期范围内的日志,亦或是仅查看最近的日志?方法如下:

sudo journalctl --since "1 hour ago"
sudo journalctl --since "2023 - 10 - 01" --until "2023 - 10 - 02"

导出日志用于分析

你还可以将日志导出至文件,以便进行离线分析:

sudo journalctl -u <service - name> > service - logs.txt

2. 深度挖掘systemctl的潜能

在深入探讨其他工具之前,我们先来确保你充分发挥systemctl的作用。这里有一些你可能尚未知晓的隐藏功能

列出所有服务

你能够列出系统中的所有服务,包括已禁用或静态的服务,命令如下:

systemctl list-units --type=service --all

检查服务依赖项

若想了解哪些其他服务依赖于特定服务,可尝试此命令:

systemctl list-dependencies <service-name>

屏蔽服务

要阻止服务启动,无论是手动启动还是自动启动,使用以下命令:

sudo systemctl mask <service-name>

模拟服务重启

若想了解重启服务时的情况,却又不想实际执行,可使用该命令:

sudo systemctl restart --dry-run <service-name>

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-01" --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的日志
sudo 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.service -o json-pretty


# 显示日志占据的硬盘空间
sudo journalctl --disk-usage

#指定日志文件占据的最大空间
sudo journalctl --vacuum-size=1G


# 指定日志文件保存多久
sudo journalctl --vacuum-time=1years

注: 默认情况下,Systemd将日志保存在/run/log/journal中,系统重启就会清除。通过新建/var/log/journal目录,日志会自动记录到这个目录中,并永久存储。

五、处理Unit配置文件

每个服务都有对应的Unit文件,它定义了服务的运行方式。这些文件存储位置因来源不同而异:系统提供的单元文件存于/lib/systemd/system/,用户提供的则存于/etc/systemd/system/

若要列出所有已安装的Unit文件,可使用:

systemctl list-unit-files --type=service

这会显示每个Unit的状态,如启用、禁用、静态等。

查看Unit文件详细信息

若想查看Unit文件的详细内容,运行:

systemctl cat <service-name>

要检查服务的依赖项,使用:

systemctl list-dependencies <service-name>

若想编辑Unit文件,可运行以下命令:

sudo systemctl edit <service-name>

这会创建一个覆盖文件,你可在其中调整单个设置,而无需修改原始单元文件。

创建自己的Unit文件

每一个Unit都有一个配置文件,告诉Systemd怎么启动这个Unit。Systemd默认从 /etc/systemd/system/目录读取配置文件。但是,里面存放的大部分文件都是符号链接,指向目录 /usr/lib/systemd/system/目录下的文件,因此真正的文件存放在那个目录下。

systemctl enable命令用于在上面两个目录之间建立符号链接关系:

# sudo systemctl enable [email protected]

//等价于
# sudo ln -s /usr/lib/systemd/system/[email protected] /etc/systemd/system/[email protected]

如果配置文件里面设置了开机启动,systemctl enable就相当于激活开机启动。与之对应的,systemctl disable命令用于在两个目录之间撤销符号链接关系,相当于撤销开机启动:

# sudo systemctl disable [email protected]

配置文件名称的后缀,就是该 Unit的种类,比如 sshd.socket。如果省略,Systemd默认后缀名为 .service。所以 sshd会被理解成 sshd.service

配置文件的状态

systemctl list-unit-files命令用于列出所有配置文件:

//列出所有配置文件
# systemctl list-unit-files
UNIT FILE                                   STATE   
proc-sys-fs-binfmt_misc.automount           static  
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  
brandbot.path                               disabled
cups.path                                   enabled 

//列出指定类型的配置文件
# systemctl list-unit-files --type=service

配置文件的状态有4种:

enabled:  已建立启动链接
disabled: 没建立启动链接
static: 该配置文件没有[Install]部分(无法执行),只能作为其他配置文件的依赖
masked: 该配置文件被禁止建立启动链接

注意,从配置文件的状态无法看出,该Unit是否正在运行。这必须执行前面提到的 systemctl status命令。

# systemctl status bluetooth.service

一旦修改配置文件,就要让 Systemd重新加载配置文件,然后重新启动,否则修改不会生效。

# sudo systemctl daemon reload
# sudo systemctl restart httpd.service

配置文件的格式

配置文件就是普通的文本文件,可以用文本编辑器打开。systemctl cat命令可以查看配置文件的内容:

[root@bogon ~]# systemctl cat mysqld
# /usr/lib/systemd/system/mysqld.service
# Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
#
# systemd service file for MySQL forking server
#

[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql

Type=forking

PIDFile=/var/run/mysqld/mysqld.pid

# Disable service start and stop timeout logic of systemd for mysqld service.
TimeoutSec=0

# Execute pre and post scripts as root
PermissionsStartOnly=true

# Needed to create system tables
ExecStartPre=/usr/bin/mysqld_pre_systemd

# Start main service
ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS

# Use this to switch malloc implementation
EnvironmentFile=-/etc/sysconfig/mysql

# Sets open_files_limit
LimitNOFILE = 5000

Restart=on-failure

RestartPreventExitStatus=1

PrivateTmp=false

从上面的输出可以看到,配置文件分成几个区块。每个区块的第一行,使用方括号表示的区的名称,比如 [Unit]。注意,配置文件的区块名和字段名都是 大小写敏感的。

每个区块内部是一些符号连接的键值对:

[Section]
Directive1=value
Directive2=value
...

注意: 键值对的等号两侧不能有空格。

配置文件的区块

1) 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运行必须满足的条件,否则会报启动失败

2) Install区块

[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

3) Service区块

[Service]区块用来Service的配置,只有service类型的unit才有本区块。它的主要字段如下:

Type: 定义启动时的进程行为。它有以下几种值:
      1) Type=simple  默认值,执行ExecStart指定的命令,启动主进程
      2) Type=forking  以fork方式从父进程创建子进程,创建后父进程会立即退出
      3) Type=oneshot 一次性进程,Systemd会等待当前服务退出,再继续往下执行
      4) Type=dbus  当前服务通过DBus启动
      5) Type=notify  当前服务启动完毕,会通知Systemd,再继续往下执行
      6) Type=idle 若有其他任务执行完毕,当前服务才会运行

ExecStart: 启动当前服务的命令

ExecStartPre: 启动当前服务之前执行的命令

ExecStartPost: 启动当前服务之后执行的命令

ExecReload: 重启当前服务执行时的命令

ExecStop: 停止当前服务时执行的命令

ExecStopPost: 停止当前服务之后执行的命令

RestartSec: 自动重启当前服务间隔的秒数

Restart: 定义何种情况下会自动重启当前服务,可能的值包括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
# 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进程主要存在以下差别:

  • 默认的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-analyze 加速启动时间

若系统启动缓慢,systemd-analyze是识别瓶颈、加快启动速度的绝佳工具。该命令能让你了解启动时间、服务启动性能以及可能拖慢系统的关键路径。

主要功能:

  • systemd-analyze blame:显示每个服务在启动期间花费的时间。这对于识别可能延迟系统启动的慢速服务非常有用。 systemd-analyze blame
  • systemd-analyze critical-chain:提供启动过程中涉及的服务的可视化分解及其依赖关系,帮助你查看是什么拖慢了系统。 systemd-analyze critical-chain

想要启动过程的可视化表示?使用:

systemd-analyze plot > boot-graph.svg

八、排查常见服务问题

有时,事情会出错,服务无法启动。

以下是排查方法:

服务无法重新加载

修改单元文件后, 始终重新加载 systemd 配置,然后再重启服务:

sudo systemctl daemon-reload
sudo systemctl restart <service-name>

未能重新加载 systemd 管理器可能导致更改未应用。

列出并检查失败的单元,请使用:

systemctl --failed

该命令帮助你快速识别失败的服务。然后你可以使用 journalctl -u <service-name> 检查它们的日志。

权限问题

以非 root 权限运行的服务可能无法访问某些资源。

始终确保你的服务文件和脚本具有正确的权限。

例如,如果你的服务需要访问 /var/log/myapp,请确保服务用户对该目录具有读/写权限:

sudo chown myuser:mygroup /var/log/myapp

环境变量

某些服务依赖于可能未正确设置的 环境变量

始终检查你运行的服务的文档,并确保所有必要的环境变量都在单元文件的 [Service] 部分中定义:

[Service]
Environment="MY_VAR=value"

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件举报,一经查实,本站将立刻删除。

文章由技术书栈整理,本文链接:https://study.disign.me/article/202511/11.linux-commands-systemctl.md

发布时间: 2025-03-12