一、Systemd
systemd是一系列工具的集合,提供了一个系统和服务管理器,运行为 PID 1 并负责启动其它程序。其作用也远远不仅是启动操作系统,它还接管了后台服务、结束、状态查询、以及日志归档、设备管理、电源管理、定时任务等许多职责,并支持通过特定事件和特定端口触发的on-demand任务。
unit表示不同类型的systemd对象,通过配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息。
- service unit:文件扩展名为.service, 用于定义系统服务,封装了一个被 systemd 监视与控制的进程
- socket unit:文件扩展名为.socket, 定义进程间通信用的socket文件,也可在系统启动时,延迟启动服务,实现按需启动
- target unit:文件扩展名为.target,用于模拟实现运行级别,封装了一个由 systemd 管理的启动目标, 用于在启动过程中将一组单元汇聚到一个众所周知的同步点
- device unit:文件扩展名为.device, 用于定义内核识别的设备,封装了一个位于 sysfs/udev中的设备
- mount unit:文件扩展名为.mount, 封装了一个由 systemd 管理的文件系统挂载点
- automount unit:文件扩展名为.automount,封装了一个由 systemd 管理的 文件系统自动挂载点
- swap unit:文件扩展名为.swap, 用于标识swap设备,封装了一个由 systemd 管理的 swap设备或swap文件
- path unit:文件扩展名为.path,用于定义文件系统中的一个文件或目录使用,常用于当文件系统变化时,延迟激活服务,封装了一组由 systemd 监视的文件系统路径,以支持基于路径的启动
- timer unit:文件扩展名为.timer,用于定时器单元配置,封装了一个由 systemd 管理的定时器, 以支持基于定时器的启动
- slice unit:文件扩展名为.slice,用于封装管理一组进程资源占用的控制组的 slice 单元
- scope unit:文件扩展名为.scope,范围(scope)单元并不通过单元文件进行配置, 而是仅能以编程的方式通过 systemd D-Bus 接口创建。
- snapshot unit:文件扩展名为.snapshot,Systemd快照,可以切回某个快照
二、Systemd配置文件
1、配置文件位置
Systemd使用单元(Units)来管理系统服务和程序。系统单元使用配置文件来控制其相关操作。单元配置文件有三种类型:默认单元配置文件,系统特定的单元配置文件和运行时的单元配置文件。
- 默认单元配置文件 -
/usr/lib/systemd/system(当安装新软件包时,在安装过程中,单元配置文件会在/usr/lib/systemd/system目录中生成)
- 运行时的配置文件 -
/run/systemd/system(分别在units启动和停止时,会自动生成和删除)
- 系统特定的配置文件 -
/etc/systemd/system(包含定制的单元配置。通过这些配置文件,用户可以覆盖units的默认行为)
当我们对系统服务和程序的状态进行任何更改时,例如:start, stop, enable, 和disable时,systemd读取并执行其单元配置文件。按照以下顺序检查单元配置文件。
系统特定的单元配置文件 > 运行时单元配置文件 > 默认单元配置文件
2、Unit配置文件格式
一个单元配置文件包含控制该单元的所有必需信息,例如;启动Units文件的路径,在Units之前和之后需要启动的 service/units 的名称,文档、手册的位置,依赖项信息,冲突信息等。Unit配置文件中的信息通常分为三部分。[Unit],[Type], [Install]
(1)Unit
该部分通常包含 描述、文档、与其他程序依赖的设置、包括在什么服务 之前 或者 之后 启动该Units的设置等。
- Description:该语句提供简要的描述。可以在systemctl list-units或者systemctl status [Units]时看到描述。
- Documentation:该语句提供手册(帮助文档)页面的位置以及访问手册页面的命令。
- After:该语句列出了在该单元之后应激活的单元。仅仅是规范服务启动的顺序,并没有强制要求启动。
- Before:该语句列出了在该单元之前应激活的单元。仅仅是规范服务启动的顺序,并没有强制要求启动。
- Wants:定义该单元启动之后还需要启动哪些unit。
- Requires:明确了定义该单元需要在哪个单元启动之前才能启动,如果前面的unit没有启动,那么该unit也不会被启动。
- BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前Unit停止运行
- PartOf:与Requires类似,仅作用Unit的停止或重启
- Conflicts:该语句列出了在启动该单元之前必须停止的单元/服务。
- Condition...:当前Unit运行必须满足的条件,否则不会运行
- ConditionArchitecture:检测是否运行于特定的硬件平台
- ConditionVirtualization:检测是否运行于(特定的)虚拟环境中
- ConditionHost:检测系统的 hostname 或者 "machine ID"
- ConditionKernelCommandLine:检测是否设置了某个特定的内核引导选项
- ConditionSecurity:检测是否启用了特定的安全模块
- ConditionCapability:检测 systemd 的 capability 集合中是否存在特定的 capabilities
- ConditionACPower:检测系统是否正在使用交流电源
- ConditionNeedsUpdate:可设为 /var 或 /etc 之一, 用于检测指定的目录是否需要更新
- ConditionFirstBoot:可设为 yes 或 no 。 用于检测 /etc 目录 是否处于未填充的原始状态 (也就是系统出厂后的首次启动)。 此选项可用于系统出厂后,首次开机时执行必要的初始化操作
- ConditionPathExists:检测指定的路径是否存在, 必须使用绝对路径
- ConditionPathExistsGlob:与 ConditionPathExists= 类似, 唯一的不同是支持通配符
- ConditionPathIsDirectory:检测指定的路径是否存在并且是一个目录,必须使用绝对路径
- ConditionPathIsSymbolicLink:检测指定的路径是否存在并且是一个软连接,必须使用绝对路径
- ConditionPathIsMountPoint:检测指定的路径是否存在并且是一个挂载点,必须使用绝对路径
- ConditionPathIsReadWrite:检测指定的路径是否存在并且可读写(rw),必须使用绝对路径
- ConditionDirectoryNotEmpty:检测指定的路径是否存在并且是一个非空的目录,必须使用绝对路径
- ConditionFileNotEmpty:检测指定的路径是否存在并且是一个非空的普通文件,必须使用绝对路径
- ConditionFileIsExecutable:检测指定的路径是否存在并且是一个可执行文件,必须使用绝对路径
- Assert...:当前Unit运行必须满足的条件,否则会报启动失败
- OnFailure:接受一个空格分隔的单元列表,当该单元进入失败("failed")状态时, 将会启动列表中的单元
- PropagatesReloadTo:接受一个空格分隔的单元列表,在 reload 该单元时,也同时 reload 所有列表中的单元
- ReloadPropagatedFrom:接受一个空格分隔的单元列表,在 reload 列表中的某个单元时,也同时 reload 该单元
- JoinsNamespaceOf:接受一个空格分隔的单元列表, 表示将该单元所启动的进程加入到列表单元的网络及 临时文件(/tmp, /var/tmp) 的名字空间中
- RequiresMountsFor:接受一个空格分隔的绝对路径列表,表示该单元将会使用到这些文件系统路径
- OnFailureJobMode:可设为 "fail", "replace", "replace-irreversibly", "isolate", "flush", "ignore-dependencies", "ignore-requirements" 之一。 默认值是 "replace"
- IgnoreOnIsolate:如果设为 yes , 那么在执行 systemctl isolate another.target 命令时,此单元不会被停止。 默认值是 no
-
StopWhenUnneeded:如果设为 yes , 那么当此单元不再被任何已启动的单元依赖时, 将会被自动停止
-
RefuseManualStart:如果设为 yes , 那么此单元将拒绝被手动启动
-
RefuseManualStop:拒绝被手动停止
-
AllowIsolate:如果设为 yes , 那么此单元将允许被 systemctl isolate 命令操作, 否则将会被拒绝
-
DefaultDependencies:默认值 yes 表示为此单元隐式地创建默认依赖
-
JobTimeoutSec:用于设置该单元等候外部任务(job)完成的最长时限
-
JobTimeoutAction:用于指定当超时发生时, 将触发什么样的额外动作
-
JobTimeoutRebootArgument:用于指定传递给 reboot(2) 系统调用的字符串参数。
-
JobTimeoutSec:是设置此单元在改变其状态的过程中,等候某个外部任务完成所能容忍的最长时间
-
StartLimitIntervalSec:用于设置时长, 默认值等于 DefaultStartLimitIntervalSec= 的值(默认为10秒)
-
StartLimitBurst:用于设置在一段给定的时长内,最多允许启动多少次, 默认值等于 DefaultStartLimitBurst= 的值(默认为5次)
一个单元的After/Before语句定义了该单元应该启动的顺序。一个单元的want/Requires语句定义了该单元的依赖关系。
(2)Type
该部分表示Unit的类型。类型有[Service],[Socket],[Timer],[Mount],[Path]等类型。
- Type:表示启动的类型,有以下几种类型:simple为默认值、forking、oneshot等类型。
- EnvironmentFile:可以有多个该语句、后面跟配置文件。
- ExecStart:后面接启动的语句
- ExecStop:后面接停止服务的语句
- ExecReload:后面接重启服务的语句
- ExecStartPre字段:启动服务之前执行的命令
- ExecStartPost字段:启动服务之后执行的命令
- ExecStopPost字段:停止服务之后执行的命令
- KillMode:该语句如果是process,当终止进程时,它会终止主程序。如果时none时,则不会关闭程序。
(3)Install
该部分时将此Unit安装到哪一个target中去。常用会安装在multi-user.target
- WantedBy:它的值是一个或多个Target,当前Unit激活时(enable)符号链接会放入/etc/systemd/system目录下面以Target名+.wants后缀构成的子目录中
- RequiredBy:它的值是一个或多个Target,当前Unit激活时,符号链接会放入/etc/systemd/system目录下面以Target 名 + .required后缀构成的子目录中
- Alias:当前Unit 可用于启动的别名
- Also:当前Unit激活(enable)时,会被同时激活的其他Unit
三、Service unit配置使用
[Service]区块用来Service的配置,只有Service类型的Unit才有这个区块。它的主要字段如下
- Type:定义启动时的进程行为。它有以下几种值。
- Type=simple:默认值,执行ExecStart指定的命令,启动主进程
- Type=forking:以fork方式从父进程创建子进程,创建后父进程会立即退出
- Type=oneshot:一次性进程,Systemd会等当前服务退出,再继续往下执行
- Type=dbus:当前服务通过D-Bus启动
- Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行
- Type=idle:若有其他任务执行完毕,当前服务才会运行
- ExecStart:启动当前服务的命令
- ExecStartPre:启动当前服务之前执行的命令
- ExecStartPost:启动当前服务之后执行的命令
- ExecReload:重启当前服务时执行的命令
- ExecStop:停止当前服务时执行的命令
- ExecStopPost:停止当其服务之后执行的命令
- RestartSec:自动重启当前服务间隔的秒数
- Restart=no(默认):退出后不会重启。
- Restart=on-success:只有正常退出时(退出状态码为0),才会重启
- Restart=on-failure:非正常退出时(退出状态码非0),包括被信号终止和超时,才会重启
- Restart=on-abnormal:只有被信号终止和超时,才会重启
- Restart=abort:只有在收到没有捕捉到的信号终止时,才会重启
- Restart=watchdog:超时退出,才会重启
- Restart=always:不管什么退出原因,总是重启
- RemainAfterExit:指定即使服务的所有进程都已退出,也应将服务视为活动的,默认为no
- GuessMainPID:指定systemd在无法可靠确定服务的主PID时是否应该猜测它,除非设置了type=forking且未设置PIDFile,否则此选项将被忽略,默认为yes
- PIDFile:指向此守护进程的PID文件的绝对文件名
- BusName:到达此服务的D-Bus总线名称。
- TimeoutSec:定义Systemd停止当前服务之前等待的秒数
- TimeoutStartSec:等待服务启动的时间
- TimeoutStopSec:等待服务停止的时间
- Environment:指定环境变量
- KillMode=control-group(默认):当前控制组里面的所有子进程都会被杀掉。
- KillMode=process:只杀主进程。
- KillMode=mixed:主进程将收到SIGTERM信号,子进程收到SIGKILL信号。
- KillMode=none:没有进程被杀掉,只执行服务的stop命令。
四、Target和Target配置
1、Target概念
Target就是一个Unit组,包含许多相关的Unit。启动某个Target的时候,Systemd就会启动里面所有的Unit。从这个意义上说,Target这个概念类似于“状态点”,启动某个Target就好比启动到某种状态。
- #查看当前系统的所有Target
$ systemctl list-unit-files --type=target - 查看一个 Target 包含的所有 Unit
$ systemctl list-dependencies multi-user.target - 查看启动时的默认 Target
$ systemctl get-default - 设置启动时的默认Target
$ sudo systemctl set-default multi-user.target - 切换Target时,默认不关闭前一个Target启动的进程,systemctl isolate命令改变这种行为,关闭前一个Target里面所有不属于后一个Target的进程
$ sudo systemctl isolate multi-user.target
另一个修改默认target方法是向bootloader添加内核参数
systemd.unit=multi-user.target
(大致相当于运行级别3)systemd.unit=rescue.target
(大致相当于运行级别1)
systemd根据已下顺序选择defult.target
内核参数 > /etc/systemd/system/default.target
软链接 > /usr/lib/systemd/system/default.target
软链接
2、target与init
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目录里面的修改可以覆盖原始设置。
3、Target配置文件
(1)Unit
- Description:该语句提供简要的描述。可以在systemctl list-units或者systemctl status [Units]时看到描述。
- Documentation:该语句提供手册(帮助文档)页面的位置以及访问手册页面的命令。
- After:该语句列出了在该单元之后应激活的单元。仅仅是规范服务启动的顺序,并没有强制要求启动。
- Before:该语句列出了在该单元之前应激活的单元。仅仅是规范服务启动的顺序,并没有强制要求启动。
- Wants:定义该单元启动之后还需要启动哪些unit。
- Requires:明确了定义该单元需要在哪个单元启动之前才能启动,如果前面的unit没有启动,那么该unit也不会被启动。
- BindsTo:与Requires类似,它指定的 Unit 如果退出,会导致当前Unit停止运行
- Conflicts:该语句列出了在启动该单元之前必须停止的单元/服务。
- Condition...:当前Unit运行必须满足的条件,否则不会运行
- Assert...:当前Unit运行必须满足的条件,否则会报启动失败
Target 配置文件里面没有启动命令
五、Systemd命令使用方式
1、使用systemctl控制
- 立即激活
# systemctl start xxx - 立即停止
# systemctl stop xxx - 重启
# systemctl restart xxx - 杀死一个服务的所有子进程
$ sudo systemctl kill xxx - 重新加载配置
# systemctl reload xxx - 输出运行状态
$ systemctl status xxx - 显示某个Unit是否正在运行
$ systemctl is-active xxx - 显示某个Unit是否处于启动失败状态
$ systemctl is-failed xxx - 检查是否配置为自动启动
$ systemctl is-enabled xxx - 开机自动激活
# systemctl enable xxx - 设置为自动启动并立即启动
# systemctl enable --now unit - 取消开机自动激活
# systemctl disable xxx - 禁用
systemctl mask xxx - 取消禁用
systemctl unmask xxx - 显示手册页
systemctl help xxx - 重新载入 systemd 系统配置,扫描文件的变动
systemctl daemon-reload - 重启系统
$ sudo systemctl reboot - 关闭系统
$ sudo systemctl poweroff
- cpu停止
$ sudo systemctl halt - 暂停系统
$ sudo systemctl suspend
- 进入休眠
$ sudo systemctl hibernate - 让系统进入交互式休眠状态
$ sudo systemctl hybrid-sleep - 启动进入救援状态(单用户状态)
$ sudo systemctl rescue - 列出正在运行的Unit
$ systemctl list-units - 列出所有Unit,包括没有找到配置文件的或者启动失败的
$ systemctl list-units --all - 列出所有没有运行的Unit
$ systemctl list-units --all --state=inactive - 列出所有加载失败的Unit
$ systemctl list-units --failed - 列出所有正在运行的、类型为service的Unit
$ systemctl list-units --type=service - 显示某个 Unit 的所有底层参数
$ systemctl show xxx - 列出一个Unit的所有依赖
$ systemctl list-dependencies xxx - 列出所有配置文件
$ systemctl list-unit-files - 列出指定类型的配置文件
$ systemctl list-unit-files --type=service
2、systemd-analyze用于查看启动耗时
- 查看启动耗时
$ systemd-analyze - 查看每个服务的启动耗时
$ systemd-analyze blame - 显示瀑布状的启动过程流
$ systemd-analyze critical-chain - 显示指定服务的启动流
$ systemd-analyze critical-chain atd.service
3、hostnamectl用于查看当前主机的信息
- 显示当前主机的信息
$ hostnamectl - 设置主机名。
$ sudo hostnamectl set-hostname rhel7
4、localectl用于查看本地化设置
- 查看本地化设置
$ localectl - 设置本地化参数。
$ sudo localectl set-locale LANG=en_GB.utf8
$ sudo localectl set-keymap en_GB
5、timedatectl用于查看当前时区设置
- 查看当前时区设置
$ timedatectl - 显示所有可用的时区
$ timedatectl list-timezones - 设置当前时区
$ sudo timedatectl set-timezone America/New_York
$ sudo timedatectl set-time YYYY-MM-DD
$ sudo timedatectl set-time HH:MM:SS
6、loginctl用于查看当前登录的用户
- 列出当前session
$ loginctl list-sessions - 列出当前登录用户
$ loginctl list-users - 列出显示指定用户的信息
$ loginctl show-user ruanyf
六、日志管理
Systemd统一管理所有Unit的启动日志,日志的配置文件是/etc/systemd/journald.conf
- 查看所有日志(默认情况下 ,只保存本次启动的日志)
$ 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-10" --until "2015-01-11 03:00"
$ sudo journalctl --since 09:00 --until "1 hour ago" - 显示尾部的最新10行日志
$ sudo journalctl -n - 实时滚动显示最新日志
$ 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 的日志
$ 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.serviceqq -o json-pretty - 显示日志占据的硬盘空间
$ sudo journalctl --disk-usage - 指定日志文件占据的最大空间
$ sudo journalctl --vacuum-size=1G - 指定日志文件保存多久
$ sudo journalctl --vacuum-time=1years
七、在项目中集成打包
1、服务程序建立
在源码的/A744/Linux_for_Tegra/mogo/Common/service下建立自己的服务
(1)服务配置文件xxxx.service
[Unit] Description=uartd After=graphical.target RefuseManualStart=no [Service] Type=simple ExecStart=/usr/local/bin/uartd -d /dev/ttyUSB0 -b 9600 Restart=always RestartSec=1 [Install] WantedBy=graphical.target |
(2)服务程序(bin或sh等)
此处为uartd可执行程序
(3)软连接,(enable service)
link/mogo_ldisc.service使用以下命令建立
ln -s /lib/systemd/system/mogo_ldisc.service mogo_ldisc.service |
2、服务程序打包
(1)打包服务控制 A744/Linux_for_Tegra/mogo/Common/Common.conf,控制打包时候的执行顺序
# Mogo customize modules install config # Install from top to bottom pip deb bin system_modify system_version time_sync boot_start software_config system_streamline startup_optimization ptp_service ldisc_service |
(2)打包脚本 xxxx_apply.sh
cp uartd $BASE_PATH/rootfs/usr/local/bin/uartd cp mogo_ldisc.service $BASE_PATH/rootfs/lib/systemd/system/ cp -d link/mogo_ldisc.service $BASE_PATH/rootfs/etc/systemd/system/graphical.target.wants/ |
参考:
systemd.index 中文手册 systemd.index 中文手册 [金步国]