0
简介
1i1wxsrjp3i64012504214.png
systemd 是一种用于 Linux 操作系统的初始化系统和服务管理器,由 Lennart Poettering 主导开发并在 LGPL 2.1 及其后续版本许可证下开源发布。自 2010 年代中期以来,systemd 已经广泛被多数主流 Linux 发行版采用,如 Ubuntu、Fedora、openSUSE、Debian 和 CentOS/RHEL 7 及以后版本,作为默认的初始化系统取代了传统的 System V init 和 Upstart 等系统。
1
主要功能和特点
并行启动服务:systemd 引入了服务间的依赖关系管理,允许并行启动多个不相互依赖的服务,显著缩短了系统启动时间。
Unit 文件:每个系统资源(如服务、挂载点、设备、sockets、计时器等)都被定义为一个“单元”(Unit),并由一个相应的配置文件(Unit file)来描述。这些文件通常位于 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目录下,拥有 .service、.socket、.target 等后缀。
依赖关系管理:systemd 允许精确地定义服务之间的依赖关系,确保服务按照正确的顺序启动或停止。
系统目标(Targets):类似于 System V init 的运行级别,但更加灵活,代表一组服务的集合,定义了系统的某种运行状态(如 multi-user.target 对应传统的运行级别3)。
journal 日志:systemd 提供了一个名为 journal 的日志系统,用于收集和查看系统日志,支持快速过滤和查询。
Socket 激活:服务可以根据实际需求(如客户端连接)动态激活,而不是一直运行等待请求,提高了资源利用率。
环境变量与资源限制:Unit 文件中可以设定服务的环境变量、资源使用限制(如内存、CPU时间)等。
用户服务:除了系统级别的服务外,systemd 还支持用户级别的服务,通过 user@.service 类型的单元。
网络命名和管理:systemd 提供了一个叫做 networkd 的组件,用于网络接口的配置和管理。
系统状态与管理工具:systemctl 命令是与 systemd 交互的主要工具,用于启动、停止、重启服务,查看服务状态,管理系统目标等。
[/ol]
2
原理概述
1.Systemd 初始化过程:
当 Linux 系统启动时,内核会加载并执行第一个用户空间程序,即 systemd。它作为 PID 1 运行,是所有其他进程的父进程。
systemd 首先读取配置文件(通常是 /etc/systemd/system 和 /usr/lib/systemd/system 中的 .service 文件),解析系统服务的依赖关系,并基于此构建一个启动图。
它按照依赖顺序并行或顺序地启动服务,这大大提高了系统的启动速度。
2.Service Unit 文件:
每个服务由一个单元文件(Unit File)定义,通常位于 /etc/systemd/system/ 或 /usr/lib/systemd/system/ 目录下,以 .service 扩展名结尾。
这些文件包含了服务的各种属性,如执行命令、依赖关系、重启行为、环境变量等。
3.systemctl 命令功能:
systemctl 允许用户与 systemd 交互,对服务进行管理,包括但不限于启动、停止、重启、查看状态、设置开机启动等操作。
它通过与 systemd 的 D-Bus 接口通信来发送指令,实现对服务单元的控制。
4.systemctl 命令处理流程:
当用户执行 systemctl start example.service 时,systemctl 会通过 D-Bus 向 systemd 发送一个请求,要求启动名为 example.service 的服务。
systemd 根据服务的配置文件和当前系统状态来决定如何处理这一请求,比如检查服务的依赖是否已经就绪,然后执行相应的启动脚本。
如果启用了日志记录,systemd 会通过 journalctl 记录服务的启动过程和输出,便于后续的故障排查。
5.启用与禁用服务:
使用 systemctl enable example.service 命令,实际上是在系统默认的启动目标(如 multi-user.target)的配置链接到服务单元文件。这意味着系统启动时,该服务会被自动启动。
相反,systemctl disable example.service 则移除这些链接,服务不再自动启动,但仍然可以通过 systemctl start 手动启动。
6.Cgroups 和命名空间:
systemd 使用控制组(Control Groups, cgroups)来跟踪和限制服务资源使用,以及命名空间(Namespaces)来隔离服务的视图,如文件系统、网络栈等,增强了系统的安全性和资源管理能力。
通过上述机制,systemctl 和 systemd 一起提供了强大且灵活的系统服务管理功能,提升了系统的响应速度和管理效率。
3
设计单元unit
systemd 设计的单元(Units)是用于描述系统资源和服务的配置文件,它们代表了systemd可以管理的各种不同类型的对象。这些单元类型允许systemd根据配置来启动、停止、重启或管理相应的系统组件。以下是systemd支持的主要单元类型分类:
服务单元 (.service):这是最常用的单元类型,用于定义系统服务,如守护进程(daemon)及其相关进程。服务单元控制着服务的启动、停止、重载等操作。
套接字单元 (.socket):用于管理系统中的本地IPC(进程间通信)或网络套接字,支持基于套接字激活服务,即当套接字上有连接请求时自动启动相应服务。
目标单元 (.target):作为一组单元的集合,用于定义系统状态或运行级别,如多用户目标(multi-user.target)或图形界面目标(graphical.target)。切换目标实际上就是启动或停止与该目标相关联的一组服务。
设备单元 (.device):代表系统中的硬件设备,可以用于基于设备的激活,即当设备接入或移除时执行特定操作。
挂载单元 (.mount):控制文件系统的挂载点,定义如何以及何时挂载或卸载文件系统。
路径单元 (.path):监控文件或目录的存在、不存在、修改等变化,并基于这些变化触发动作。
计时器单元 (.timer):用于定义定时任务,可以在特定的时间间隔执行其他单元。
交换单元 (.swap):管理交换分区或文件,控制交换空间的启用和禁用。
自动挂载点单元 (.automount):用于自动挂载文件系统,当访问到挂载点时才实际挂载,不访问时自动卸载,节省资源。
Snapshot 单元 (.snapshot):用于保存和恢复系统状态快照,是系统状态的即时备份,可用于快速回滚。
Slice 单元 (.slice):用于组织和管理cgroup层级,控制资源分配,特别是对于一组相关的进程。
[/ol]
这些单元通过它们的配置文件来定义,并且systemd通过解析这些文件来确定如何处理不同的系统组件和服务。每个单元类型都服务于特定的系统管理目的,共同构建了一个强大且灵活的初始化系统和服务管理框架。
服务单元service
一个典型的.service服务单元文件示例是管理SSH服务的配置文件。SSH服务允许用户通过加密的网络连接远程登录系统。下面是一个简化版的ssh.service服务单元文件示例,通常位于/usr/lib/systemd/system/ssh.service或/etc/systemd/system/ssh.service:
[Unit]Description=OpenSSH server daemonAfter=network.target auditd.service
[Service]Type=notifyExecStart=/usr/sbin/sshd -D $OPTIONSExecReload=/bin/kill -HUP $MAINPIDKillMode=processRestart=on-failureRestartSec=42s
[Install]WantedBy=multi-user.target
这个文件分为三个部分:
1.[Unit]部分:描述了单元的元数据和依赖关系。
- Description=:简述服务的功能。
- After=:定义此服务应该在哪些服务启动后才启动,这里指定了网络必须先启动,以及auditd服务(如果启用)。
2.[Service]部分:定义了服务的具体行为。
- Type=:定义服务的类型,notify表示服务会在启动后通知systemd其启动状态。
- ExecStart=:指定启动服务的命令行。
- ExecReload=:指定重新加载服务配置的命令。
- KillMode=:指定systemd如何终止服务的进程。
- Restart=:定义服务失败后是否以及如何重启,这里是on-failure表示仅在失败时重启。
- RestartSec=:重启前等待的秒数。
3.[Install]部分:定义了如何将服务安装到系统中,即决定服务应该在哪种系统目标(target)下启用。
- WantedBy=:声明此服务希望被包含在multi-user.target中,这意味着SSH服务在多用户、无图形界面的系统状态中自动启动。
通过这个服务单元文件,systemd知道如何控制SSH服务的启动、停止、重启以及如何响应服务的失败情况,从而实现了对SSH服务的精细管理。
套接字单元.socket
2rcqr0qajgt64012504314.png
一个套接字单元(.socket)的用例是用于配置监听特定网络端口或Unix域套接字的服务,以便当有连接请求到达时自动激活相应的服务单元。这有助于减少资源消耗,因为服务只有在真正需要时才启动。下面是一个简单的HTTP服务(例如使用nginx作为Web服务器)的套接字单元示例,文件可能位于/etc/systemd/system/nginx.socket:
[Unit]Description=nginx Web Server Socket
[Socket]ListenStream=80Accept=yes
[Install]WantedBy=sockets.target这个.socket单元的各部分解释如下:
1.[Unit]部分:描述了单元的基本信息。
- Description=:说明这个套接字单元的功能,这里是为nginx Web服务器配置监听套接字。
2.[Socket]部分:定义了套接字的具体配置。
- ListenStream=:指定监听的TCP端口,在这个例子中是80端口,用于HTTP服务。
- Accept=yes:指示systemd接受传入的连接,并根据关联的服务单元自动启动服务。
3.[Install]部分:定义了如何将套接字单元安装到系统中。
- WantedBy=sockets.target:表明这个套接字单元应该在sockets.target下启用,这是systemd默认启动的一部分,意味着系统启动时就会开始监听这个端口。
配合这个.socket单元,还需要一个对应的服务单元(通常是.service),例如nginx.service,来定义当套接字接收连接时应执行的服务启动命令。在服务单元中,通常会使用Socket=指令来引用相应的套接字单元,以确保服务只在有实际连接请求时被激活。这样,当有HTTP请求到达80端口时,systemd会自动启动或唤醒nginx.service来处理请求,提高了资源的使用效率。
目标单元.target
一个目标单元(.target)的例子是multi-user.target,它是systemd中一个非常基础且常用的目标,代表了多用户、非图形界面的系统运行状态。这个目标意味着系统已经完成了初始化并准备好了 shell 接入和其他多用户服务,但没有启动图形桌面环境。许多服务器系统默认启动到这个目标。
multi-user.target并不需要一个显式的单元文件来定义,因为它是systemd内部预设的目标之一,但理解其概念和用途是非常重要的。下面简要概述其行为,虽然实际中你可能不会直接编辑一个multi-user.target的配置文件,但可以通过查看其依赖关系来理解它所包含的服务:
[Unit]Description=Multi-User SystemDocumentation=man:systemd.special(7)Requires=basic.targetConflicts=rescue.service rescue.targetAfter=sysinit.target basic.targetAllowIsolate=yes这段描述是示意性的,说明了multi-user.target的一些关键属性:
- Description:简短描述目标,这里是“多用户系统”。
- Requires:列出该目标依赖的基本目标,如basic.target,表示在达到multi-user.target之前,basic.target必须已经启动完成。
- Conflicts:定义了与该目标冲突的服务或目标,如救援模式的服务和目标。
- After:指明该目标应当在哪些目标之后启动,确保了系统的有序启动。
- AllowIsolate:允许使用systemctl isolate multi-user.target命令直接切换到此目标。
当系统启动并指定了multi-user.target作为默认目标时,systemd会启动所有依赖于multi-user.target的服务单元,如SSH服务、数据库服务、Web服务器等,但不包括X Window系统或GNOME、KDE等桌面环境服务。这对于大多数服务器场景是理想的,因为它减少了不必要的图形界面资源消耗。
设备单元.device
设备单元(.device)是systemd用于管理系统中的硬件设备的配置单元。这些单元自动由udev规则创建,并且可以用来基于设备的状态变化(如插入或移除)执行动作。下面是一个简单的设备单元示例,假设我们要为一个特定的USB存储设备定义一些自动化行为,这个设备单元可能被命名为/etc/systemd/system/usb_storage_device.device:
[Unit]Description=USB Storage DeviceWants=usb_storage.mount
[Device]KernelMatchSubsystem=blockKernelMatchAttributes=idVendor=1234,idProduct=5678
[Install]WantedBy=dev-block-sda.device在这个例子中,设备单元定义了以下内容:
1.[Unit]部分:
- Description=:描述了设备单元的功能,这里是识别一个USB存储设备。
- Wants=:声明当此设备被激活时,也应启动或激活usb_storage.mount单元,即自动挂载该设备。
2.[Device]部分:
- KernelMatchSubsystem=:匹配内核设备子系统,这里是block,意味着块设备,涵盖了硬盘、USB存储等。
- KernelMatchAttributes=:使用udev属性来精确匹配设备,如供应商ID(idVendor)和产品ID(idProduct),这里假定为虚构的值,实际使用时需要根据具体设备查询并替换。
3.[Install]部分:
- WantedBy=:指定这个设备单元应该在哪个设备单元激活时启动。在这个例子中,它与特定的设备文件(如sda)相关联,意味着当该设备被系统识别时,这个设备单元将被激活。
通过这样的设备单元配置,当系统检测到符合特定条件的USB存储设备插入时,systemd可以自动挂载它,或者执行其他定义好的操作,提供了对硬件事件响应的自动化机制。
挂载单元mount
挂载单元(.mount)用于定义文件系统的挂载点及其挂载参数。这些单元允许systemd在系统启动时自动挂载文件系统,并能够管理这些挂载点的生命周期。下面是一个挂载单元的例子,用于自动挂载一个名为data-disk的硬盘分区到/mnt/data目录:
[Unit]Description=Mount for Data DiskBefore=local-fs.target
[Mount]What=/dev/disk/by-label/data-diskWhere=/mnt/dataType=ext4Options=noatime,nodiratime
[Install]WantedBy=multi-user.target
这个.mount单元的各个部分说明如下:
1.[Unit] 部分:
- Description=:描述挂载单元的功能,这里是用于数据磁盘的挂载点。
- Before=:定义此挂载操作应在local-fs.target之前完成,确保文件系统挂载的正确顺序。
2.[Mount] 部分:
- What=:指定要挂载的设备或设备标识符。这里使用了/dev/disk/by-label/data-disk,意味着是通过磁盘标签来标识设备,这种方式比直接使用设备节点更健壮,不易受设备名变动影响。
- Where=:指定挂载点目录,这里是/mnt/data。
- Type=:指定文件系统的类型,这里是ext4。
- Options=:挂载选项,noatime和nodiratime告诉系统不要更新文件或目录的最后访问时间戳,可以减少I/O操作,提高性能。
3.[Install] 部分:
- WantedBy=:声明这个挂载单元应该在multi-user.target目标下启动,意味着在多用户、非图形界面的系统状态下自动挂载这个文件系统。
通过这个挂载单元配置,每当系统进入multi-user.target状态时,systemd会自动挂载标签为data-disk的硬盘分区到/mnt/data目录,且遵循指定的挂载选项。
路径单元path
路径单元(.path)用于监控文件或目录是否存在、是否发生变化,然后基于这些变化来触发其他单元的操作。下面是一个路径单元的例子,用于监控日志目录/var/log/app_logs下是否有新创建的日志文件,并在检测到新文件时重新加载app_logger.service服务,以确保日志服务能处理新的日志条目:
[Unit]Description=Watch for new log files in /var/log/app_logs
[Path]PathModified=/var/log/app_logs/*.log
[Install]WantedBy=multi-user.target这个.path单元的各部分含义如下:
1.[Unit] 部分:
- Description=:简述路径单元的作用,这里是监控特定目录下的日志文件变化。
2.[Path] 部分:
- PathModified=:指定要监控的路径及其模式。这里使用通配符*.log来监控/var/log/app_logs目录下所有.log文件的修改。当这些日志文件被创建或修改时,systemd会触发关联的动作。
3.[Install] 部分:
- WantedBy=:声明此路径单元应该在multi-user.target下启动,意味着在多用户、无图形界面的系统状态下启用此监控。
为了完整实现上述功能,还需要一个服务单元(.service)与之关联,比如app_logger.service,并且在该服务单元中使用适当的配置来响应路径单元触发的事件。例如,服务单元中可能会包含ExecReload指令来定义当路径单元触发时执行的重载命令。这样,一旦/var/log/app_logs目录中有新的日志文件生成或修改,systemd就会自动重新加载app_logger.service,确保日志处理逻辑能够及时处理新日志。
计时器单元timer
o1vumws0yqo64012504415.png
计时器单元(.timer)在Systemd中用于安排服务单元或其他单元按指定的时间计划执行。下面是一个.timer单元的例子,该例设置了一个每天凌晨3点执行一次清理缓存任务的服务。
首先,需要有一个服务单元(如cache-cleanup.service),定义实际执行的任务:
[Unit]Description=Cleanup Cache Files
[Service]Type=oneshotExecStart=/usr/local/bin/cleanup_cache.sh在这个例子中,cleanup_cache.sh是一个脚本,负责执行实际的缓存清理操作。
接下来是对应的计时器单元(cache-cleanup.timer),用于定时触发上述服务:
[Unit]Description=Daily Cache Cleanup Timer
[Timer]OnCalendar=*-*-* 03:00:00 # 每天凌晨3点执行Persistent=true # 如果错过执行时间,在下次机会立即执行AccuracySec=1min # 执行时间的精度,这里设置为1分钟
[Install]WantedBy=timers.target[Timer]部分的设置解释如下:
- OnCalendar=*-*-* 03:00:00:定义了执行时间,这里设置为每天的03:00:00(即凌晨3点整)。
- Persistent=true:如果因为系统关闭或计时器未激活而错过了执行时间,那么在系统下次启动或计时器被激活时立即执行。
- AccuracySec=1min:指定了执行时间的容忍度,即计时器触发的实际时间可能与设定时间最多相差的时间,这里是1分钟。
最后,通过[Install]部分的WantedBy=timers.target,确保此计时器在系统启动时被启用。
要使这个计时器生效,你需要通过Systemd的命令行工具进行启用和启动操作:
sudo systemctl enable cache-cleanup.timersudo systemctl start cache-cleanup.timer这样设置后,每天凌晨3点,cleanup_cache.service就会自动执行,完成缓存清理任务。
slice单元
Slice单元(.slice)在Systemd中用于组织和管理一组相关进程的资源分配,特别是通过Linux控制组(cgroups)来实现对CPU、内存等资源的限制。下面是一个Slice单元的例子,展示了如何创建一个名为user-1000.slice的Slice,用于管理属于用户UID 1000的进程,并设置一些资源限制:
示例:用户 Slice 单元 (user-1000.slice)
[Unit]Description=Slice for User with ID 1000
[Slice]MemoryMax=500M # 限制该Slice内所有进程的总内存使用量不超过500MBCPUQuota=20% # 限制该Slice内所有进程的CPU使用率不超过20%在这个例子中,.slice单元定义了几个关键的资源限制:
MemoryMax=500M:设置了该Slice内所有进程可使用的最大内存总量为500MB。
CPUQuota=20%:限制了该Slice内所有进程可使用的CPU时间比例,不超过单个CPU核心20%的计算能力。
[/ol]创建这样一个Slice单元后,可以通过将用户会话或者特定服务绑定到这个Slice中,来实现对这些进程资源使用的集体管理。例如,你可以通过修改用户的登录服务(假设为user@.service模板实例)来指定Slice:
# 在相应的用户服务单元(如默认的getty服务)中[Unit]...PartOf=user-1000.slice
[Service]...或者,如果要手动将一个已运行的进程移动到该Slice,可以使用systemctl set-property命令调整其控制组归属:
sudo systemctl set-property --user my_service.service Slice=user-1000.slice4
配置文件
systemd 的配置文件主要是单元(Unit)文件,这些文件定义了系统如何管理不同的实体,如服务、挂载点、设备、sockets、计时器等。以下是几个主要的目录及其用途:
1./etc/systemd/system/:此目录存放系统管理员自定义或修改的单元文件,以及通过软链接指向/lib/systemd/system/或其他地方的默认单元文件。管理员在这里放置的文件优先级最高,可以覆盖默认设置。开机启动服务的配置通常通过在此目录创建软链接到实际的单元文件实现。
wfjxtycb4sj64012504515.png
2./usr/lib/systemd/system/:这个目录包含所有预装服务的默认单元文件。这些是由软件包安装时提供的,代表了服务的标准配置。它们的优先级低于/etc/systemd/system/目录中的文件。
kff0hv5qzx164012504615.png
3.run/systemd/system/:此目录用于存放系统运行过程中动态生成的服务脚本或临时修改的单元文件,这些变化不会永久保存。这个目录的优先级高于上述两个目录,意味着这里的配置会覆盖任何静态配置。
fdlkfappwyt64012504715.png
4。/usr/local/lib/systemd/system/:某些本地编译安装的软件可能会将服务单元文件放在这里,优先级介于/usr/lib/systemd/system/和/etc/systemd/system/之间。
理解这些目录的关键在于它们的优先级和用途:
lib/systemd/system/ 和 /usr/local/lib/systemd/system/ 存放的是系统或本地安装的服务的标准配置。
/etc/systemd/system/ 用于系统管理员进行定制化配置,可以覆盖默认设置。
/run/systemd/system/ 则用于临时性的、即时生效的配置更改,适合在不希望永久改变配置时使用。
[/ol]
通过这些目录的组织,systemd 允许系统管理员灵活地调整服务管理配置,同时保持了配置文件的清晰结构和可维护性。
5
常用命令
systemctl 是 Systemd 系统和服务管理器的主要命令行接口,它提供了一个统一的方式来管理 Linux 系统中的各种服务、系统状态、以及相关的系统组件。
5qh3znkv0nh64012504816.png
1.服务管理:
- 启动服务:使用 systemctl start 命令启动指定的服务。
- 停止服务:使用 systemctl stop 停止指定的服务。
- 重启服务:使用 systemctl restart 重启服务。
- 查看状态:通过 systemctl status 查看服务当前状态。
2.开机启动管理:
- 启用服务:systemctl enable 设置服务为开机启动。
- 禁用服务:systemctl disable 取消服务的开机启动设置。
3.系统状态查询:
- 列出所有单元:systemctl list-units 显示当前活跃的单元(服务、挂载点、sockets等)。
- 查看单元文件状态:systemctl list-unit-files 显示所有单元文件的状态(是否启用)。
4.时间安排与定时任务:
- 计时器单元:通过 .timer 单元定义定时任务,如 systemctl start mytimer.timer。
5.资源管理:
- Slice 单元:通过 .slice 单元组织和管理资源分配给一组进程。
- 资源限制:可以在 Slice 或服务单元中设置 CPU、内存等资源限制。
6.系统控制:
- 关机、重启:systemctl poweroff 关闭系统,systemctl reboot 重启系统。
- 目标管理:切换系统运行级别,如 systemctl isolate multi-user.target 进入多用户命令行模式。
7.日志查看:
- 服务日志:使用 journalctl -u 查看服务的日志输出。
8.配置重载:
- 重载配置:systemctl daemon-reload 重新加载 systemd 的配置文件,确保改动生效。
6
小结
systemd 作为一个全面的系统和服务管理框架,通过其高度集成的设计和丰富的功能集,为 Linux 系统带来了更快的启动速度、更高的服务管理效率和更细致的系统控制能力。尽管它的引入曾引发过争议,但随着其在各大发行版中的广泛应用,systemd 已成为现代 Linux 系统服务管理的重要组成部分。
end
一口Linux
关注,回复【1024】海量Linux资料赠送
精彩文章合集
文章推荐
?【专辑】ARM?【专辑】粉丝问答?【专辑】所有原创?【专辑】linux入门?【专辑】计算机网络?【专辑】Linux驱动?【干货】嵌入式驱动工程师学习路线?【干货】Linux嵌入式所有知识点-思维导图 |