下面针对技术人员的不同角色来简单地介绍一下 systemd 的使用。本文只打算给出简单的描述,让您对 systemd 的使用有一个大概的理解。具体的细节内容太多,即无法在一篇短文内写全,本人也没有那么强大的能力。还需要读者自己去进一步查阅 systemd 的文档。
系统软件开发人员开发人员需要了解 systemd 的更多细节。比如您打算开发一个新的系统服务,就必须了解如何让这个服务能够被 systemd 管理。这需要您注意以下这些要点:
后台服务进程代码不需要执行两次派生来实现后台精灵进程,只需要实现服务本身的主循环即可。
不要调用 setsid(),交给 systemd 处理
不再需要维护 pid 文件。
Systemd 提供了日志功能,服务进程只需要输出到 stderr 即可,无需使用 syslog。
处理信号 SIGTERM,这个信号的唯一正确作用就是停止当前服务,不要做其他的事情。
SIGHUP 信号的作用是重启服务。
需要套接字的服务,不要自己创建套接字,让 systemd 传入套接字。
使用 sd_notify()函数通知 systemd 服务自己的状态改变。一般地,当服务初始化结束,进入服务就绪状态时,可以调用它。
Unit 文件的编写
对于开发者来说,工作量最大的部分应该是编写配置单元文件,定义所需要的单元。
举例来说,开发人员开发了一个新的服务程序,比如 httpd,就需要为其编写一个配置单元文件以便该服务可以被 systemd 管理,类似 UpStart 的工作配置文件。在该文件中定义服务启动的命令行语法,以及和其他服务的依赖关系等。
此外我们之前已经了解到,systemd 的功能繁多,不仅用来管理服务,还可以管理挂载点,定义定时任务等。这些工作都是由编辑相应的配置单元文件完成的。我在这里给出几个配置单元文件的例子。
下面是 SSH 服务的配置单元文件,服务配置单元文件以.service 为文件名后缀。
#cat /etc/system/system/sshd.service [Unit] Description=OpenSSH server daemon [Service] EnvironmentFile=/etc/sysconfig/sshd ExecStartPre=/usr/sbin/sshd-keygen ExecStart=/usrsbin/sshd –D $OPTIONS ExecReload=/bin/kill –HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s [Install] WantedBy=multi-user.target
文件分为三个小节。第一个是[Unit]部分,这里仅仅有一个描述信息。第二部分是 Service 定义,其中,ExecStartPre 定义启动服务之前应该运行的命令;ExecStart 定义启动服务的具体命令行语法。第三部分是[Install],WangtedBy 表明这个服务是在多用户模式下所需要的。
那我们就来看下 multi-user.target 吧:
#cat multi-user.target [Unit] Description=Multi-User System Documentation=man.systemd.special(7) Requires=basic.target Conflicts=rescue.service rescure.target After=basic.target rescue.service rescue.target AllowIsolate=yes [Install] Alias=default.target
第一部分中的 Requires 定义表明 multi-user.target 启动的时候 basic.target 也必须被启动;另外 basic.target 停止的时候,multi-user.target 也必须停止。如果您接着查看 basic.target 文件,会发现它又指定了 sysinit.target 等其他的单元必须随之启动。同样 sysinit.target 也会包含其他的单元。采用这样的层层链接的结构,最终所有需要支持多用户模式的组件服务都会被初始化启动好。
在[Install]小节中有 Alias 定义,即定义本单元的别名,这样在运行 systemctl 的时候就可以使用这个别名来引用本单元。这里的别名是 default.target,比 multi-user.target 要简单一些。。。
此外在/etc/systemd/system 目录下还可以看到诸如*.wants 的目录,放在该目录下的配置单元文件等同于在[Unit]小节中的 wants 关键字,即本单元启动时,还需要启动这些单元。比如您可以简单地把您自己写的 foo.service 文件放入 multi-user.target.wants 目录下,这样每次都会被默认启动了。
最后,让我们来看看 sys-kernel-debug.mout 文件,这个文件定义了一个文件挂载点:
#cat sys-kernel-debug.mount [Unit] Description=Debug File Syste DefaultDependencies=no ConditionPathExists=/sys/kernel/debug Before=sysinit.target [Mount] What=debugfs Where=/sys/kernel/debug Type=debugfs
这个配置单元文件定义了一个挂载点。挂载配置单元文件有一个[Mount]配置小节,里面配置了 What,Where 和 Type 三个数据项。这都是挂载命令所必须的,例子中的配置等同于下面这个挂载命令:
mount –t debugfs /sys/kernel/debug debugfs
配置单元文件的编写需要很多的学习,必须参考 systemd 附带的 man 等文档进行深入学习。希望通过上面几个小例子,大家已经了解配置单元文件的作用和一般写法了。
系统管理员systemd 的主要命令行工具是 systemctl。
多数管理员应该都已经非常熟悉系统服务和 init 系统的管理,比如 service、chkconfig 以及 telinit 命令的使用。systemd 也完成同样的管理任务,只是命令工具 systemctl 的语法有所不同而已,因此用表格来对比 systemctl 和传统的系统管理命令会非常清晰。
表 2. Systemd 命令和 sysvinit 命令的对照表 Sysvinit 命令Systemd 命令备注service foo start systemctl start foo.service 用来启动一个服务 (并不会重启现有的)
service foo stop systemctl stop foo.service 用来停止一个服务 (并不会重启现有的)。
service foo restart systemctl restart foo.service 用来停止并启动一个服务。
service foo reload systemctl reload foo.service 当支持时,重新装载配置文件而不中断等待操作。
service foo condrestart systemctl condrestart foo.service 如果服务正在运行那么重启它。
service foo status systemctl status foo.service 汇报服务是否正在运行。
ls /etc/rc.d/init.d/ systemctl list-unit-files --type=service 用来列出可以启动或停止的服务列表。
chkconfig foo on systemctl enable foo.service 在下次启动时或满足其他触发条件时设置服务为启用
chkconfig foo off systemctl disable foo.service 在下次启动时或满足其他触发条件时设置服务为禁用
chkconfig foo systemctl is-enabled foo.service 用来检查一个服务在当前环境下被配置为启用还是禁用。
chkconfig –list systemctl list-unit-files --type=service 输出在各个运行级别下服务的启用和禁用情况
chkconfig foo –list ls /etc/systemd/system/*.wants/foo.service 用来列出该服务在哪些运行级别下启用和禁用。
chkconfig foo –add systemctl daemon-reload 当您创建新服务文件或者变更设置时使用。
telinit 3 systemctl isolate multi-user.target (OR systemctl isolate runlevel3.target OR telinit 3) 改变至多用户运行级别。
除了表 2 列出的常见用法,系统管理员还需要了解其他一些系统配置和管理任务的改变。
首先我们了解 systemd 如何处理电源管理,命令如下表所示:
表 3,systemd 电源管理命令 命令操作systemctl reboot 重启机器
systemctl poweroff 关机
systemctl suspend 待机
systemctl hibernate 休眠
systemctl hybrid-sleep 混合休眠模式(同时休眠到硬盘并待机)
关机不是每个登录用户在任何情况下都可以执行的,一般只有管理员才可以关机。正常情况下系统不应该允许 SSH 远程登录的用户执行关机命令。否则其他用户正在工作,一个用户把系统关了就不好了。为了解决这个问题,传统的 Linux 系统使用 ConsoleKit 跟踪用户登录情况,并决定是否赋予其关机的权限。现在 ConsoleKit 已经被 systemd 的 logind 所替代。
logind 不是 pid-1 的 init 进程。它的作用和 UpStart 的 session init 类似,但功能要丰富很多,它能够管理几乎所有用户会话(session)相关的事情。logind 不仅是 ConsoleKit 的替代,它可以:
维护,跟踪会话和用户登录情况。如上所述,为了决定关机命令是否可行,系统需要了解当前用户登录情况,如果用户从 SSH 登录,不允许其执行关机命令;如果普通用户从本地登录,且该用户是系统中的唯一会话,则允许其执行关机命令;这些判断都需要 logind 维护所有的用户会话和登录情况。
Logind 也负责统计用户会话是否长时间没有操作,可以执行休眠/关机等相应操作。
为用户会话的所有进程创建 CGroup。这不仅方便统计所有用户会话的相关进程,也可以实现会话级别的系统资源控制。
负责电源管理的组合键处理,比如用户按下电源键,将系统切换至睡眠状态。
多席位(multi-seat) 管理。如今的电脑,即便一台笔记本电脑,也完全可以提供多人同时使用的计算能力。多席位就是一台电脑主机管理多个外设,比如两个屏幕和两个鼠标/键盘。席位一使用屏幕 1 和键盘 1;席位二使用屏幕 2 和键盘 2,但他们都共享一台主机。用户会话可以自由在多个席位之间切换。或者当插入新的键盘,屏幕等物理外设时,自动启动 gdm 用户登录界面等。所有这些都是多席位管理的内容。ConsoleKit 始终没有实现这个功能,systemd 的 logind 能够支持多席位。
以上描述的这些管理功能仅仅是 systemd 的部分功能,除此之外,systemd 还负责系统其他的管理配置,比如配置网络,Locale 管理,管理系统内核模块加载等,完整地描述它们已经超出了本人的能力。
systemd 小结在不才作者看来,作为系统初始化系统,systemd 的最大特点有两个:
令人惊奇的激进的并发启动能力,极大地提高了系统启动速度;
用 CGroup 统计跟踪子进程,干净可靠。
此外,和其前任不同的地方在于,systemd 已经不仅仅是一个初始化系统了。
Systemd 出色地替代了 sysvinit 的所有功能,但它并未就此自满。因为 init 进程是系统所有进程的父进程这样的特殊性,systemd 非常适合提供曾经由其他服务提供的功能,比如定时任务 (以前由 crond 完成) ;会话管理 (以前由 ConsoleKit/PolKit 等管理) 。仅仅从本文皮毛一样的介绍来看,Systemd 已经管得很多了,可它还在不断发展。它将逐渐成为一个多功能的系统环境,能够处理非常多的系统管理任务,有人甚至将它看作一个操作系统。
好的一点是,这非常有助于标准化 Linux 的管理!从前,不同的 Linux 发行版各行其事,使用不同方法管理系统,从来也不会互相妥协。比如如何将系统进入休眠状态,不同的系统有不同的解决方案,即便是同一个 Linux 系统,也存在不同的方法,比如一个有趣的讨论:如何让 ubuntu 系统休眠,可以使用底层的/sys/power/state 接口,也可以使用诸如 pm-utility 等高层接口。存在这么多种不同的方法做一件事情对像我这样的普通用户而言可不是件有趣的事情。systemd 提供统一的电源管理命令接口,这件事情的意义就类似全世界的人都说统一的语言,我们再也不需要学习外语了,多么美好!
如果所有的 Linux 发行版都采纳了 systemd,那么系统管理任务便可以很大程度上实现标准化。此外 systemd 有个很棒的承诺:接口保持稳定,不会再轻易改动。对于软件开发人员来说,这是多么体贴又让人感动的承诺啊!
结束语本系列文章从古老却简明稳定的 sysvinit 说起,接着简要描述了 UpStart 带来的清新改变,最后看到了充满野心和活力的新生代 systemd 系统逐渐统治 Linux 的各个版本。就好像在看我们这个世界,一代人老去,新的一代带着横扫一切的气概登上舞台,还没有喊出他们最有力的口号,更猛的一代已经把聚光灯和所有的目光带走。Systemd 之后也许还有更新的 init 系统出现吧,让我们继续期待。。。