FPs

Systemd 系统管理相关

从本文开始将对Systemd 与系统的方方面面相关的作用和功能进行分店详细介绍,除去基础概念以及注意事项,部分小节包含实例已帮助您理解。
再次提醒,由于个人水平和能力有限,对某些小节未能深入详细的叙述和论证,若您需要深入了解相关内容请参考对应小节参考链接,或需求其他资料。

规范化的配置文件

在Systemd 中定义了一批公用配置文件,systemd 希望通过推广和使用这些配置文件,在Linux 的各类发行版中形成标准,以解决目前各大发行版配置文件五花八门的情况。
配置文件列表:

  • /etc/hostname: 主机名。在不同的发行版上主机名存在不同的文件中,例如Fedora:/etc/sysconfig/network,OpenSUSE:/etc/HOSTNAME。systemd采用的是debian的配置文件:/etc/hostname。
  • /etc/vconsole.conf: 默认键盘映射与终端字体配置。
  • /etc/locale.conf: 配置系统全局locale。
  • /etc/modules-load/*.conf: 启动时候静态加载内核模块的配置。
  • /etc/sysctl.d/*.conf: 内核sysctl参数配置,此处配置文件作为/etc/sysctl.conf的扩展。
  • /etc/tmpfiles.d/*.conf: 临时文件的创建、删除、清空的配置。
  • /etc/binfmt.d/*.conf: 系统附加二进制格式支持的配置。
  • /etc/os-release: 包含操作系统基础信息,例如操作系统名称,版本,主页等等。(注:debian 7已存在此文件,格式相同)。
    • 例(debian testing x86)
 PRETTY_NAME="Debian GNU/Linux jessie/sid"  
 NAME="Debian GNU/Linux"  
 ID=debian  
 HOME_URL="http://www.debian.org/"
 SUPPORT_URL="http://www.debian.org/support/"
 BUG_REPORT_URL="http://bugs.debian.org/"

注: systemd 215之后,`/etc/os-release`被移到`/usr/lib/os-release`,原来的`/etc/os-release`将是后者的软链接。     
  • /etc/machine-id:机器ID。详细信息在后文Unique Machinehandling ID一节详细介绍。
  • /etc/machine-info:包含机器元数据,主要是主机名,图标名称和图片等等。详细信息在后文Dynamic host name and machine meta data handling一节详细介绍。

/etc/hostname

systemd定义的/etc/hostname 文件参考自发行版debian,路径与文件名称、格式等等与debian相同。

注:debian中的/etc/debian_version 文件依旧存在且无变化。

/etc/locale.conf

系统启用systemd之后,要设置整个系统使用的locale,只需在/etc/locale.conf 中设置LANG变量即可。 locale.conf中可以设置一系列环境变量,每行一个。可以包含LANG变量和LC_ALL外的所有LC_*变量。 例:

LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

systemd提供了localectl工具用于修改系统全局locale,可以通过此工具修改locale.conf

#localectl set-locale LANG="en_US.UTF-8"

参考: man localectl

注:/etc/locale.conf默认不存在,需要手动创建。

本节参考链接:

PAM integration

systemd 提供了一个pam模块(pam_systemd.so)配合systemd 登录管理器(systemd-logind.service)用于管理用户会话,pam_systemd.so模块目前只支持session,处理系统为用户提供服务之前/后需要的做的事情,具体见下文。

pam_systemd.so支持的选项:

  • class=[user,greeter,lock-screen]:指定会话类别。
  • type =[unspecified,tty,x11,wayland,mir]:指定会话类型。
  • debug[=]:配置为yes或未配置该选项,将输出额外的调试信息。

用户登入后本模块动作:

  1. 若登入的用户的主目录不存在,将先创建所有权为登入用户的目录(/run/user/$USER),然后登入。
  2. 初始化 $XDG_SESSION_ID 环境变量。
  3. 为本次会话创建一个新的systemd scope单元(scope 单元可用来组织进程,应用资源单元,或者杀死进程组),一个用户会话的所有进程都包含在一个scope单元的实例。 若当前会话是登入用户的首次会话,一个新的slice单元user.slice(slice 单元用于将管理进程的单元分组成层级,层级可允许控制分配给 slice 的资源。) 将自动创建,每个会话将限制在用户slice 内的 scope 单元中。

用户登出后本模块动作:
1. 关闭本次会话内的所有进程。若退出会话是该用户最后一个会话,那么该用户的systemd实例也将被关闭。 - 注:nohup 和screen 运行的服务不受影响 2. 若退出的会话是该用户最后一个会话,$XDG_RUNTIME_DIR目录与其内容将被删除。

本节参考链接

Target

注:此部分内容与启动分析一节有重叠,但是考虑到本大节内容的完整性,未删去。

target单元为其他配置单元进行逻辑组,它们实际上不做什么,只是运用其他配置单元(类似快照单元),这样并可以对配置单元做一个统一的控制,这样就可以实现runlevel的概念。

启动级别(runlevel)是一个旧的概念。现在,systemd 引入了一个和启动级别功能相似又不同的概念——目标(target)。不像数字表示的启动级别,每个目标都有名字和独特的功能,并且能同时启用多个。一些目标继承其他目标的服务,并启动新服务。systemd 提供了一些模仿 sysvinit 启动级别的目标,仍可以使用旧的 telinit 启动级别 命令切换。 ---Archlinux Wiki

它们本身实际上并不做什么,只是引用其他 unit(unit是systemd的配置单元,包含.service,.mount,.scokets等)而已。这样便可以对 unit 做一个统一的控制。(例如:multi-user.target 相当于在传统使用 SysV 的系统中运行级别5);bluetooth.target 只有在蓝牙适配器可用的情况下才调用与蓝牙相关的服务,如:bluetooth 守护进程、obex 守护进程等) - -

更多介绍:

对于常见的runlevel:0,1,2,3,4,5,6,systemd都有对应的target与之对应,不同的target与不同的服务相关,启动时候进入默认的target,即可带起下属的服务。-Fedora Wiki

target table:

target table

由上表可知每个SvsV的启动级别与之对于的Systemd target,另外systemd一般还会有一个默认的target(default.target),default.target是上表中的某一个target的软链接,表示默认的启动级别,等同于/etc/inittab文件中的 initdefault值。
相对于/etc/rc[0~6].d,Systemd采用target来管理不同的服务,同时也是对服务进行抽象和分组管理的一种方式。除了以上表中的target,还有不同的target。例如graphical.target 依赖着multi-user.target,multi-user.target依赖着 basic.target,basic.target依赖着 sysinit.target。

看一个例子,即可明白这种关系:
basic.target
basic.target

  • basic.target requires sysinit.targe,
  • basic.target wants sockets.target、timer.target、paths.targt

可以很方便的将系统某个运行状态所需要的配置单元组合一个target进行管理。
系统包含以下常见target,见图:targets。
targets

实例

如果我们添加了一个服务(example.service),然后想此服务在系统进入多用户模式时候(multi-user.target)可以自动启动,我们可新建一个与此服务同名的target(example.target),然后ln -smulti-user.target.wants文件夹中即可。另外也可以继承已有的target,并添加其他服务,来创建自定义的target。

注:wants目录与target相关联,若一个target有同名的wants目录,只需将依赖此target的单元文件链接到目录下,当系统启动此target时同时也会自动启动这些单元文件。使用systemctl enable xxx.service,会自动根据[Install]中 WantedBy的信息创建链接文件到对应wants目录。

Path­based Activation(inotify)

systemd提供了一个以.path为扩展名的单元,用于监视目录文件,激活服务。由于path单元内部使用inotify的API监视文件系统,所以也和inotify具有同样的局限性,无法用于监视远程NFS文件系统上的文件或目录。

每一个path单元默认必须有一个同名的service单元,path单元监视文件或目录去激活同名的service服务(可以通过Unit选项指定激活的单元)。 触发条件的选项:

  • PathExists=:目录或文件存在时,触发service单元;
  • PathExistsGlob=:和PathExists类似,不过可以使用通配符指定监视的目录和文件们,当至少有一个文件或目录存在时,触发service单元。
  • PathCahnged=:目录或文件在打开后再关闭的时候如果发生了更改将触发service单元,打开和关闭文件期间的写和变动不会触发服务。
  • PathModified=:目录或文件每一次更改都会触发service单元。
  • DirectoryNotEmpty=:目录非空时,触发service单元。

实例

为了确保当有打印任务在队列中的时候CUPS服务(UNIX 通用打印系统)会启动,我们可以写一个cups.path:当在/var/spool/cups目录下发现文件时,激活CUPS服务(存在同名服务单元cups.service)。

[Unit]
Description=CUPS Printer Service Spool

[Path]
DirectoryNotEmpty=/var/spool/cups

[Install]
WantedBy=multi-user.target

例子来源:systemd for Developers II#Path-based Activation in Detail

注:(实验结果)设置了文件存在的时候触发,创建了文件,触发了服务,然后删除了文件即破坏了触发条件,服务不会被停止。要做到此类需求,可以编写另外一个path单元,用于监控触发条件被破坏时,即监控一个反面的触发条件,当满足条件时这个path单元触发停止之前进行中的服务的动作。

本节参考链接

Timer

Systemd中的.timer单元的功能和cron类似,但是同cron相比有更多的特性,例如配置语法更直观友好(更丰富和直观的时间单位,以及友好的日历事件等)、更丰富的控制选项(系统启后候等待时间,systemd启动后等待时间,距离服务单元上次活动或未活动多少时间再次激活等等),持久化支持(存储服务单元最后一次触发记录),休眠唤醒,流逝时间精度设置等等。

.timer单元的格式上同其他配置单元相同,特殊点在于[Timer] Section,部分配置选项如下:

  • OnActiveSec=:timer自身被激活后过多少时间激活任务。
    • 例如:OnActiveSec=1min,表示当该timer被激活后1分钟激活任务。
  • OnBootSec=:系统启动之后过多少时间激活任务。
    • 例如:OnBootSec=5min,表示系统启动5分钟之后激活任务。
  • OnStartupSec=:systemd服务启动之后过多少时间激活任务。
    • 例如:OnStartupSec=10min,表示在systemd启动10分钟之后激活任务。
  • OnUnitActiveSec=:距离上次timer激活任务之后多久再次激活任务的时间间隔。
    • 例如:OnUnitActiveSec=30min,表示timer在最后一次激活任务之后的30分钟将再次激活任务。
  • OnUnitInactiveSec=:defines a timer relative to when the unit the timer is activating was last deactivated.//todo
  • OnCalendar=:日期的设置,通过过指定的格式设置在某个月的第几天激活任务,或者一个星期中的某个时间激活任务。
    • 例如:OnCalendar= *-*-1 0:0:0,表示每个月的第一天开始的时候激活任务;OnCalendar=Mon,Sun 2014-*-* 01,02:23:00,表示2014年中每个星期1和星期日的1点和2点的23分的时候激活任务。
  • AccuracySec=:Timer流逝的时间精度设置,默认为1分钟。若想更准确,可设置为1us。
    • 设置建议:make sure to set this value as high as possible and as low as necessary 。
  • Unit=:指定激活的单元名称。若未指定,将默认执行与timer同名的service单元。
  • Persistent=[true,fales]:设置是否保存服务单元上一次激活的时间。此设置项只在设置了OnCalendar之后有效。
    • This is useful to catch up on missed runs of the service when the machine was off.

更详细的时间单位与日期设置请参看:systemd.time

实例

/etc/systemd/system//usr/lib/systemd/system创建example.service文件。

/etc/systemd/system/example.service

[Unit]
Description= Reset

[Service]
ExecStart=/usr/bin/echo "reset~"

创建timer文件,每5小时激活一次example.service,屏幕打印提醒:

/etc/systemd/system/remind-reset.timer

[Uni]
Description= Remind of reset

[Timer]
OnUnitActiveSec=5h
Unit=example.service

[Install]
WantedBy=multi-user.target
$ sudo systemctl enable remind-reset.timer #设置开机启动
$ sudo systemctl start remin-reset.tmer #启动timer

对于/etc/cron.{daily,hourly,monthly,weekly}等目录,在Timer中没有默认类似的目录,需要手动创建timer调用target,然后将服务进程放入target即可。
/etc/cron.d/daily的替代:
定义/etc/systemd/system/timer-daily.timer

[Unit]
Description=Daily Timer

[Timer]
OnbootSec=5min
OnUnitActiveSec=1d
Unit=timer-daly.target

[Install]
WantedBy=basic.target

添加需要的target:/etc/systemd/system/timer-daily.target

[Unit]
Description=Dail Timer Target
StopWhenUnneeded=yes

创建与target同名的wants文件夹,/etc/systemd/system/timer-daily.target.wants,

设置开机自动激活timer

$ sudo systemctl enbale timer-daily.timer

然后将需要每天执行的服务进程.service文件 ln -s/etc/systemd/system/timer-daily.target.wants文件夹中间即可。

本节参考链接

Sysctl

在系统启动阶段,systemd-sysctl.service会自动读取以下三个目录中的配置文件设置内核参数:

  • /etc/sysctl.d/*.conf
  • /run/sysctl.d/*.conf
  • /usr/lib/sysctl.d/*.conf

操作

使用sysctl命令设置内核参数和载入配置文件。 加载所有配置文件

sudo sysctl --system

加载特定配置文件

sudo sysctl -p filename.conf

临时性设置某项内核参数

sudo sysctl kernel.domainname=hell-world  .
或
echo "hello-world" > /proc/sys/kernel/domainname

更多详细用法参考sysctl用户手册。

优先级

上文三个文件夹的优先级从上到下依次降低,即若/etc/sysctl.d//run/sysctl.d/中文件存在同名的设置条目,前者的设置将覆盖后者的设置。/run/sysctl.d/usr/lib/sysctl.d

注:目前debian testing(systemd 204)系统依然存在/etc/sysctl.conf,但在systemd 207之后,systemd只会加载应用/etc/sysctl.d/*.conf/usr/lib/sysctl.d/*.conf中的内容。/etc/sysctl.conf将被弃用,需要用户手动移动已存在的sysctl.conf至/etc/sysctl.d/99-sysctl.conf

注:目前debian testing 存在的/etc/sysctl.conf优先级高于其他三个目录中的配置文件,见下图验证优先级:

sysctl

文件格式与命名

配置文件内,使用正斜杆/或点号.分隔内核参数,例如kernel.domainname=debian等同于kernel-domainname=debiandebian将写入/pro/sys/kernel/domainname文件。

注意:若一个配置条目中第一个使用分隔符是点号,条目中点号和正斜杆是等价互换的;若第一个使用的分隔符号是正斜杆,其余的点号与正斜杆将保持不变。

例:net.ipv4.conf.enp3s0/200.forwardingnet/ipv4/conf/enp3s0.200/forwarding都指向 /proc/sys/net/ipv4/conf/enp3s0.200/forwarding

各个文件夹下的配置文件将按照文件名的字典序进行排序,所以配置生效或者覆盖等情况将受此影响。建议将配置文件命名为 [2个数字]+-+[直观的名称]+.conf,通过设置名称开头的数字控制加载配置顺序。

本节参考链接

Unique Machinehandling ID

systemd新规定了一个配置文件/etc/machine-id保存着本地系统的唯一机器ID。机器ID是以一个换行符结束、十六进制编码、32个字符、全小写的字符串(格式和D-Bus machine ID相同)。
机器ID通常在系统初次安装时通过工具systemd-machine-id-setup随机生成(符合v4 UUIDs标准,无需担心重复率),在生成之后,用户更改软件配置或者计算机更换硬件,都不会改变此ID

注:在之后再次启动的时候,若/etc/machine-id为空,将重新生成(可能不会改变,后文解释);若/etc/machine-id被删除,将不会重新生成该文件与id。(debian testing 实验)。

systemd-machine-id-setup

systemd-machine-id-setup在系统安装时用于初始化机器ID,之后可以手动调用此工具用于生成机器ID,但是/etc/machine-id已存在并且不为空,将不会进行任何操作。
另外若在systemd-machine-id-setup 初始化/etc/machine-id之前,D-Bus machine ID(/var/lib/dbus/machine-id)已存在,将拷贝后者内容作为/etc/machine-id

machineID

注:/var/lib/dbus/machine-iddbus-uuidgen生成。

注:/etc/machine-id可能是/var/lib/dbus/machine-id的软链接文件。

本节参考链接

Dynamic host name and machine meta data handling

  • pretty hostname:级别最高,通常根据用户的桌面环境或shell呈现给用户,是一段可以包含所有特殊字符的UTF-8编码的字符串,对用户友好,例如“John‘s Laptop”,非常直观。若有可能 pretty hostname应该与/etc/hostname(下文介绍)相近,例如"John's Latop"对应的/etc/hostname可以是johns-laptop
  • static(configured) hostname:是一段不可以包含特殊符号或空格,全小写,7bit ASCII的字符串,一般是系统合法的域名。/etc/hostname用于存储static hostname,在引导时由内核使用,用户可手动指定。例如:"johns-laptop"。
  • transient(dynamic) hostname:transient hostname又名dynamic hostname,正如其名词,它是通过网络由DHCP服务器动态分配,临时的。格式上同 static hostname 相同。例如:“ dhcp-192-168-47-11”。
    • 注:若static hostname 已经设置且可用(非 localhost),transient hostname将被停用。
  • icon name:icon name被某些GUI程序用于可视化主机,命名上遵循XDG icon命名规范。
  • chassis type:一般依照计算机实际类型定义为:"desktop", "laptop", "server", "tablet", "handset",若是虚拟机将定义为:"vm"或"container"。

配置相关

可以通过hostname查看static hostname,或者进行临时性设置,static hostname存在/etc/hostname目录中。

$sudo hostname
debian
$sudo hostname debian-jessie #临时性更改hostname,关机丢失
debian-jessie

/etc/machine-info文件用于存储系统的pretty hostname,icon name以及chassis type。

注:debian tessting 在本文写成时默认不存在/etc/machine-info,需手动创建或通过hostnamectl工具(下文介绍)进行设置时将自动创建。

machine-info中包含以下三个条目:

  • PRETTY_HOSTNAME=
  • ICON_NAME=
  • CHASSIS=

PRETTY_HOSTNAME="Lennart's Tablet"
ICON_NAME=computer-tablet
CHASSIS=tablet

systemd内置了用于配置系统hostname的工具--hostnamectl。使用hostnamectl进行的配置是永久性的(transient hostname 除外),配置信息将写入/etc/hostname(static hostname)或/etc/machine-info(pretty hostname,icon name,classis type)。

显示系统元组信息

$ sudo hostnamectl
或
$ sudo hostnamectl status

返回示例

   Static hostname: johns-server
   Pretty hostname: john's server
Transient hostname: dhcp-123456
         Icon name: computer-vm
           Chassis: vm
        Machine ID: 0de206a66f9cf937239d126753c62e2f
           Boot ID: c30bb7e14e5a4381ae089b095c553047
    Virtualization: oracle
  Operating System: Debian GNU/Linux jessie/sid
            Kernel: Linux 3.14-1-486
      Architecture: i686

设置操作

$ sudo hostnamectl set-hostname [NAME]                #设置static hostname
$ sudo hostnamectl set-hostname --static [NAME]       #设置static hostname
$ sudo hostnamectl set-hostname --transient [NAME]    #设置transient hostname
$ sudo hostnamectl set-hostname --pretty   [NAME]     #设置pretty hostname,若包含特殊符号或者空格请加上空格
$ sudo hostnamectl set-icon-name [NAME]               #设置icon name
$ sudo hostnamectl set-chassis [TYPE]                 #设置chassis type

另外也可以直接编辑/etc/machine-info文件,修改pretty hostname,icon-name和chassis type,编辑时注意格式要求。编辑之后需要重启生效。

本节参考链接

Dependency based bootup

注:此部分内容与启动分析一节有重叠,但是考虑到本大节内容的完整性,未删去。

在SysV init中,通过给/etc/rcN.d目录下的启动目标设置不同的启动数字来控制启动依赖(先后顺序,串行执行,同步阻塞),如下:

LSB_bootup

上文已经介绍了systemd的target单元,systemd启动过程由target控制,不同的target之间有层级关系,也包含着不同的服务,相对于LSB的服务依赖控制方式更加简单和直观。

boot

我们需要在系统到达某个target的时候启动某项服务,可以将服务对应的单元文件链接到target的wants文件夹下即可。

如下图:

target-wants

对于A依赖B,B依赖C,C依赖A的循环依赖关系,systemd会根据配置单元内依赖关系(required 强依赖;want 弱依赖)去掉若依赖来打破循环而修复问题,若无法修复则会报错。Systemd能够自动检测和修复这类配置错误,可保证有依赖相关的服务都可以正常启动(无法修复会报错)而不会出现互相依赖,以至于死锁的情况出现。

在单元文件内部,可以通过AfterBeforeConficts等等限制启动顺序与依赖性以及防止冲突等,具体在进程管理一节分析。

With systemd, dependencies can be resolved by designing the unit files correctly. The most typical case is that the unit A requires the unit B to be running before A is started. In that case add Requires=B and After=B to the [Unit] section of A. If the dependency is optional, add Wants=B and After=B instead. Note that Wants= and Requires= do not imply After=, meaning that if After= is not specified, the two units will be started in parallel.

得益于systemd的socket-based activation(以及解决了D-Bus依赖,文件系统依赖等),有依赖性的服务可以几乎同时启动,具体在socket-based activation一节分析。

P.S.关于启动请参看上文 启动分析一节。

系统时间管理

timedatectl

systemd提供了用于查询和设置系统时间和日期的工具--timedatectl。

注:下文中将提到的RTC即实时时钟,是计算机主板上的时钟设备(例:在BIOS中设备的时间)。操作系统会在启动阶段去读取RTC,然后设置系统时钟(又名内核时间)。而对系统时钟的更改也将会同步到RTC。

部分配置选项与实例
  • -H,--host=
    • 执行远程操作(over SSH)。注意其他操作参数需要写在-H之后,不然会提示错误信息:Too many arguments,远程执行完命令将自动返回本地控制终端。
    • timedatectl-ssh
  • status
    • 返回当前设置与状态,timedatectl不带命令参数默认与此等效。
    • timedatectl-status
    • 注:RTC可以设置为本地时间,也可以设置为世界时间。使用timedatectltimedatectl status将打印出三种时间,通过对比即可知道RTC是设置为本地时间还是世界时间。
  • set-time [TIME]
    • 设置系统时钟。同时也会更新硬件(RTC)时钟。TIME格式示例:“2011-11-11 11:11:11”,可省略某些设置项,例如只设置年月日:“2014-10-30”,只设置小时与分钟:“10:30”。
    • timedatectl-set-time
  • set-timezone [TIMEZOME]
    • 设置系统时区。可设置的时区可以用下文的list-timezones查看。若RTC是设置为本地时间,则更改时区之后RTC也会更新。
 #timedatectl set-timezone Asia/Shanghai
  • list-timezones
  • 列出可选的时区。set-timezone可设置为此选项打印出的时区。
#timedatectl list-timezones
  • timedatectl-list-timezones
  • set-local-rtc [BOOL]
  • 设置为“0”:RTC为世界时(UTC)
  • 设置为“1”:RTC为本地时
  • set-ntp [BOOL]
  • 选项:true,false。设置ntp同步时间是否打开(系统需安装ntp客户端且开启,如chrony客户端)。

timedated

systemd中一个用于控制系统时间和相关设置的daemon,它可以通过D-Bus进行访问,提供设置系统时间、时区、本地RTC、NTP服务器等接口。若想使用timedated接口进行相关工具脚本的编写请查看其官方文档,见本节参考链接。

timesyncd

systemd-timesyncd是systemd-213添加的一个新的daemon,用于同步系统时间。它内部实际上是实现了一个SNTP客户端,专注于同步时间,去掉了NTP那些繁多的功能。timesyncd以最小权限运行,且只有当网络可用时才进行工作。注意:若要使用timesyncd,确保在安装systemd时创建了为“systemd-timesync”的用户和用户组。

由于debian目前的systemd未提供此功能,以下配置文件来自systemd源代码目录。

若要启用timesyncd首先需要配置/etc/systemd/timesyncd.conf文件中的servers,多个NTPServer用空格隔开:

[Time]
Servers=0.asia.pool.ntp.org 1.asia.pool.ntp.org 2.asia.pool.ntp.org

设置开机自启动

# systemctl enable systemd-timesyncd

本节参考链接

系统临时文件管理

systemd-tmpfiles通过读取以下三个目录的配置文件来新建、清空、删除临时文件或目录。

  • /etc/tmpfiles.d/*.conf
  • /run/tmpfiles.d/*.conf
  • /usr/lib/tmpfiles.d/*.conf

在系统启动阶段,会按照以上目录下的配置文件新建、清空、删除临时文件或目录,同时也有timer单元文件自动清理超时文件。 系统管理员也可使用此工具用于管理临时文件。

# systemd-tmpfiles --[option] [config file path]

注:一条命令可同时指定多个选项。若未指定配置文件,将默认加载全部配置文件。

常见操作选项:

  • --create
  • 执行配置文件中创建文件或文件夹的行(with:f,F,w,d,D,p,L,c,b..)。
  • --clean
  • 所有超时的临时文件或目录将被删除(age)。
  • --remove
  • 执行配置文件中删除文件或文件夹的行(with:r,R..)。
  • --boot
  • 执行配置文件中带有的行(即在系统启动时才会执行的行)。

配置文件

配置文件目录:

  • /etc/tmpfiles.d/*.conf
  • /run/tmpfiles.d/*.conf
  • /usr/lib/tmpfiles.d/*.conf

以上目录优先级从上至下依次降低。若存在同名的配置文件,优先级高的目录中的配置文件将覆盖优先级低。若配置文件中存在配置错误的行,将会被自动忽略,不影响其他行的执行。管理员编写的配置文件应放在/etc/tmpfiles.d/目录下,程序安装时生成的配置文件应在/usr/lib/tmpfiles.d目录下。

以下为实验结论,官方文档暂未有此部分相关说明:

若对同一文件或目录有不同的操作(不保存新建后再删除此类操作,一般为新建同一文件或目录为不同类型的时出现),调用systemd-tmpfiles进行执行时,将提示存在冲突的临时文件或目录。若相同文件内有此类冲突行,排列在前的行将被执行,后续冲突的行不执行。若同一目录下不同文件内冲突行,将配置文件文件名按字典序排序,在前的文件中的行将被执行,之后的文件中的行被忽略。若不同目录中的不同名文件存在行冲突,优先级低的目录下的文件中的行将被执行(感觉奇怪。。不过是实验结果如此)。

tmpfiles配置文件一行即一条配置信息,包含五个部分:

Type,Path,Mode,UID,GUID,Age,Argument:

#例
#Type Path        Mode UID  GID  Age Argument
d    /run/user   0755 root root 10d -
L    /tmp/foobar -    -    -    -   /dev/null
  • Type:表示操作类型,是要新建(f,F,d,D..)还是删除(r,R..))文件或目录,还是要创建一个链接或一个设备块等,还是要调整临时文件的访问模式等。若某行只要在启动时执行,需在Type后加上,例如R!
  • Path:表示临时文件或目录的路径。Path支持部分通匹符与符号扩展(例如:%H表示Host name),具体请参考用户手册。
  • Mode:访问模式。若省略或设置为-,则目录默认为0755,文件默认为0644,若此时Type为z,则Mode不变。此参数在Type为x,r,R,L时忽略。
  • UID:用户ID。若省略、设置为-或Type为z的行中,默认为0(root)。此参数在Type为x,r,R,L时忽略。
  • GIO:用户组ID。其他同UID。
  • Age:临时文件或目录的存在时间,到期后将被自动删除。单位可为s,min,h,d,w,ms,m,us。若省略或设置为-,将不会自动清理。若以开头,例如~10d,指定目录下的内容会被保留,而更深级的目录与内容将全被删除(例:Path为/run/tmp1/,/run/tmp1/下的aa/,bb/,11文件与文件都会被保留,而例如aa/目录下cc/目录,22文件以及更深目录都将全被删除)。

    If the age field starts with a tilde character "~", the clean-up is only applied to files and directories one level inside the directory specified, but not the files and directories immediately inside it.

  • Argument:Type为c,b,f,F,w用于设置不同的参数,例如Type为L时用于设置链接的源文件,具体请参考用户手册。

关于以上选项的详细介绍请查看tmpfiles.d

实例

/usr/lib/tmpfiles.d/systemd.conf

d /run/user 0755 root root ~10d
F! /run/utmp 0664 root utmp -

f /var/log/wtmp 0664 root utmp -
f /var/log/btmp 0600 root utmp -

d /var/cache/man - - - 30d

d /run/systemd/ask-password 0755 root root -
d /run/systemd/seats 0755 root root -
d /run/systemd/sessions 0755 root root -
d /run/systemd/users 0755 root root -
d /run/systemd/machines 0755 root root -
d /run/systemd/shutdown 0755 root root -

m /var/log/journal 2755 root systemd-journal - -
Z /var/log/journal/%m 2755 root systemd-journal - -
m /run/log/journal 2755 root systemd-journal - -
Z /run/log/journal/%m 2755 root systemd-journal - -

/usr/lib/tmpfiles.d/debian.conf

# Type Path    Mode UID  GID  Age Argument
L /run/initctl -    -    -    -   /dev/initctl
d /run/sendsigs.omit.d 0755 root root -

本节参考链接

网络管理

注:systemd>=210才存在 systemd-networked 用于网络配置。

systemd-networked的配置文件存在于三个目录下,

  • /etc/systemd/network/
  • /run/systemd/network/
  • /usr/lib/systemd/network/

以上三个目录优先级从上到下依次降低。三个目录中的配置文件将被一起收集按照字典序排序,和它们在哪个目录中无关系,只有在处理同名文件时候才会考虑到目录优先级。若存在同名配置文件,优先级低的配置文件将被忽略。

有三种配置文件与systemd-networked相关,扩展名分别为'.link','.netdev','.network'。

  • .link:当网络设备就绪时,udev将匹配对应的.link文件
  • .netdev:对匹配的环境创建虚拟网络设备
  • .network:对匹配的设备进行网络配置

systemd-networked的配置文件格式上与systemd的单元文件格式相同,但是不再有后者那些常见的section,三种不同的配置文件各自有一些特有的seciton。对于配置文件的section与其中的众多选项意义不做繁杂的解释,请参考本节的参考链接。 将通过具体例子对三种配置进行大致介绍。

.link

wireless0.link

[Match]
MACAddress=12:34:56:78:9a:bc
Driver=brcmsmac
Path=pci-0000:02:00.0-*
Type=wlan
Virtualization=no
Host=my-laptop
Architecture=x86-64

[Link]
Name=wireless0
MTUBytes=1450
BitsPerSecond=10M
WakeOnLan=magic
MACAddress=cb:a9:87:65:43:21

[Mactch]section中指定了设备的mac地址,以及链接PCI总线使用的驱动brcmsmac,还有设备的工作环境(是否为虚拟环境,主机名称,系统架构等)。当对应mac地址的网络设备出现时,匹配后,[Link]section将请求udev将设备改名为wireless0,然后改变MTUbytes,设置BitPerSecond,打开WakeOnLan。同时也重新设置了设备的mac地址。另外还可以通过选项MACAddressPolicy将网络设备的mac地址设为随机,具体请参看networkd用户手册。

.netdev

Bridge

bridge0.netdev

[NetDev]
Name=bridge0
Kind=bridge

添加以上配置文件到对应目录,然后可在其他.network文件中设置网桥Bridge=bridge0。networkd启动之后,即会将.network文件匹配到的网络设备添加到对应网桥。

VLAN

vlan0.netdev

[NetDev]
Name=vlan1
Kind=vlan

[VLAN]
Id=1

vlan1.netdev

[NetDev]
Name=vlan2
Kind=vlan

[VLAN]
Id=2

将以上配置文件加入对于目录,即可在.network文件中设置VLAN VLAN=vlan1 vlan2。当networkd启动之后,对应.network文件中的设备就绪后即会自动创建VLAN。

.network

ethX.network

[Match]
Name=eth*

[Network]
DHCP=yes

将名称以eth(若eth0,eth1)开头的网络接口都开启DHCP服务配置。

enp2s0.network

[Match]
Name=enp2s0

[Network]
Address=192.168.0.15/24
Gateway=192.168.0.1

设置名称为enp2s0的网络接口的地址与网关。

若要对单网络接口设置多个IP,可以使用多个[Address]section,见:add multiple static ip addresses to a server with systemd-networkd

注:[Network]中可通过DNS=指定一个DNS服务器地址。

注:启用systemd-networked后,须关闭dhcpcd.service与所有netctl服务。

注:systemd-213新增加了 systemd-resolved ,用于管理系统DNS。systemd-resolved会将 /etc/resolv.conf链接到/run/systemd/resolve/resolv.conf/etc/resolv.conf文件的的相关设置以及格式没有变化,启用systemd-resolved之后设置依然通过修改/etc/resolv.conf文件。

本节参考链接

SysV兼容性

Systemd 提供了和 Sysvinit 以及 LSB initscripts 兼容的特性。 系统中已经存在的服务和进程无需修改。这降低了系统向 systemd 迁移的成本,使得 systemd 替换现有初始化系统成为可能。

请尽量按照标准编写LSBInit Scripts,若不符合标准可能带来兼容性问题,具体兼容性问题需要进一步调研。 标准化启动脚本和改写为systemd service单元文件是更长远和低成本的选择。

注:Systemd 214 之后“The support for SysV and LSB init scripts has been reomved from the systemd daemon itself”,取而代之的,systemd将会有一个生成器根据这些脚本生成systemd原生的unit文件。对于此生成器如何处理依赖关系、runlevel暂时未知。

The support for SysV and LSB init scripts has been removedfrom the systemd daemon itself. Instead, it is nowimplemented as a generator that creates native systemd unitsfrom these scripts when needed. This enables us to remove asubstantial amount of legacy code from PID 1, following thefact that many distributions only ship a very small numberof LSB/SysV init scripts nowadays.

service与systemctl命令

systemd中除了提供systemctl(用户手册)用于控制管理服务,也提供了老式的service命令管理服务。 但是查看service脚本文件,即可发现若系统安装了systemd之后使用service命令的时候实际上是调用systemctl命令:

/usr/sbin/service(debian下路径与官方博客中的/sbin/service不同)

service script

可知实际调用的是systemctl ${ACTION} ${UNIT} ,其实如果使用service status [NAME]也可发现返回的结果是systemd类型的服务进程状态。 所以servicesystemctl都可以对/etc/init.d/和systemd的.service进行操作管理。若存在同名的服务,systemd的.serviced单元优先级高于sysv脚本。

不兼容点(注意点)

Systemd仍然与SysV/LSB存在一些不兼容的地方和注意的点,罗列如下:

  • 各个发行版本对LSB/SysV初始化脚本进行的一些定制扩展,例如openSUSE对LSB头部内容进行了扩展,存在# X-Start-Before:# X-Stop-After:等专有的行。Systemd目前不支持此类扩展。
  • 不推荐使用/etc/init.d/xxx来管理旧的服务进程,建议使用service命令。
    • "invoking the init script directly has always been suboptimal since too much of the caller's execution context (environment block, umask, resource limits, audit trails, ...) ended up being inherited by the service, and invocation via "/sbin/service" used to clean this up at least partially. "
  • 若sysv脚本中LSB头部中依赖信息缺少或者不正确,systemd会全部解析并在运行时候尽量遵循解析的规则。为了保证服务正常运行,请在LSB头部清晰的、正确的定义依赖关系。
  • systemd下的启动脚本都有超时设置。
  • service单元执行的时候没有附带任何上下文环境,甚至没有进行$HOME目录的设置。对这些有依赖的启动脚本将无法正常工作。
  • service单元无法从stdin读取内容,默认连接到/dev/null。即不支持交互式启动脚本(i.e. Debian's X-Interactive in the LSB header)。
  • 不支持其他控制操作,只支持标准的start,stop,restart等等。
  • 标准的控制操作(i.e start,stop,restart..)不支持附加的参数。
  • systemd只停止正在运行的服务。
    • 对具体使用似乎没什么影响。
  • /sbin/chkconfig可能返回误导性的内容,所以请使用systemctl命令。
    • chkconfig常见使用命令用systemctl替代:
    • chkconfig servicename on : systemctl enable servicename.service
    • chkconfig servicename off :systemctl disable servicename.service
    • chkconfig --list :systemctl list-unit-files --type=service(preferred) 或者 ls /etc/systemd/system/*.wants/
    • chkconfig servicename --list: ls /etc/systemd/system/*.wants/servicename.service
    • chkconfig servicename --add :systemctl daemon-reload
  • Early boot runlevels as they are used by some distributions are no longer supported. i.e. "fake", distribution-specific runlevels such as "S" or "b" cannot be used with systemd.
  • System V services are not permitted to acquire realtime scheduling, even with root privileges.My Service Can't Get Realtime!

将SysV init脚本转化为Systemd Service单元文件(实例)

如果情况允许应该尽量将旧的sysv init脚本手动改写为systemd的service单元文件,不仅仅意味着不用担心兼容性问题,原生的service文件在使用上更能与systemd的其他单元文件配合,也同时能享受systemd带来的诸多特性与便利。

以下是一个将sysv init脚本转化为service文件的例子(来自systemd作者Blog):

/usr/sbin/abrtd( Automatic Bug Reporting Tool,Fedora发行版本中常见的默认工具)

#!/bin/bash
# Starts the abrt daemon
#
# chkconfig: 35 82 16
# description: Daemon to detect crashing apps
# processname: abrtd
### BEGIN INIT INFO
# Provides: abrt
# Required-Start: $syslog $local_fs
# Required-Stop: $syslog $local_fs
# Default-Stop: 0 1 2 6
# Default-Start: 3 5
# Short-Description: start and stop abrt daemon
# Description: Listen to and dispatch crash events
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions
ABRT_BIN="/usr/sbin/abrtd"
LOCK="/var/lock/subsys/abrtd"
OLD_LOCK="/var/lock/subsys/abrt"
RETVAL=0

#
# Set these variables if you are behind proxy
#
#export http_proxy=
#export https_proxy=

#
# See how we were called.
#

check() {
        # Check that we're a privileged user
        [ "`id -u`" = 0 ] || exit 4

        # Check if abrt is executable
        test -x $ABRT_BIN || exit 5
}

start() {

        check

        # Check if it is already running
        if [ ! -f $LOCK ] && [ ! -f $OLD_LOCK ]; then
                echo -n $"Starting abrt daemon: "
                daemon $ABRT_BIN
                RETVAL=$?
                [ $RETVAL -eq 0 ] && touch $LOCK
                echo
        fi
        return $RETVAL
}

stop() {

        check

        echo -n $"Stopping abrt daemon: "
        killproc $ABRT_BIN
        RETVAL=$?
        [ $RETVAL -eq 0 ] && rm -f $LOCK
        [ $RETVAL -eq 0 ] && rm -f $OLD_LOCK
        echo
        return $RETVAL
}


restart() {
        stop
        start
}

reload() {
        restart
}

case "$1" in
start)
        start
        ;;
stop)
        stop
        ;;
reload)
        reload
        ;;
force-reload)
        echo "$0: Unimplemented feature."
        RETVAL=3
        ;;
restart)
        restart
        ;;
condrestart)
        if [ -f $LOCK ]; then
                restart
        fi
        # update from older version
        if [ -f $OLD_LOCK ]; then
                restart
        fi
        ;;
status)
        status abrtd
        RETVAL=$?
        ;;
*)
        echo $"Usage: $0 {start|stop|status|restart| \
               condrestart|reload|force-reload}"
        RETVAL=2
esac

exit $RETVAL

转化为等价的service文件abrt.service

[Unit]
Description=Daemon to detect crashing apps
After=syslog.target

[Service]
ExecStart=/usr/sbin/abrtd
Type=forking

[Install]
WantedBy=multi-user.target

通过上面这个例子,我们能明显的感觉到sysv init脚本转化为service文件之后,变得非常短小(115行变为10行),也非常易懂。在service文件中, 大量的细节被隐藏,只需设置常见的脚本描述、依赖关系、执行路径等,另外在service文件中更多进行更多的设置,例如对服务进程资源的限制、工作路径的限制等等。

  • 关于service文件的编写规则将在专门的文档中描述。
  • 关于本例子转换的更多细节请单击下文作者blog的文章链接。

本节参考链接

container(systemd-nspawn)

systemd中可以在service文件中指定RootDirectory来进行chroot,具体请查看进程权限与安全管理一节, 但是systemd本身提供了比chroot更先进和方便的轻量级命名空间(Linux Namespace)容器管理工具:systemd-nspawn。 我们可以使用systemd-nspawn非常简单的在系统中创建简单的轻量级的容器,而且它比chroot更安全(对宿主OS的隔离更彻底), systemd-nspawn会自动在容器中挂载/proc,/sys节点,整体操作上更加简单。 Lennart的blog中列出了4点systemd-naspawn的优点如下[本节参考链接1]:

  • It's really easy to use. No need to manually mount /proc and /sys into your chroot() environment. The tool will do it for you and the kernel automatically cleans it up when the container terminates.
  • The isolation is much more complete, protecting the host OS from accidental changes from inside the container.
  • It's so good that you can actually boot a full OS in the container, not just a single lonesome shell.
  • It's actually tiny and installed everywhere where systemd is installed. No complicated installation or setup.

关于systemd-nspawn命令的使用和更多用例子请查看本节参考链接[3], 一个简单的实例(debian-stable-i386):

# debootstrap --arch=i386 stable ~/debian-tree/ 
# systemd-nspawn -D ~/debian-tree/

执行结果见图 systemd-nspawn-debian-stable。

systemd-nspawn-debian-stable

systemd默认存在与systemd-nsapwn相关的service单元模板文件(关于模板文件请查看基础--进程管理--instandtiated service 一节),可用于配置开机启动容器。

/lib/systemd/system/systemd-nspawn@.service:

[Unit]
Description=Container %i
Documentation=man:systemd-nspawn(1)

[Service]
ExecStart=/usr/bin/systemd-nspawn -bjD /var/lib/container/%i
Type=notify

[Install]
WantedBy=multi-user.target

根据这个service文件,我们可知,只需要将容器目录移动到/var/lib/container/下或者创建链接到此目录(container默认不存在,需手动创建),然后使对应服务单元开启自启动即可。

以上文创建的debian-tree容器为例:

# mkdir -p /var/lib/container/
# ln -s ~/debian-tree /var/lib/container/debian-tree
# systemctl enable systemd-nspawn@debian-tree

注意:实验过程中遇到的一个已知的bug(kernel >= 3.14)

kernel auditing is broken when used with systemd's container code. When using systemd in conjunction with containers, please make sure to either turn off auditing at runtime using the kernel command line option "audit=0", or turn it off at kernel compile time using: CONFIG_AUDIT=n

另外可使用macinectl查看与管理系统中的容器,具体用法请查看本节参考链接[2,4],注意参考链接4为systemd-215的用户手册,不同版本的功能上可能有略微差异,具体请man machinectl

本节参考链接

  1. Changing Roots
  2. Arch systemd container
  3. systemd-nspawn
  4. machinectl

Systemd sysusers

注:sysusers 是systemd 215新加入的工具,用于添加系统用户和用户组(非普通用户)。

systemd-sysusers 使用 /usr/lib/sysusers.d/*.conf下的配置文件后直接访问/etc/passwd/etc/group文件创建系统用户和用户组在系统启动的时候或者软件包安装的时候(注:此工具不支持创建非系统用户和用户组)。

配置文件格式

# Type Name ID GECOS
u httpd 440 "HTTP User"
u authd /usr/bin/authd "Authorization user"
g input - -
m authd input
  • Type为操作类型
  • u:创建未存在的系统用户。用户的主用户组将是与其同名的用户组。shell是/sbin/login,home目录为/。此类用户不允许登录。
  • g:创建未存在的系统用户组。无密码设置。
  • m:添加一个系统用户至一个用户组。若用户或者用户组不存在,将自动创建。
  • Name为用户名
  • ID为用户ID,若未指定(-),将自动生成。
  • GECOS为所创建的系统用户简短的描述说明

注:若用户或用户组已存在,systemd-sysusers不会做任何操作,不会覆盖已存在的用户或用户组。

优势

systemd在 sysusers.d/下有两个配置文件,包含最小系统所需要的基础系统用户和用户组,systemd-sysusers将在early boot 创建这些系统用户和用户组,这个特性对于启动时候/etc目录为空的系统非常有用(factory resets and volatile systems)。

本节参考链接

Snapshotting of systemd state

Systemd的快照功能不是操作系统的快照,而是systemd本身运行状态(systemd中各单元与服务的状态)的快照。systemd中的.snapshot 单元与其.target单元类似,都只是引用其他的单元。 由于Systemd支持按需启动(例如一个socket配置单元对应一个service单元,当有连接进入socket时候,启动对应服务),导致系统运行状态多变,使用快照我们可以保存systemd中各单元的状态,以及回滚恢复到某个状态。比如系统当前正运行服务A和B,可以对当前系统运行状况创建快照,然后将进程A停止,或者做其他的任意的对系统的改变,比如启动新的进程C。在这些改变之后,运行快照恢复命令,就可立即将系统恢复到快照时刻的状态,即只有服务A,B在运行。

一个可能的应用场景是调试:比如服务器出现一些异常,为了调试可将当前状态保存为快照,然后可以进行任意的操作,比如停止服务等等。等调试结束,恢复快照即可。

具体操作

与其他配置单元不同,快照单元不是通过磁盘上的配置文件进行管理,而是通过systemctl snapshot命令进行动态生成和管理,保存在内存中。

生成快照:

$ sudo systemctl snapshot fpm1
fpm1.snapshot

$ sudo systemctl snapshot #未指定快照名称时,将默认生成 snapshot-N.snaphshot
snapshot-1.snapshot

$ sudo systemctl snapshot
snapshot-2.snashot

查看所有快照,及其状态:

$sudo systemctl -all list-units|grep snapshot
fpm1.snapshot              loaded inactive dead      fpm1.snapshot
snapshot-1.snapshot        loaded inactive dead      snapshot-1.snapshot
snapshot-2.snapshot        loaded inactive dead      snapshot-2.snapshot

查看某个快照内容:

$ sudo systemctl show fpm1

Id=fpm1.service
Names=fpm1.service
Description=fpm1.service
LoadState=error
ActiveState=inactive
SubState=dead
InactiveExitTimestampMonotonic=0
ActiveEnterTimestampMonotonic=0
ActiveExitTimestampMonotonic=0
InactiveEnterTimestampMonotonic=0
CanStart=yes
CanStop=yes
CanReload=no
CanIsolate=no
StopWhenUnneeded=no
RefuseManualStart=no
RefuseManualStop=no
AllowIsolate=no
DefaultDependencies=yes
OnFailureIsolate=no
IgnoreOnIsolate=no
IgnoreOnSnapshot=no
NeedDaemonReload=no
JobTimeoutUSec=0
ConditionTimestampMonotonic=0
ConditionResult=no
LoadError=org.freedesktop.DBus.Error.FileNotFound "No such file or directory"
Restart=no
NotifyAccess=none
RestartUSec=100ms
TimeoutUSec=1min 30s
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
WatchdogUSec=0
WatchdogTimestampMonotonic=0
StartLimitInterval=10000000
StartLimitBurst=5

....

删除快照:

$ sudo systemctl delete fpm1

还原快照:

$sudo systemctl isolate snapshot-1.snapshot

注:快照是保存在内存中,关机后即丢失,即不可以本次系统运行时保存快照,重启之后再恢复到该快照。

注:快照功能在systemd中并不完善,似乎开发人员也没有特别关注它,因此有报告指出它存在一些使用上的问题,使用需谨慎。

本节参考链接

2016-03-18 Systemd