0x00 Systemd 简述
1.Linux 启动流程
2.主角登场
0x01 Systemd Unit
1.配置文件
2.启动流程
3.进程树(Process tree)
4.运行级别
0x02 Systemd Manager
1.Systemctl 命令
2.Journal 命令
3.Systemd-analyze
0x03 补充知识
1.自定义服务单元
2.自定义配置
描述:系统启动和服务器守护进程管理器,负责在系统启动或运行时激活系统资源,并且管理服务器进程和其它进程,可以说他是Linux的小伙伴系统启动时候最先都是运行的systemd;
$ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 128204 5884 ? Ss 3月25 2:19 /usr/lib/systemd/systemd --switched-root --system --deserialize 22
描述:要想清楚 systemd 在 Linux 系统中的地位和作用,就不得不提一下 Linux 的启动流程;
Linux 从按下电源键到进入用户交互界面整个启动流程大致可以分为四个阶段:
BIOS 阶段: 基本的硬件自检准备以及加载 bootloader 程序;
BootLoader 阶段
kernel 加载阶段
init (systemd/sysvinit 初始化阶段
)
(1) BIOS 阶段
Step 1.在按下电源电源键(冷启动)后,CPU 的程序计数器被初始化为一个特定的內存地址
(所以没有 CPU 是无法启动主板上的 BIOS 的),存储在只读存储器(ROM)中的 BIOS 就是从这个特定的內存地址开始执行,值得注意的是对于嵌入式系统中的 CPU ,将会加载引导区去启动 flash/ROM 中已知地址的程序;
Step2.BIOS 启动后就开始执行硬件的基本初始化也称之为上电自检
,并根据引导设备的优先级将系统控制权交给硬件启动项(比如硬盘/网络/U盘等
),此阶段可以进行外部中断我们按下 F12 或者 ESC 键(根据主板芯片组而异)就会弹出选择启动项的界面,而且这些按键高度依赖硬件。
Step3.BIOS 选择好硬件启动项之后就开始执行硬件设备上的初级引导程序代码
,对于 MBR 硬盘来讲是最开始的一个扇区(512字节)將被加载到內存,並执行行其中的初始化代码来加载下一阶段的 Bootloader
PS:此处以MBR引导的系统记录为例,MBR 主引导记录是一个 512 字节的扇区,位于硬盘的第一扇区(0道0柱1扇区),对于 GPT/EFI 引导等有经验的时候再来讲解补充;
#dd 命令读取 MBR 主引导记录
dd if=/dev/sda of=mbr.bin bs=512 count=1
#od 命令来查看二进制文件
od -xa mbr.bin
# 0000000 63eb 0090 0000 0000 0000 0000 0000 0000
# k c dle nul nul nul nul nul nul nul nul nul nul nul nul nul
# 0000020 0000 0000 0000 0000 0000 0000 0000 0000
# nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
# *
# 0000120 0000 0000 0000 0000 0000 8000 0800 0000
# nul nul nul nul nul nul nul nul nul nul nul nul nul bs nul nul
# 0000140 0000 0000 faff 9090 c2f6 7480 f605 70c2
# nul nul nul nul del z dle dle v B nul t enq v B p
# 0000160 0274 80b2 79ea 007c 3100 8ec0 8ed8 bcd0
# t stx 2 nul j y | nul nul 1 @ so X so P <
(2) BootLoader 阶段
主引导记录加载完 Bootloader(主要为GRUB)到 RAM 中之后,GRUB 会根据需求显示一个可用的内核列表(定义在/etc/grub.conf,/etc/grub/menu.lst和/etc/grub.conf的软连接
)
根据 GRUB 的配置加载默认内核镜像和 initrd 镜像到内存中,当所有镜像准备好后,即跳转到内核镜像(针对于Windows可能有些许不同但都大同小异)。
(3) kernel 阶段
当BootLoader 阶段完成之后内核镜像(kernel image)被加载到内存中,系统的控制权就交给内核镜像由此内核阶段开始了;
内核镜像不是一个可以执行的内核,而是一个被压缩的内核镜像 (zImage 或 bzImage
), 在内核镜像的头部有一个小型程序 routine 其做少量的硬件设置 ,然后自解压压缩的内核镜像并放到高端内存。
如果存在初始磁盘镜像(initrd), routine 将拷贝 initrd 以供稍后安装使用,然后 routine 将调用内核开始内核启动。
在内核引导过程中,初始 RAM 磁盘(initrd)是由 BootLoader 加载到内存中的,它会被复制到 RAM 中并挂载到系统上。
initrd 作为 RAM 中的临时根文件系统使用,并允许内核在没有挂载任何物理磁盘的情况下完整地实现引导(实际上CentOS7忘记使用进行恢复也是主要依赖于initrd
),由于与外围设备进行交互所需要的模块可是 initrd 的一部分,因此内核可以非常小,但是仍然支持大量可能的硬件配置
在内核启动后就可以正式装备根文件系统了(通过 pivot_root),此时会将 initrd 根文件系统卸载掉并挂载真正的根文件系统。
initrd 函数可以创建一个小型的 Linux 内核,其中包括作为可加载模块编译的驱动程序, 并且该模块可以为内核提供了访问磁盘和磁盘上的文件系统的方法,并为其他硬件提供了驱动程序
由于根文件系统是磁盘上的一个文件系统,因此 initrd 函数会提供一种启动方法来获得对磁盘的访问,并挂载真正的根文件系统。但是在没有硬盘的嵌入式目标中,initrd 可以是最终的根文件系统,或者也可以通过网络文件系统(NFS)来挂载最终的根文件系统。
#使用 dmesg 来查看从加载内核后的流程
$ dmesg
[ 0.000000] Linux version 5.0.0-1031-gcp (buildd@lcy01-amd64-020) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #32-Ubuntu SMP Tue Feb 11 03:55:48 UTC 2020 (Ubuntu 5.0.0-1031.32-gcp 5.0.21)
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-5.0.0-1031-gcp root=PARTUUID=9b22aacc-c8b9-497a-9583-a20c1be968c4 ro scsi_mod.use_blk_mq=Y console=ttyS0
[ 0.000000] KERNEL supported cpus:
[ 0.000000] Intel GenuineIntel
[ 0.000000] AMD AuthenticAMD
[ 0.000000] Hygon HygonGenuine
[ 0.000000] Centaur CentaurHauls
……………………………………………………………………………………………………
[ 2.486896] Write protecting the kernel read-only data: 22528k
[ 2.489395] Freeing unused kernel image memory: 2016K
[ 2.490937] Freeing unused kernel image memory: 1708K
[ 2.500867] x86/mm: Checked W+X mappings: passed, no W+X pages found.
[ 2.503126] x86/mm: Checking user space page tables
[ 2.513767] x86/mm: Checked W+X mappings: passed, no W+X pages found.
[ 2.516258] Run /sbin/init as init process
[ 3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
[ 4.002297] systemd[1]: Detected virtualization kvm.
[ 4.004593] systemd[1]: Detected architecture x86-64.
[ 4.031531] systemd[1]: Set hostname to .
[ 5.343604] systemd[1]: Reached target Swap.
[ 5.355156] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[ 5.367360] systemd[1]: Created slice User and Session Slice.
[ 5.379321] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[ 5.395189] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[ 5.411078] systemd[1]: Reached target Local Encrypted Volumes.
[ 5.644759] EXT4-fs (sda1): re-mounted. Opts: (null)
[ 11.663490] bpfilter: Loaded bpfilter_umh pid 456
(4)init 阶段
当内核自解压完成启动并初始化后,内核启动第一个用户空间应用程序即 systemd 进程(其实是老式 System V 系统的 init 程序的替代品
)并将控制权移交给它; 这是系统启动后调用的第一个使用标准 C 库编译的程序,在此进程之前还没有执行任何标准的 C 应用程序,至此整个系统引导过程的结束;
此时 kernel和 systemd 处于工作运行状态然后就由systemd来管理各项程序,有可能您从dmesg输错的日志上该阶段首先执行/sbin/init命令而对于采用systemd的发行版来说,实际上/sbin/init 是指向 /lib/systemd/systemd
的软链接文件;
[ 2.516258] Run /sbin/init as init process
[ 3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
Q:为什么为systemd是 Linux 的小伙伴?
答:其实广义上来讲 Linux 是众多 Linux 系统发行版的集合,但严格来讲 Linux 仅仅是一个 OS 的 kernel 而已,仅仅有一个内核是无法组成一个系统的,所以 Linux kernel 还需要他的几个兄弟比如 GNU 、 systemd 、X Window 、GNOME 、 KDE 、Xfce 等等
其他用户层面的程序来构建出一套完整的操作系统出来
比如: GNU/Linux 将 Debian 哲学与方法论,GNU 工具集、Linux 内核,以及其他重要的自由软件结合在一起所构成的独特的软件发行版称为 Debian GNU/Linux。
systemd 简介
描述:在片头的时候我大致对systemd的工作做了一个总结,在本章节我对其深入的讲解
systemd 是一个 Linux 系统基础组件的集合,提供了一个系统和服务管理器,运行为 PID 1 并负责启动其它程序。
功能包括:
支持并行化任务;
同时采用 socket 式与 D-Bus 总线式激活服务;
按需启动守护进程(daemon);
利用 Linux 的 cgroups 监视进程; 比如systemctl 显示 CPU 和 Mem 信息就是基于此哦
。
支持快照和系统恢复;
维护挂载点和自动挂载点;
各服务间基于依赖关系进行精密控制。
systemd* 支持 SysV 和 LSB 初始脚本,可以替代 sysvinit。
除此之外功能还包括日志进程、控制基础系统配置,维护登陆用户列表以及系统账户、运行时目录和设置,可以运行容器和虚拟机,可以简单的管理网络配置、网络时间同步、日志转发和名称解析等。
systemd 设计目标
描述:在Redhat、CentOS等系列发行版中从7.x ~ 8.x 正式采用systemd作为系统服务管理工具的内核系统服务;它融合之前service和chkconfig的功能于一体,所以说它也能在 /etc/init.d/
启动脚本进行扫描查看相程序;
主要目标:
改进效能:使用二进制代码替换松散的SYSV启动脚本,减少频繁的进程创建/ 库加载/ 内核/用户切换;
启动并行化: 利用 Dbus 进程间通讯与 socket 激活机制,解决任务启动时的依赖问题
实现任务(daemons)精确控制:使用内核的 cgroup 机制,不依赖 pid 来追踪进程,即使是两次 fork之后生成的守护进程也不会脱离 systemd 的控制
统一任务定义: 用户不需要自行编写 shell 脚本,而仅依据 systemd 制定的 unit 规则;
systemd 体系架构
systemd体系架构如下:
1.最底层:systemd 内核层
面依赖 cgroup、autofs、kdbus
2.第二层:systemd libraries
是 systemd 依赖库
3.第三层:systemd Core
是 systemd 自己的库
4.第四层:systemd daemons
以及 targets 是自带的一些基本 unit、target,类似于 sysvinit 中自带的脚本
5.最上层就是和 systemd 交互的一些工具,比如我们下面将要学习的systemctl;
描述:systemd核心概念unit(单元)类型:unit表示不同类型的systemd对象,并提供了处理不同单元之间依赖关系的能力,通过配置文件进行标识和配置;
文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息;
type | name | 作用 |
---|---|---|
Service unit | .service | 用于封装一个后台服务进程 |
Target unit | .target | 用于将多个单元在逻辑上组合在一起。 |
Device unit | .device | 用于定义内核识别的设备,在 sysfs(5) 里面作为 udev(7) 设备树展示 |
Socket unit | .socket | 用于标识进程间通信用到的socket文件 |
Snapshot unit | .snapshot | 管理系统快照 |
Swap unit | .swap | 用于标识swap 文件或设备 |
Mount unit | .mount | 用于封装一个文件系统挂载点(也向后兼容传统的 /etc/fstab 文件) |
Automount unit | .automount | 用于封装一个文件系统自动挂载点 |
Path unit | .path | 用于根据文件系统上特定对象的变化来启动其他服务。 |
Time unit | .timer | 用于封装一个基于时间触发的动作。取代传统的 crond 等任务计划服务 |
Slice unit | *.slice | 用于控制特定 CGroup 内所有进程的总体资源占用。 |
systemd 只在内存中加载最小化的一组单元 只有至少满足下列条件之一的单元,才会被加载到内存中:
1.处于 活动(active)、启动中(activating)、停止中(deactivating)、失败(failed) 状态之一(也就是停止(inactive)之外的状态)
2.至少有一个作业正在作业队列中
3.至少有一个其他已经加载到内存中的单元依赖于它
4.仍然占有某些资源 (例如一个已停止的服务单元的进程忽略了终止请求,仍在逗留)
5.被 D-Bus 调用以程序化的方式固定到了内存中
实际上用户并不能显而易见的看到某个单元是否已被加载到内存用 systemctl list-units –all
命令可以显示当前已加载到内存中的所有单元不满足加载条件(见上文)的单元会被立即从内存中卸载,并且它的记帐数据(accounting data)也会被清空。不过因为每当一个单元关闭时,都会生成一条日志记录声明该单元所消耗的资源, 所以这些数据通常不会彻底消失。
在 CentOS/RedHat 发行版中 man systemd.unit
Table 1. Load path when running in system mode (--system).
┌────────────────────────┬─────────────────────────────┐
│Path │ Description │
├────────────────────────┼─────────────────────────────┤
│/etc/systemd/system │ Local configuration │
├────────────────────────┼─────────────────────────────┤
│/run/systemd/system │ Runtime units │
├────────────────────────┼─────────────────────────────┤
│/usr/lib/systemd/system │ Units of installed packages │
└────────────────────────┴─────────────────────────────┘
在 Ubuntu/Debian 发行版中 man systemd.unit
Table 1. Load path when running in system mode (--system).
┌────────────────────┬─────────────────────────────┐
│Path │ Description │
├────────────────────┼─────────────────────────────┤
│/etc/systemd/system │ Local configuration │
├────────────────────┼─────────────────────────────┤
│/run/systemd/system │ Runtime units │
├────────────────────┼─────────────────────────────┤
│/lib/systemd/system │ Units of installed packages │
└────────────────────┴─────────────────────────────┘
在使用 yum/apt 或其他包管理器,以及 rpm/deb 等软件包安装软件的时候,如果该软件支持 systemd 管理的话,就会自动在/usr/lib/systemd/system
目录添加一个配置文件(针对于CentOS说明),此时可以采用systemctl cat name 来查看该软件的 systemd 单元文件
但是如果软件没有自带 systemd 配置文件的话,我们可以自己搓一个配置文件出来,并复制到相应的目录下即可(后续我会简单配置一个实例[Webp Server Go](https://github.com/webp-sh/webp_server_go)
)
service unit文件格式说明(类似于windows下的ini):
man systemd.service #参考
[unit]
Description:描述信息
After:定义unit的启动次序,表示当前unit应该晚于哪些unit启动,其功能与Before相反
Requires:依赖到的其它units,强依赖,被依赖的units无法激活时,当前unit也无法激活
Wants:依赖到的其它units,弱依赖
Conflicts:定义units间的冲突关系
[Service] #与特定类型相关的专用选项;此处为Service类型
Type:定义影响ExecStart及相关参数的功能的unit进程启动类型
simple:默认值,这个daemon主要由ExecStart接的指令串来启动,启动后常驻于内存中
forking:由ExecStart启动的程序透过spawns延伸出其他子程序来作为此daemon的主要服务。原生父程序在启动结束后就会终止
oneshot:与simple类似,不过这个程序在工作完毕后就结束了,不会常驻在内存中
dbus:与simple类似,但这个daemon必须要在取得一个D-Bus的名称后,才会继续运作.因此通常也要同时设定BusNname=才行
notify:在启动完成后会发送一个通知消息。还需要配合 NotifyAccess 来让 Systemd 接收消息
idle:与simple类似,要执行这个daemon必须要所有的工作都顺利执行完毕后才会执行。这类的daemon通常是开机到最后才执行即可的服务
EnvironmentFile=/etc/sysconfig/sshd #环境file
ExecStart=/usr/sbin/sshd -D $OPTIONS #启动
ExecReload=/bin/kill -HUP $MAINPID #重启
KillMode=process #关闭
Restart=on-failure # Restart: fail 时重启
RestartSec=42s
[Target]
#.target定义了一些基础的组件,供.service文件调用
[Mount]
#.mount文件定义了一个挂载点,[Mount]节点里配置了What,Where,Type三个数据项
#等同于以下命令:mount -t hugetlbfs /dev/hugepages hugetlbfs
What=hugetlbfs
Where-/dev/hugepages
Type=hugetlbfs
[Install]:#定义由“systemctl enable”以及"systemctl disable“命令在实现服务启用或禁用时用到的一些选项
Alias:别名,可使用systemctl command Alias.service
RequiredBy:被哪些units所依赖,强依赖
WantedBy:被哪些units所依赖,弱依赖 多用户模式下需要的
Also:安装本服务的时候还要安装别的相关服务
注意事项:
不同的发行版 systemd unit 的 path 不一样,但是总体来说systemd 的配置文件主要位于以下三个目录中
/usr/lib/systemd/system
或 /lib/systemd
: 使用包管理器安装的软件的 systemd unit 件实际配置文件的存放位置
/run/systemd/system
:在运行时创建的s ystemd unit 文件。该目录优先于已安装服务单元文件的目录。
/etc/systemd/system
: 优先级最高
,由 systemctl 命令创建的 systemd unit 文件以及为扩展服务而添加的 unit 文件都将启用。
当内核加载到内存中后开始执行 systemd,并且根据 dmesg 的日志我们可以了解到 systemd 启动后执行了哪一些操作
[ 2.516258] Run /sbin/init as init process
[ 3.992535] systemd[1]: systemd 237 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN2 +IDN -PCRE2 default-hierarchy=hybrid)
[ 4.002297] systemd[1]: Detected virtualization kvm.
[ 4.004593] systemd[1]: Detected architecture x86-64.
[ 4.031531] systemd[1]: Set hostname to .
[ 5.343604] systemd[1]: Reached target Swap.
[ 5.355156] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[ 5.367360] systemd[1]: Created slice User and Session Slice.
[ 5.379321] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[ 5.395189] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[ 5.411078] systemd[1]: Reached target Local Encrypted Volumes.
[ 5.644759] EXT4-fs (sda1): re-mounted. Opts: (null)
[ 5.702603] RPC: Registered named UNIX socket transport module.
[ 5.704115] RPC: Registered udp transport module.
[ 5.705318] RPC: Registered tcp transport module.
[ 5.706573] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 5.825727] Loading iSCSI transport class v2.0-870.
[ 5.912079] iscsi: registered transport (tcp)
[ 5.942499] systemd-journald[196]: Received request to flush runtime journal from PID 1
[ 5.973269] systemd-journald[196]: File /var/log/journal/7bc72ce3e0aa559e38159aa4fa0547f9/system.journal corrupted or uncleanly shut down, renaming and replacing.
下面的图表解释了 这些具有特定含义的 target 单元之间的依赖关系 以及各自在启动流程中的位置。图中的箭头表示了单元之间的依赖关系与先后顺序, 整个图表按照自上而下的时间顺序执行。
local-fs-pre.target
|
v
(various mounts and (various swap (various cryptsetup
fsck services...) devices...) devices...) (various low-level (various low-level
| | | services: udevd, API VFS mounts:
v v v tmpfiles, random mqueue, configfs,
local-fs.target swap.target cryptsetup.target seed, sysctl, ...) debugfs, ...) #主要单元Unti
| | | | |
\__________________|_________________ | `_______________` |____________________/
\|/
v
sysinit.target
|
`________________________________` /|\________________________________________
/ | | | \
| | | | |
v v | v v
(various (various | (various rescue.service
timers...) paths...) | sockets...) |
| | | | v
v v | v *rescue.target
timers.target paths.target | sockets.target
| | | |
v \_________________ | `_______________` /
\|/
v
basic.target
|
`________________________________` /| emergency.service
/ | | |
| | | v
v v v *emergency.target
display- (various system (various system
manager.service services services)
| required for |
| graphical UIs) v
| | *multi-user.target
| | |
\_________________ | `_____________` /
\|/
v
*graphical.target
(1) systemd 执行的第一个目标是 default.target。但实际上 default.target 是指向 graphical.target 的软链接。Graphical.target 的实际位置是/usr/lib/systemd/system/graphical.target
$ cat /usr/lib/systemd/system/graphical.target
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target #注意依赖
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
(2) 在default.target这个阶段,会启动multi-user.target而这个 target 将自己的子单元放在目录/etc/systemd/system/multi-user.target.wants
里。这个 target 为多用户支持设定系统环境。非 root用户会在这个阶段的引导过程中启用。防火墙相关的服务也会在这个阶段启动。multi-user.target会将控制权交给另一层basic.target。
cat /usr/lib/systemd/system/multi-user.target
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target #注意依赖
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
(3)basic.target单元用于启动普通服务特别是图形管理服务。它通过/etc/systemd/system/basic.target.wants
目录来决定哪些服务会被启动,basic.target 之后将控制权交给 sysinit.target.
$ tree /etc/systemd/system/multi-user.target.wants
/etc/systemd/system/multi-user.target.wants
├── auditd.service -> /usr/lib/systemd/system/auditd.service
├── chronyd.service -> /usr/lib/systemd/system/chronyd.service
├── crond.service -> /usr/lib/systemd/system/crond.service
├── docker.service -> /usr/lib/systemd/system/docker.service
├── firewalld.service -> /usr/lib/systemd/system/firewalld.service
├── gitlab-runner.service -> /etc/systemd/system/gitlab-runner.service
├── irqbalance.service -> /usr/lib/systemd/system/irqbalance.service
├── kdump.service -> /usr/lib/systemd/system/kdump.service
├── NetworkManager.service -> /usr/lib/systemd/system/NetworkManager.service
├── postfix.service -> /usr/lib/systemd/system/postfix.service
├── remote-fs.target -> /usr/lib/systemd/system/remote-fs.target
├── rhel-configure.service -> /usr/lib/systemd/system/rhel-configure.service
├── rsyslog.service -> /usr/lib/systemd/system/rsyslog.service
├── sshd.service -> /usr/lib/systemd/system/sshd.service
└── tuned.service -> /usr/lib/systemd/system/tuned.service
(4) sysinit.target会启动重要的系统服务例如系统挂载,内存交换空间和设备,内核补充选项等等。sysinit.target 在启动过程中会传递给local-fs.target。
tree /etc/systemd/system/basic.target.wants
/etc/systemd/system/basic.target.wants
├── microcode.service -> /usr/lib/systemd/system/microcode.service
└── rhel-dmesg.service -> /usr/lib/systemd/system/rhel-dmesg.service
(5) local-fs.target
,这个 target 单元不会启动用户相关的服务,它只处理底层核心服务。这个 target 会根据 /etc/fstab 和 /etc/inittab 来执行相关操作。
cat /usr/lib/systemd/system/sysinit.target
[Unit]
Description=System Initialization
Documentation=man:systemd.special(7)
Conflicts=emergency.service emergency.target
Wants=local-fs.target swap.target
After=local-fs.target swap.target emergency.service emergency.target
使用 pstree 命令来看一哈进程树的状态,用户空间的进程都挂在 PID 为 1 的 systemd 下,注意该命令不是发行版本内置的需要进行安装 yum install pstree
;
╭─root@sg-02 ~
╰─# pstree -p
systemd(1)─┬─accounts-daemon(661)─┬─{accounts-daemon}(689)
│ └─{accounts-daemon}(729)
├─agetty(971)
├─agetty(992)
├─aria2c(1010)
├─atd(653)
├─containerd(2915)─┬─{containerd}(2928)
│ ├─{containerd}(2929)
│ ├─{containerd}(2930)
│ ├─{containerd}(2934)
│ ├─{containerd}(2935)
│ ├─{containerd}(2950)
│ ├─{containerd}(2951)
│ ├─{containerd}(2978)
│ ├─{containerd}(5360)
│ └─{containerd}(8299)
├─cron(639)───cron(20506)───sh(20507)───monitor.sh(20509)───ffmpeg(20514)
├─dbus-daemon(664)
├─dockerd(17771)─┬─{dockerd}(17783)
│ ├─{dockerd}(17784)
│ ├─{dockerd}(17785)
│ ├─{dockerd}(17791)
│ ├─{dockerd}(17793)
│ ├─{dockerd}(17800)
│ ├─{dockerd}(17803)
│ ├─{dockerd}(3030)
│ └─{dockerd}(3031)
├─fail2ban-server(755)─┬─{fail2ban-server}(1059)
│ └─{fail2ban-server}(1060)
├─iscsid(896)
├─iscsid(897)
├─lvmetad(392)
├─networkd-dispat(622)───{networkd-dispat}(982)
├─nginx(3305)───nginx(17700)
├─php-fpm7.2(7497)─┬─php-fpm7.2(1295)
│ ├─php-fpm7.2(1296)
│ └─php-fpm7.2(5611)
├─polkitd(808)─┬─{polkitd}(820)
│ └─{polkitd}(822)
├─rngd(981)
├─rpcbind(7125)
├─rsyslogd(11567)─┬─{rsyslogd}(11598)
│ ├─{rsyslogd}(11599)
│ └─{rsyslogd}(11600)
├─ss-server(17126)───obfs-server(17138)
├─sshd(5357)─┬─sshd(15490)───sshd(15598)───zsh(15619)───pstree(20539)
│ ├─sshd(20413)───sshd(20414)
│ └─sshd(20517)
├─systemd(5715)───(sd-pam)(5718)
├─systemd-journal(12866)
├─systemd-logind(652)
├─systemd-network(12827)
├─systemd-resolve(12839)
├─systemd-timesyn(12852)───{systemd-timesyn}(12861)
└─systemd-udevd(8171)
描述: 如今systemd 引入了一个和启动级别(一个旧的概念)功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每一个目标都有名字和独特的功能,而且能同一时候启用多个,一些目标继承其它目标的服务,并启动新服务。
SysV 启动级别 | Systemd 目标 | 描述 |
---|---|---|
0 | runlevel0.target, poweroff.target | 中断系统(halt) |
1, s, single | runlevel1.target, rescue.target | 单用户模式 |
2, 4 | runlevel2.target, runlevel4.target, multi-user.target | 用户自己定义启动级别。通常识别为级别3。 |
3 | runlevel3.target, multi-user.target | 多用户,无图形界面。用户能够通过终端或网络登录。 |
5 | runlevel5.target, graphical.target | 多用户。图形界面。继承级别3的服务。并启动图形界面服务。 |
6 | runlevel6.target, reboot.target | 重新启动 |
emergency | emergency.target | 急救模式(Emergency shell) |
控制 systemd 的主要命令主要有以下几种:
systemctl 命令控制 systemd
的管理系统和服务的命令行工具
systemsdm 命令控制 systemd
的管理和服务的图形化工具
journalctl 命令查询systemd
日志系统
loginctl 命令控制 systemd
登入管理器
systemd-analyze 分析系统启动效能(类似开机时间)
systemctl help <单元> ## 显示单元的手冊页(必须由单元文件提供):
#unit类型或者单元:
service :文件扩展名为.service, 用于定义系统服务
target :文件扩展名为.target,用于模拟实现运行级别
device :用于定义内核识别的设备
mount:定义文件系统挂载点
socket:用于标识进程间通信用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动
snapshot :管理系统快照
swap:用于标识swap设备
automount :文件系统的自动挂载点
path:用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务
Systemctl 新特性:
系统引导时实现服务并行启动
按需启动守护进程
自动化的服务依赖关系管理
同时采用socket式与D-Bus总线式激活服务
系统状态快照
优先级从低到高各自是:
/usr/lib/systemd/system/: 软件包安装的单元 #(Centos) Ubuntu:/lib/systemd/system
/etc/systemd/system/: 系统管理员安装的单元
/etc/init.d/ :软件安装服务单元(#任然有部分软件采用和用户自定义脚本)
当systemd执行在用户模式下时,使用的载入路径是全然不同的;systemd 单元名仅能包括 ASCII 字符, 下划线和点号. 其它字符须要用 C-style “\x2d” 替换. 參阅 man systemd.unit 和 man systemd-escape.}}
参数语法
#0.启动/重启/停止/重载服务
systemctl start NAME
systemctl restart NAME
systemctl stop NAME
systemctl reload NAME
#1.查看服务状态
systemctl status NAME
#2.重启守护程序-修改过服务单元配置文件必须执行它(扫描新的或有变动的单元)
systemctl daemon-reload
#3.可以实现对其他机器的远程控制,该功能使用 SSH 连接。
systemctl 参数中添加 -H <用户名>@<主机名>
#4.杀死服务
systemctl kill NAME
基本用法
#示例0.自启与启动等常用命令
systemctl enable nginx.service
systemctl disable xinetd.service #关闭自启动服务
systemctl start nginx.service
systemctl stop xinetd.service #停止服务
systemctl restart xinetd.service #重启服务
systemctl status firewalld #查看状态
systemctl status cobbler.service
# ● cobbler.service - SYSV: cobbler
# Loaded: loaded (/etc/rc.d/init.d/cobbler; bad; vendor preset: disabled)
# Active: inactive (dead)
# Docs: man:systemd-sysv-generator(8)
#示例1.显示当前已加载到内存中的所有单元(Active)
systemctl list-units --all
#UNIT LOAD ACTIVE SUB DESCRIPTION
#proc-sys-fs-binfmt_misc.automount loaded active running Arbitrary Executable File Formats File System Automount Point
#dev-block-8:2.device loaded active plugged LVM PV dKOf4k-3rna-sW69-3GHn-79gA-cfLX-DbC5oJ on /dev/sda2 2
systemctl list-units --type=target #获取指定单元目标
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
cryptsetup.target loaded active active Local Encrypted Volumes
#示例2.查看该软件的 systemd 单元文件信息
systemctl cat docker
# /usr/lib/systemd/system/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
BindsTo=containerd.service
After=network-online.target firewalld.service containerd.service
Wants=network-online.target
Requires=docker.socket
#示例3.查看服务是否开机启动,服务是否激活
$systemctl is-enabled firewalld.service
# disabled
systemctl is-enabled sshd.service
# enabled
systemctl is-active sshd
# active
#示例4.列出 systemd目录下面的服务单元
systemctl list-unit-files
systemctl list-unit-files | grep mysqld #查看mysqld服务是不是启动
systemctl list-unit-files | grep enabled #查看已启动的服务列表
# auditd.service enabled
# [email protected] enabled
# chronyd.service enabled
# crond.service enabled
systemctl list-unit-files --failed #查看启动失败的服务列表
# UNIT FILE STATE
# 0 unit files listed.
#示例5.欲查看对特定 target 启用的服务请执行
systemctl list-dependencies
systemctl list-dependencies [target]
systemctl list-dependencies microcode.service
# microcode.service
# ● ├─system.slice
# ● └─basic.target
# │ └─...
#注意:该输出结果只显示 SysV 服务,并不包含原生 systemd 服务,SysV 配置数据可能被原生 systemd 配置覆盖。
#示例6.切换并查看启动级别/目标
$systemctl set-default multi-user.target
rm '/etc/systemd/system/default.target'
ln -s '/usr/lib/systemd/system/multi-user.target' '/etc/systemd/system/default.target'
#能够在 systemctl 的输出中看到命令执行的效果:链接 /etc/systemd/system/default.target 被创建。指向新的默认启动级别。
$systemctl isolate graphical.target #等价于telinit 3 或 telinit 5。
$systemctl get-default
graphical.target #当前为 graphical.target 修改为命令模式multi-user.target:
#示例7.查看unit中的类型
systemctl -t service
# UNIT LOAD ACTIVE SUB DESCRIPTION
# auditd.service loaded active running Security Auditing Service
systemctl --type target
# UNIT LOAD ACTIVE SUB DESCRIPTION
# basic.target loaded active active Basic System
#示例8.禁用和取消禁用单元
# 禁用一个单元(禁用后,间接启动也是不可能的):
systemctl mask <单元>
# 取消禁用一个单元:
systemctl unmask <单元>
#示例9.电源管理
#安装 polkit 后才干够一般用户身份使用电源管理。
#假设你正登录在一个本地的systemd-logind用户会话。且当前没有其它活动的会话。那么下面命令无需root权限就可以执行。否则(比如当前有还有一个用户登录在某个tty),systemd 将会自己主动请求输入rootpassword。
$ systemctl reboot #重新启动
$ systemctl poweroff #退出系统并停止电源
$ systemctl suspend #待机
$ systemctl hibernate #休眠
$ systemctl hybrid-sleep #混合休眠模式(同一时候休眠到硬盘并待机):
#示例10.远程控制其他服务器的 systemd
systemctl status nginx -H [email protected]
描述:systemd 的第二个主要部分是 journal 日志系统,类似于 syslog 但也有些显著区别。
如果你喜欢用 sed 、grep 、awk
三剑客来处理日志,那么当你面对 journal 日志系统的时候你就准备掀桌儿吧!因为这是个二进制日志,无法使用常规的命令行文本处理工具来解析它
Systemd Journal 的优点如下:
* 简单性:代码少,依赖少,抽象开销最小。
* 零维护:日志是除错和监控系统的核心功能,因此它自己不能再产生问题。举例说,自动管理磁盘空间,避免由于日志的不断产生而将磁盘空间耗尽。
* 移植性:日志 文件应该在所有类型的 Linux 系统上可用,无论它使用的何种 CPU 或者字节序。
* 性能:添加和浏览 日志 非常快。
* 最小资源占用:日志 数据文件需要较小。
* 统一化:各种不同的日志存储技术应该统一起来,将所有的可记录事件保存在同一个数据存储中。所以日志内容的全局上下文都会被保存并且可供日后查询。例如一条固件记录后通常会跟随一条内核记录,最终还会有一条用户态记录。重要的是当保存到硬盘上时这三者之间的关系不会丢失。Syslog 将不同的信息保存到不同的文件中,分析的时候很难确定哪些条目是相关的。
* 扩展性:日志的适用范围很广,从嵌入式设备到超级计算机集群都可以满足需求。
* 安全性:日志 文件是可以验证的,让无法检测的修改不再可能。
日志的优先级和分类
系统日记按(优先级Priority level)和(设施Facility)对信息进行分类。日志分类对应于经典的Syslog协议(RFC 5424)。
注:下面表格最后一列 (wc -l) 是统计的记录数比例,总数是3个月的日志,大约100万条数据。
(2)设施分类:
journalctl 命令帮助
journalctl -h
#Options:
--system Show the system journal 显示系统日志
--user Show the user journal for the current user 显示当前用户的用户日志
-M --machine=CONTAINER Operate on local container 在本地容器上操作
-S --since=DATE Show entries not older than the specified date 显示不早于指定日期的条目
-U --until=DATE Show entries not newer than the specified date 显示不比指定日期更新的条目
-c --cursor=CURSOR Show entries starting at the specified cursor 显示从指定光标开始的条目
--after-cursor=CURSOR Show entries after the specified cursor 在指定的光标后显示条目
--show-cursor Print the cursor after all the entries 在所有条目之后打印光标
--cursor-file=FILE Show entries after cursor in FILE and update FILE 在FILE中显示光标后的条目并更新FILE
-b --boot[=ID] Show current boot or the specified boot 显示当前引导或指定的引导
--list-boots Show terse information about recorded boots 显示有关录制的靴子的简洁信息
-k --dmesg Show kernel message log from the current boot 显示当前引导的内核消息日志
-u --unit=UNIT Show logs from the specified unit 显示指定单位的日志
--user-unit=UNIT Show logs from the specified user unit 显示指定用户单元的日志
-t --identifier=STRING Show entries with the specified syslog identifier 显示具有指定syslog标识符的条目
-p --priority=RANGE Show entries with the specified priority 显示具有指定优先级的条目
-g --grep=PATTERN Show entries with MESSAGE matching PATTERN 显示MESSAGE匹配PATTERN的条目
--case-sensitive[=BOOL] Force case sensitive or insenstive matching 强制区分大小写或不区分匹配
-e --pager-end Immediately jump to the end in the pager 立即跳到寻呼机的末尾
-f --follow Follow the journal 关注期刊, 最新的
-n --lines[=INTEGER] Number of journal entries to show 要显示的日记帐分录数
--no-tail Show all lines, even in follow mode 即使在跟随模式下也显示所有行
-r --reverse Show the newest entries first 首先显示最新的条目
-o --output=STRING Change journal output mode (short, short-precise, short-iso, short-iso-precise, short-full, short-monotonic, short-unix, (precise精确,monotonic单调) 更改日志输出模式: verbose, export,
json, json-pretty, json-sse, json-seq,
cat, with-unit)
--output-fields=LIST Select fields to print in verbose/export/json modes 选择要以详细/导出/ json模式打印的字段
--utc Express time in Coordinated Universal Time (UTC) 协调世界时(UTC)的快车时间
-x --catalog Add message explanations where available 添加消息说明(如果有)
--no-full Ellipsize fields Ellipsize字段
-a --all Show all fields, including long and unprintable 显示所有字段,包括长字段和不可打印字段
-q --quiet Do not show info messages and privilege warning 不显示信息消息和权限警告
--no-pager Do not pipe output into a pager 不要将输出传输到寻呼机
--no-hostname Suppress output of hostname field 禁止输出主机名字段
-m --merge Show entries from all available journals 显示所有可用期刊的条目
-D --directory=PATH Show journal files from directory 显示目录中的日志文件
--file=PATH Show journal file 显示日志文件
--root=ROOT Operate on files below a root directory 对根目录下的文件进行操作
--interval=TIME Time interval for changing the FSS sealing key 更改FSS密封键的时间间隔
--verify-key=KEY Specify FSS verification key 指定FSS验证密钥
--force Override of the FSS key pair with --setup-keys 使用--setup-keys覆盖FSS密钥对
Commands:
-h --help Show this help text 显示此帮助文本
--version Show package version 显示包版本
-N --fields List all field names currently used 列出当前使用的所有字段名称
-F --field=FIELD List all values that a specified field takes 列出指定字段所需的所有值
--disk-usage Show total disk usage of all journal files 显示所有日志文件的总磁盘使用情况
--vacuum-size=BYTES Reduce disk usage below specified size 将磁盘使用量降低到指定大小以下
--vacuum-files=INT Leave only the specified number of journal files 只保留指定数量的日志文件
--vacuum-time=TIME Remove journal files older than specified time 删除早于指定时间的日志文件
--verify Verify journal file consistency 验证日志文件一致性
--sync Synchronize unwritten journal messages to disk 将未写入的日志消息同步到磁盘
--flush Flush all journal data from /run into /var 将/ run中的所有日志数据刷新到/var
--rotate Request immediate rotation of the journal files 请求立即轮换日志文件
--header Show journal header information 显示日记标题信息
--list-catalog Show all message IDs in the catalog 显示目录中的所有消息ID
--dump-catalog Show entries in the message catalog 在消息目录中显示条目
--update-catalog Update the message catalog database 更新消息目录数据库
--setup-keys Generate a new FSS key pair 生成新的FSS密钥对
实际案例:
#实例1.显示bootloader启动信息
$ sudo journalctl -b #启动信息23565
$ sudo journalctl -b -0
$ sudo journalctl -b -1 #前一次启动信息... 通过查询引导列表可看到最多能查看前几次启动信息
$ sudo journalctl --list-boots #引导列表
#实例2.显示不早于指定日期的条目
$ sudo journalctl --since="2019-06-13 16:42:34"
$ sudo journalctl --since "20 min ago" #Show all messages since 20 minutes ago: 最近20分钟
$ sudo journalctl -S "20 min ago"
#实例3.持续显示最新新消息默认10条
$ sudo journalctl -f
#实例4.显示特定可执行文件的信息
$ sudo journalctl /usr/lib/systemd/systemd
#实例5.显示特定进程PID的日志信息
$ sudo journalctl _PID=1
#实例6.显示特定单元日志信息
$ sudo journalctl -u man-db.service
#实例7.显示当前引导的内核消息日志(--dmesg)
$ sudo journalctl -k
#实例8.-p 显示具有指定优先级的条目(0-7)
$ sudo journalctl -p err..alert
$ sudo journalctl -p 3..1 //3-1
$ sudo journalctl -p 3 //3-0
$ sudo journalctl -p 3 -r //3-0; 加-r选项,首先显示最新的条目
#实例9.通过在syslog工具上进行过滤来显示等效的auth.log
$ sudo journalctl SYSLOG_FACILITY=10
# 0 kern 内核;
# 1 user 用户;
# 3 daemon 守护进程;
# 4 auth 授权;
# 10 authpriv 授权;
$ sudo journalctl SYSLOG_FACILITY=0 -r
$ sudo journalctl -k -r
$ sudo journalctl SYSLOG_FACILITY=4 |wc -l
#14516
$ sudo journalctl SYSLOG_FACILITY=10 |wc -l
#9049
#实例10.如果日志目录(默认位于/var/log/journal下)包含大量日志数据,那么journalctl可能需要几分钟来过滤输出。
#它可以通过使用——file选项来强制journalctl只查看最近的日志,从而显著加快速度:
$ sudo journalctl --file /var/log/journal/*/system.journal -f
#实例11.手动清理日志文件删除已归档的日志文件
$ sudo journalctl --vacuum-size=100M #直到它们使用的磁盘空间低于100M:
$ sudo journalctl --vacuum-time=2weeks #使所有日记文件不包含超过2周的数据。
配置文件设置:
(1)日志大小限制设置
默认为基础文件系统的10%,但上限为4GB。
例如本机/var/log/journal/位于30Gb分区上,日志最多需要3Gb。超过40Gb的分区,日志文件需要最大值都为4Gb。
可以通过取消注释和更改以下内容来控制持久日志的最大大小:
$vim /etc/systemd/journald.conf
SystemMaxUse=50M
#也可以使用drop-in snippets配置覆盖机制,而不是编辑全局配置文件。在这种情况下,将覆盖置于[Journal]标题下:
$vim /etc/systemd/journald.conf.d/00-journal-size.conf
[Journal]
SystemMaxUse=50M
修改后重新启动日志系统 systemd-journald.service
即 systemctl restart systemd-journald.service;
#Linux系统开机时间流程所耗费时间一览
[root@initiator ]$ systemd-analyze
Startup finished in 473ms (kernel) + 3.990s (initrd) + 40.050s (userspace) = 44.515s
方式1:
描述:为了避免和 pacman 冲突,不应该直接编辑软件包提供的文件. 要更改由软件包提供的单元文件,先创建名为/etc/systemd/system/<单元名>.d/ 的文件夹(如 /etc/systemd/system/httpd.service.d/
);然后放入 *.conf 文件,当中能够加入或重置參数,这里设置的參数优先级高于原来的单元文件。
实际案例:
#1.比如假设想加入一个额外的依赖。创建这么一个文件就可以:
/etc/systemd/system/.d/customdependency.conf
[Unit]
Requires=<新依赖>
After=<新依赖>
/etc/systemd/system/unit.d/customexec.conf
[Service]
#想知道为什么改动 ExecStart 前必须将其置空
ExecStart=
ExecStart=new command
#自己主动重新启动服务
Restart=always
RestartSec=30
#2.然后执行下面命令使更改生效:
systemctl daemon-reload
systemctl restart <单元>
此外,把旧的单元文件从 /usr/lib/systemd/system/ 拷贝到 /etc/systemd/system/,然后进行改动,也能够达到相同效果。
总结:
在 /etc/systemd/system/ 文件夹中的单元文件的优先级总是高于 /usr/lib/systemd/system/ 文件夹中的同名单元文件
用 systemd-delta 命令来查看哪些单元文件被覆盖、哪些被改动,系统维护的时候须要及时了解哪些单元已经有了更新。
方法2
自定义软件的 Systemd 单元实例:
[Unit]
Description=WebP Server Go
Documentation=https://github.com/webp-sh/webp_server_go
After=nginx.target
[Service]
Type=simple
StandardError=journal
WorkingDirectory=/opt/webps
ExecStart=/opt/webps/webp-server --config /opt/webps/config.json
Restart=always
RestartSec=3s
[Install]
WantedBy=multi-user.target
然后将其保存在/usr/lib/systemd/system/docker.service/webp.service
,并且 执行 systemctl daemon-reload
重载守护服务; 之后将可以通过systemctl status webp.service 对我们编写的服务单元进行管理;
关于 systemd 的单元配置文件如何书写,因为根据不同的单元类型包含的配置项实在是巨多。建议参考官方文档/社区翻译文档
(1)基于systemd实现显示服务CPU 和 Memory 信息
$vim /etc/systemd/system.conf
DefaultCPUAccounting=yes
DefaultMemoryAccounting=yes
DefaultTasksAccounting=yes