关于systemd:Systemd详解与使用

背景

  • 不太适宜进入docker,须要间接部署在宿主机下面,领有root权限,操作批改零碎,读取零碎的一些信息等
  • 保障开机启动以及异样重启
  • 有一套欠缺的日志零碎
  • 反对Before/After的启动机制
  • 反对基于cgroup的限度
  • 以最低的零碎开销实现该目标
  • 不便打包为deb包进行装置,参考各种服务的装置,比方apt install nginx docker postgresqldeb包背地的逻辑与实现
  • 兼容根本全副的linux发行版本

尽管之前应用过的supervisor也能够满足上述大部分需要,然而打工人的世界总是须要去谋求一下极致的,于是决定好好学习一下systemd

Systemd根本介绍

  • 内核加载到内存之后启动的第一个用户空间程序,pid是1,是所有过程的父过程,会托管所有僵尸过程,如果这个程序挂了,零碎也就间接关机了
  • systemd不是内核的一部分,然而却成为了Debian/Ubuntu系和Fedora/Centos/Redhat/RockyLinux系的零碎初始化过程

Linux启动流程

systemd是系统启动流程中初始化阶段的次要角色,有必要介绍一下linux系统启动流程

硬件疏导启动阶段(第一阶段)

  • 机器电源接通时,存储在主板芯片下面的固件初始化,POST(Power On Self Test)上电自检
  • BIOS阶段

    • 初始化硬件,内存,磁盘,显卡等
    • 查找启动介质(个别是硬盘),查找MBR或者EFI分区的第一阶段疏导程序,并且移交控制权
  • MBR或者EFI程序阶段,查找第二阶段的GRUB(GRand Unified Boot)疏导程序并装置到BootLoder

BootLoader 启动疏导阶段(第二阶段)

  • stage1: 执行BootLoader的主程序(GRUB程序),开始启动stage1.5
  • stage1.5: 疏导文件系统中的stage2
  • stage2: 加载GRUB外围映像
  • grub.conf/grub.cfg阶段

    • 解析grub.conf/grub.cfg配置文件,加载默认内核镜像和 initrd (初始磁盘镜像,对应于/boot/initrd.img文件)镜像到内存中,当所有镜像筹备好后,即跳转到内核镜像,移交零碎控制权给内核,接下去进入到内核阶段
    • 文件后缀名称在Ubuntu22下面看到的是.cfg,可能其余零碎是.conf结尾
    • 该配置文件门路是/grub/grub.cfg或者/boot/grub/grub.cfg,门路具体位置取决于零碎装置时候是否宰割了一个/boot分区,之前装零碎的时候/boot分区都是必须调配的

内核疏导阶段(第三阶段)

  • /boot/kernel and Kernel parameter

    • 内核读取/boot上面的文件,执行加载
    • 查看/boot分区的内容如下,能够看到内核保留了两个版本的镜像(img-5.15.0-53-genericimg-5.15.0-56-generic),其中新镜像是目前零碎失常运行时候加载的镜像,每次apt更新零碎的时候如果有新版本内核开释,更新时候会保留一份老版本镜像,等下一次新镜像更新到时候才会删除,一份冗余

      $ ll /boot 
      总用量 165M
      -rw-r--r-- 1 root root 256K 十月   18 02:36 config-5.15.0-53-generic
      -rw-r--r-- 1 root root 256K 十一月 22 23:08 config-5.15.0-56-generic
      drwx------ 3 root root 4.0K 一月    1  1970 efi
      drwxr-xr-x 5 root root 4.0K 十二月  3 09:44 grub
      lrwxrwxrwx 1 root root   28 十二月  2 09:45 initrd.img -> initrd.img-5.15.0-56-generic
      -rw-r--r-- 1 root root  65M 十二月  1 09:01 initrd.img-5.15.0-53-generic
      -rw-r--r-- 1 root root  65M 十二月  4 09:04 initrd.img-5.15.0-56-generic
      lrwxrwxrwx 1 root root   28 十二月  2 09:45 initrd.img.old -> initrd.img-5.15.0-53-generic
      drwx------ 2 root root  16K 五月   26  2021 lost+found
      -rw-r--r-- 1 root root 179K 二月    7  2022 memtest86+.bin
      -rw-r--r-- 1 root root 181K 二月    7  2022 memtest86+.elf
      -rw-r--r-- 1 root root 181K 二月    7  2022 memtest86+_multiboot.bin
      -rw------- 1 root root 6.0M 十月   18 02:36 System.map-5.15.0-53-generic
      -rw------- 1 root root 6.0M 十一月 22 23:08 System.map-5.15.0-56-generic
      lrwxrwxrwx 1 root root   25 十二月  2 09:45 vmlinuz -> vmlinuz-5.15.0-56-generic
      -rw------- 1 root root  12M 十月   18 02:41 vmlinuz-5.15.0-53-generic
      -rw------- 1 root root  12M 十一月 23 01:07 vmlinuz-5.15.0-56-generic
      lrwxrwxrwx 1 root root   25 十二月  2 09:45 vmlinuz.old -> vmlinuz-5.15.0-53-generic
  • /boot/initrd

    • 疏导initrd解压载入
    • 在内存中加载内核应用的root文件系统,执行initrd文件系统中的init程序,实现加载其余驱动模块
    • 执行/sbin/init过程

      发现/sbin是指向/usr/sbin的一个软链接

      $ ll / |grep bin
      lrwxrwxrwx   1 root root    7 五月   26  2021 bin -> usr/bin
      lrwxrwxrwx   1 root root    8 五月   26  2021 sbin -> usr/sbin

      查看init发现init是指向systemd的一个软链接

      $ ll /usr/sbin |grep init
      lrwxrwxrwx 1 root root     20 九月   10 02:47 init -> /lib/systemd/systemd
      -rwxr-xr-x 1 root root    13K 三月   15  2022 mkinitramfs
      lrwxrwxrwx 1 root root     14 九月   10 02:47 telinit -> /bin/systemctl
      -rwxr-xr-x 1 root root   6.8K 二月    9  2022 update-initramfs

Systemd初始化阶段(第四阶段)

  • 内核启动第一个用户空间应用程序,零碎控制权移交给systemd
  • 该阶段会加载执行级别,加载服务,启动shell和图形化界面
  • 初始化阶段有3个类型,SysV初始化,UpStart(Ubuntu开发的用于替换SysV的初始化程序)和Systemd(由Redhat工程师开发),很多老零碎个别都是SysV作为初始化程序,从centos7(大略是2014年)当前的零碎大多都是采纳SystemdUbuntu15开始应用systemd

为什么各大支流linux零碎采纳systemd

  • 改良启动项的效率,防止频繁的过程创立,内核/用户切换,为零碎的启动和治理提供一套残缺的解决方案
  • 利用 Dbus 过程间通信与 socket 激活机制,解决工作启动时的依赖问题,实现启动并行化
  • 实现工作daemons的准确管制,应用内核的 cgroup 机制,不依赖 pid 来追踪过程,过程屡次fork 之后生成的过程也不会脱离 systemd 的管制
  • 对立工作定义,用户不须要编写shell脚本,而是应用 systemd 制订的 unit 规定
  • systemd有两大设计理念,启动更少的服务,更多地并行启动服务,最终实现用户能够疾速进入零碎
  • systemd应用C编写,用于替换传统的脚本shell启动,shell中调用系统命令的操作会导致新过程的生成,比方awk, sed, grep等都会生成新过程,产生了很大的开销,systemd的运行开销比SysVUpStart小很多,速度也更快

systemd做了什么

解决启动项的依赖性

  • Socket依赖:例如服务A依赖服务Bsocket,然而服务B还未启动,所以systemd创立了一个长期socket用于接管服务A的申请与数据,当B真正起来的时候再把长期socket缓存的数据以及描述符替换为Bsocket
  • D-Bus(Desktop Bus)依赖:是一个用来在过程间通信的服务,该服务反对Bus Activation个性,即服务A要通过 D-Bus 服务和B通信,然而B没有启动,那么 D-Bus 能够把B起来,在B启动的过程中,D-Bus 缓存数据,systemd应用这个个性并行启动AB
  • 文件系统依赖: 系统启动过程中,systemd 参考了 autofs 的设计思路,使得依赖文件系统的服务和文件系统自身初始化两者能够并发工作,监测到某个文件系统挂载点真正被拜访到的时候才触发挂载操作

提供了一个零碎和服务管理器

  • 利用 Linuxcgroups监督过程
  • 反对快照和零碎复原
  • 保护挂载点和主动挂载点
  • 各服务间基于依赖关系进行精细管制
  • 基于journald的服务日志治理
  • 管制根底系统配置
  • 保护登陆用户列表以及零碎账户
  • 运行时目录和设置
  • 运行容器和虚拟机
  • 简略的管理网络配置
  • 网络工夫同步
  • 日志转发

systemd的管控范畴曾经远超作为零碎启动项的角色,能够了解为曾经大一统治理linux各项性能了,职责和最后的sysvupstart有所脱离,变得极其简单宏大,这个也是最后redhat/centos系列和debian/ubuntu系列采纳systemd引起的微小波澜

在此举荐浏览一下itwire于2014发表的 Linus Torvalds对于systemd的访谈文章(Linus保持中立意见,如果这个人没有开喷的话,阐明是曾经获得微小的胜利了)

https://www.itwire.com/business-it-news/open-source/65402-torvalds-says-he-has-no-strong-opinions-on-systemd

也能够浏览一下systemd的作者Lennert发表的对于PID 1的再思考Rethinking PID 1

http://0pointer.de/blog/projects/systemd.html

systemdUnit单元的文件类型

零碎初始化须要很多操作,比方启动后盾服务,挂载文件系统,配置网络等,过程中的每一步都被 Systemd 形象为一个配置单元,即 Unit,具体蕴含的类型如下

type name 作用
Service unit .service 封装一个后盾服务过程,比方sshd,dockerd
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 Unit文件的地位与执行优先级

不同发行版本的门路是不同的,当三个目录上面存在同名文件的时候,优先级最高目录下的文件会被优先应用

  • /usr/lib/systemd/system/lib/systemd : 应用包管理器装置的软件的 systemd unit 的理论配置文件的寄存地位,在Ubuntu22下面/lib门路是指向/usr/lib的一个软链接,优先级最低
  • /run/systemd/system:在运行时创立的 systemd unit 文件,该目录优先于已装置服务单元文件的目录
  • /etc/systemd/system: 优先级最高,由 systemctl 命令创立的 systemd unit 文件以及为扩大服务而增加的 unit 文件都将启用,系统管理员装置的单元

Systemd Unit文件的组成

次要由三块UnitServiceInstall组成

具体版本或者全副字段解释执行如下命令查看

$ man systemd.unit
$ man systemd.service
$ man systemd.exec
....

或者拜访地址https://www.freedesktop.org/software/systemd/man/ 或者第三方中文版http://www.jinbuguo.com/systemd/systemd.index.html

常见字段解释如下

Unit块上面的字段

  • Requires: 强依赖,依赖的其它 Unit 列表,列在其中的 Unit 会在这个Unit启动时的同时被启动,如果其中任意一个Unit启动失败,这个Unit也会启动失败
  • Wants: 弱依赖,与 Requires 类似,但只是在以后 Unit 启动时,触发启动列出的 Unit ,而不思考这些 Unit 启动是否胜利
  • After:与 Requires 类似,该字段列出的所有 Unit 全副启动后,才会启动以后的 Unit
  • Before: 与 After 相同,以后 Unit 应该在列出的 Unit 之前启动
  • OnFailureUnit 启动失败时,主动启动列出的每个 Unit
  • Conflicts: 与这个 Unit 有抵触的模块,如果列出的 Unit 曾经在运行时,以后 Unit 不能启动,反之亦然

Service块上面的字段

  • EnvironmentFile: 指定以后服务的环境变量定义文件,该文件外部的 key=value 键值对,能够用 $key 的模式,在以后.service文件中援用
  • ExecStart: 定义启动过程时执行的命令
  • ExecStartPre : 启动以后服务之前执行的命令

    • ExecStartPost: 启动以后服务之后执行的命令
    • ExecStop: 进行服务时执行的命令
    • ExecStopPost: 进行服务之后执行的命令

      • ExecReload : 重启服务时执行的命令
  • Type : 启动类型

    • simple: 默认值,执行ExecStart指定的命令,启动主过程
    • forking: 以 fork 形式从父过程创立子过程,创立后父过程会立刻退出
    • oneshot: 一次性过程,Systemd 会等以后服务退出,再持续往下执行
    • dbus: 以后服务通过D-Bus启动
    • notify: 以后服务启动结束,会告诉Systemd,再持续往下执行
    • idle: 若有其余工作执行结束,以后服务才会运行

      • WorkingDirectory: 指定服务的工作目录
      • RootDirectory: 指定服务过程的根目录,如果配置了这个参数,服务将无法访问指定目录以外的文件
    • User: 指定运行服务的用户

      • Group: 指定运行服务的用户组
      • KillMode: 定义 Systemd 如何进行服务,可选项如下
      • control-group: 默认值,以后控制组外面的所有子过程,都会被杀掉
      • process: 只杀主过程
      • mixed: 主过程将收到 SIGTERM 信号,子过程收到 SIGKILL 信号
      • none: 没有过程会被杀掉,只是执行服务的 stop 命令

install块上面的字段

  • WantedBy 值为一个或多个 Target,以后 Unit 激活 (enable,即开机启动) 时符号链接会放入 /usr/lib/systemd/system 目录下以 <Target>.wants 后缀形成的子目录中,该参数常见的值是multi-user.target,这样,当该target中的任意一个Unit启动的时候,本Unit都会跟着一起启动,这就是配置开机自启动的要害
  • Also 以后 Unit enable/disable 时,同时 enable/disable 的其余 Unit
  • Alias 以后 Unit 可用于启动的别名

systemd Unit的配置与应用

最好的样例还是参考操作系统曾经有的内容

比方当初要编写一个自启动服务,能够参考docker.servicesshd.service

$ systemctl cat docker
$ systemctl cat sshd

如果要编写一个定时工作,能够参考apt-dayly.timer

$ systemctl cat apt-daily.timer

systemctl应用

管理系统和服务的命令行工具

设施启动,关机等操作,能够看到设施运行操作命令是指向systemctl的软链接

$ ll /usr/sbin |grep system
lrwxrwxrwx 1 root root     14 九月   10 02:47 halt -> /bin/systemctl
lrwxrwxrwx 1 root root     20 九月   10 02:47 init -> /lib/systemd/systemd
lrwxrwxrwx 1 root root     14 九月   10 02:47 poweroff -> /bin/systemctl
lrwxrwxrwx 1 root root     14 九月   10 02:47 reboot -> /bin/systemctl
lrwxrwxrwx 1 root root     14 九月   10 02:47 runlevel -> /bin/systemctl
lrwxrwxrwx 1 root root     14 九月   10 02:47 shutdown -> /bin/systemctl
lrwxrwxrwx 1 root root     14 九月   10 02:47 telinit -> /bin/systemctl

systemd罕用操作

动作 命令 正文
剖析零碎状态
显示零碎状态 systemctl status
列出正在运行的单元 systemctl or systemctl list-units
列出失败的单元 systemctl --failed
列出已装置的单元 systemctl list-unit-files
Show process status for a PID systemctl status {pid} cgroup slice, memory and parent
查看单元状态
显示单元的手册页 systemctl help {unit} 如果单元反对
显示单元的状态 systemctl status {unit} 包含其是否在运行
查看单元是否配置为主动启动 systemctl is-enabled {unit}
启动、重新启动和从新加载单元
立刻启动单元 systemctl start {unit}
立刻进行单元 systemctl stop {unit}
重新启动单元 systemctl restart {unit}
从新加载单元及其配置 systemctl reload {unit}
从新加载 systemd 配置 systemctl daemon-reload 扫描单元的变动
启用单元
开机主动启用单元 systemctl enable {unit}
开机主动启用单元,并立刻启动 systemctl enable --now {unit}
勾销开机主动启用单元 systemctl disable {unit}
从新启用 单元 systemctl reenable {unit} 先勾销启用,再启用
禁用单元
禁用单元,使其无奈启动 systemctl mask {unit}
勾销禁用单元 systemctl unmask {unit}

systemd其余常用命令模块

journalctl

  • 查问systemd服务的日志信息

    $ journalctl

loginctl

  • systemd的登入管理器,能够查看目前登录到以后计算机的用户信息

    $ sudo loginctl         
    SESSION  UID USER SEAT  TTY   
          2 1000 gong seat0 tty2
        640 1000 gong       pts/17
        641 1000 gong       pts/19

    如果应用ssh {用户名}@localhost再次登录到本地计算机,应用loginctl的时候会看到多了一个session

    这个时候能够应用如下命令,指定一个session id 的形式敞开某个用户的拜访

    $ sudo loginctl kill-session 641

systemd-analyze

  • 剖析系统启动过程中的耗时,敞开或者调整某些服务能够优化启动速度

    $ sudo systemd-analyze blame
    1min 55.462s fstrim.service
         39.372s fwupd-refresh.service
         33.827s apt-daily.service
         31.949s apt-daily-upgrade.service
         16.637s systemd-networkd-wait-online.service
          6.193s plymouth-quit-wait.service
          5.070s docker.service
          1.551s snapd.service
          1.540s netfilter-persistent.service
          1.318s snapd.seeded.service
          1.196s vmware.service
          1.129s freeradius.service
          1.049s gpu-manager.service
          .....

systemd service应用示例

编写一个文件/usr/lib/systemd/system/test-boot.service如下

[Unit]
Description=test boot
# 示意在网络模块启动之后才启动本Unit
After=network.target

[Service]
# 该命令是阻塞的,每隔1秒会打印以后日期
ExecStart=/bin/sh -c "while true; do date; sleep 1; done"
# 配置查问的工作门路,该门路须要存在,否则会报错
WorkingDirectory=/tmp/

[Install]
# 该参数示意此Unit是开机启动时候关联到multi-user.target
# 当multi-user.target上面的任意一个Unit启动都会触发本Unit的启动
# 即enable状态的时候会创立一个链接到/etc/systemd/system/multi-user.target.wants/目录上面
WantedBy=multi-user.target

执行命令如下

$ sudo systemctl daemon-reload

查看以后服务状态

$ sudo systemctl status test-boot
○ test-boot.service - test boot
     Loaded: loaded (/lib/systemd/system/test-boot.service; disabled; vendor preset: enabled)
     Active: inactive (dead)

配置开机启动,留神察看软链接的地位是配置在

$ sudo systemctl enable test-boot
Created symlink /etc/systemd/system/multi-user.target.wants/test-boot.service → /lib/systemd/system/test-boot.service.

接下去启动服务并查看状态

$ sudo systemctl start test-boot
$ sudo systemctl status test-boot
● test-boot.service - test boot
     Loaded: loaded (/lib/systemd/system/test-boot.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2023-03-16 17:32:13 CST; 20s ago
   Main PID: 940646 (sh)
      Tasks: 2 (limit: 38197)
     Memory: 364.0K
     CGroup: /system.slice/test-boot.service
             ├─940646 /bin/sh -c "while true; do date; sleep 1; done"
             └─940825 sleep 1

三月 16 17:32:24 gong sh[940765]: 2023年 03月 16日 星期四 17:32:24 CST
三月 16 17:32:25 gong sh[940769]: 2023年 03月 16日 星期四 17:32:25 CST
三月 16 17:32:26 gong sh[940778]: 2023年 03月 16日 星期四 17:32:26 CST
三月 16 17:32:27 gong sh[940782]: 2023年 03月 16日 星期四 17:32:27 CST
三月 16 17:32:28 gong sh[940786]: 2023年 03月 16日 星期四 17:32:28 CST
三月 16 17:32:29 gong sh[940795]: 2023年 03月 16日 星期四 17:32:29 CST
三月 16 17:32:30 gong sh[940799]: 2023年 03月 16日 星期四 17:32:30 CST
三月 16 17:32:31 gong sh[940803]: 2023年 03月 16日 星期四 17:32:31 CST
三月 16 17:32:32 gong sh[940814]: 2023年 03月 16日 星期四 17:32:32 CST

最初能够重启机器校验一下是否能够开机自启动

参考浏览

Linux 系统启动流程

Linux 的小伙伴 systemd 详解

linuxinit程序倒退历史

Linux PID 1Systemd

Docker根底技术:Linux CGroup

archlinuxsystemd wiki文档

itwire于2014发表的 Linus Torvalds对于systemd的访谈

systemd的作者Lennert发表的对于PID 1的再思考

systemdunit配置

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理