systemd是CentOS7所使用的全新的init程序.
Systemd:
POST -> Boot Sequence -> Bootloader -> kernel + initramfs(initrd) -> rootfs -> /sbin/init
systemd的架构图:
Systemd
之前就已经说过, CnetOS5,6上的运行级别这个概念在systemd上已经失去了意义.但是systemd依然可以兼容之前的SysV init脚本, 但是即使不使用脚本, systemd仍然可以进行服务的启动.但是, 当然, 使用脚本的启动速度是很慢的.
接下来说一下Systemd的新特性有哪些:
- 实现系统引导的时候服务的并行启动
- 可以实现按需激活进程, 也就是说在需要这个进程的时候才去激活它, 这样就比较节省资源
- 支持系统状态快照 ( 蛤?这也可以?没用过呢…)
- 基于依赖关系来定义服务控制逻辑
因此到了CentOS7上, systemd已经完全取代了之前的init.
这么说来, CentOS6所使用的Startup init是十分短命的, 而当时Systemd的开发者就已经建议RH使用Systemd instead of StartUp了, 然而我们都知道RH以安全著称, 因此并没有使用. 当时的新版Fedora就使用了(小白鼠).
对于Systemd而言有一个核心概念 – unit 也就是单元
而这个unit的配置主要是依靠其配置文件进行标示和配置: 文件主要包括了系统服务,监听的套接字, 保存的系统快照以及其他和init相关的信息. 每一个unit都有一个配置文件. 这些配置文件都保存在这些位置:
/usr/lib/systemd/system
&& /run/systemd/system
&&/etc/systemd/system
目前我们可以简单的把unit当做之前的一个一个服务脚本, 负责进行服务的启动, 重载, 终止, 重启等等… 但要明确的是, 决不能把unit和这些服务脚本画上等号. 这是因为, unit除了进行这些服务的管理之外还有别的功能.归根结底: unit是有类型的
Unit的类型
其中最多最重要的就是这个服务类型的unit,叫做Service Unit
这些文件的扩展名就是*.service
比如: httpd.service sshd.service crond.service
等等
在之前说init的时候, 我们可以在/etc/rc.d/init.d/
里面看到许许多多的的服务脚本 而在systemd来看这些类似的东西都放在/usr/lib/systemd/system
里面, 这个目录里还有很多其他扩展名的东西: path target wants …
而且如你所见, 这些文件不需要执行权限 因为他们仅仅是systemd的配置文件.
除开service, 第二重要的配置文件就是target类型的, 叫做目标单元. 主要用于模拟实现”运行级别”
第三种叫做device unit, 文件扩展名就是device, 这个文件主要用来负责定义内核识别的设备.
接着还有进行文件系统挂载的mount unit, 也就是用来定义文件系统挂载点
还有socket unit, 后缀名.socket, 用来标识进程间进行通信的socket文件.
另外, 还有snapshot unit, 后缀名就叫做.snapshot, 用于管理系统快照.
下一个swap unit, 后缀.swap, 用来干什么也很容易就知道了: 表示和管理swap设备.
最后还有两项, 一个后缀是叫.automount, 用来定义文件系统的自动挂载点, 以及Path unit, 后缀名就是.path, 用来定义文件系统中与一个文件或者一个目录. 仅在某些特定的场景下才会使用.
以上这些就是unit的类型, 用一张图来说明就是:
systemd的关键特性
基于socket的激活机制
在系统引导的时候systemd对所有支持这种模式的服务, 分别创建需要监听的套接字, 并在服务启动之后, 立即将这个套接字传递给它.
这样做的好处是: 可以实现多个服务的并行启动, 而且如果用不到这个服务的时候我就不启动, 反正套接字创建好了(我不关心服务的启动与否),这样当有人访问套接字, systemd就会收到, 接着就可以去激活相应的进程服务, 也就是按需激活. 这就像CentOS5,6上的超级守护进程和瞬时启动进程.
其实也就是: 1. socket和服务程序分离, 由一个统一的systemd来进行启动. 2. 只要我套接字建立完毕,那么其他依赖服务都可以进行启动(因为认定已经启动), 从而实现并行启动.
基于bus的激活机制
D-bus是一个最早见于Linux的IPC实现, 用于桌面. 其实就是一个用于桌面应用的消息系统/通讯机制.
systemd可以使得所有使用D-Bus的服务在第一次访问的时候按需激活.
基于Device的激活机制
就像是在Windows上插入U盘之后就会有相应的进程被激活一样, 这一机制使得当我们有硬件上的更新(可用)的时候有systemd有能力激活相应服务.(就比如说automount)
基于Path的激活机制
也就是某个目录下文件发生变动的时候, 激活相应的程序.说白了就是特定文件路径的监控从而激活.
系统快照
就像我们所使用的vmware等虚拟化应用的暂停功能一样. systemd能够将当前系统的各个unit的临时数据(当前状态信息)进行持久化(写入磁盘..), 说白了就是保存状态. 然后再下次开机的时候载入这些文件从而使得系统恢复之前的状态.
向后兼容sysV init脚本
这个大家再熟悉不过了, 最起码systemd可以完美兼容start, stop, status, restart
这样的操作脚本. 而CentOS7 也保留了这种风格.
以上就是systemd的关键特性, 现在我们说说他和sysV不兼容(不同)的地方以及一些point
- systemd对之前sysV的系统运行级别的模拟和兼容是有限的, 0,6,3,5, 事实上systemd用不到这个东西, 他只是通过target unit来进行模拟.
- target unit和之前的运行级别是不能做对等的, 因为target unit有十几个之多.
- systemd使用systemctl来进行服务操作的命令, 其支持的子命令不仅仅是上述4个. 在sysV时代, 用户可以进行拓展和自定义脚本, 但在systemd中, 子命令是固定不变的.
- systemd只能与systemd相通信的应用通信, 也就是说非systemd的应用他没法管.(比如service启动的)
- 我们知道在init的时候, 当我们进行运行级别的切换的时候, 会执行/etc/rcX.d/init.d/对应级别的脚本, 所有K开头的都会执行stop操作, 而S的进行start操作. 但是这样存在的问题就是, 如果我的服务没有启动,还是会执行一遍stop操作, 这就是多余操作. 因此systemd就不会这样了, systemd会动态进行关闭操作, 仅关闭需要关闭以及当前正在运行的服务和程序.同理,S开头的也是.
- 系统服务不会读取来自标准输入的数据,systemd启动时不会和标准输入进行交互,他自行控制着所以服务的管理.
- 我们的系统服务不会从用户那里继承任何信息, 包括PATH等环境变量等等. 因此建议在使用应用程序使用绝对路径 这样每个服务都会在最纯净的运行环境中, 而和用户没有任何关系.
- 每个服务operation的timeout都设置成5min
管理系统服务
使用service unit, 也可以兼容早期的运行脚本. 运行的命令叫做: systemctl 完整的一个命令是: systemctl COMMAND name.service
比如我们现在以久负盛名,大名鼎鼎的httpd.service来做个实验:
1 | [root@WWW ~]# rpm -q httpd |
在旧的sysV时代, 我们的status只有一句干巴巴的说明, 服务已经启动/服务没有启动.. 现在的systemd可以提供非常详细的信息来让我们进行debug或者查看相关信息.
现在我们来列举一下systemctl
- 启动: systemctl start name.service == service name start
- 停止: systemctl stop name.service == service name stop
- 重启: systemctl restart name.service == service name restart
- 状态: systemctl status name.service == service name status
- 条件式重启: systemctl try-restart name.service == service name condrestart # 条件式重启是指: 如果这个服务启动了, 那么就停掉他再进行启动操作, 如果没有启动就不作操作.
- 查看某服务当前是否激活: systemctl is-active name.service
- 查看所有已经激活的服务: systemctl list-units
- 查看所有的 在后面加上 –all, 可以组合
- 查看特定的类型的 在后面加上 –type={target,service…}, 可以组合.
与chkconfig的对应关系:
设定某服务开机自启/关闭: chkconfig name on/off ==> systemctl enable/disable name.service
比disable更强大的禁止自启是: systemctl mask name.service 这将会连接到/dev/null, 从而使启动这些变成不可能. 翻过来就是systemctl umask name.service 可以取消mask的效果.
为了查看服务是否开机自启, 上面也已经展示了, 使用systemctl status name.service就可以了.
如果要查看所有开机自启的服务, 在chkconfig时代, 还是使用: chkconfig –list
但是systemctl就提供了非常清晰的信息:
1 | [root@WWW ~]# systemctl list-unit-files --type=service |
现在我们就来谈谈这个target unit.
我们说过这个是用来实现运行级别的模拟的. 因此所有以target结尾的文件就是用来将需要启动的服务定义在一起, 使得他们能够一起启动.
在/usr/lib/systemd/system
这个目录下, 我们可以看到:
1 | lrwxrwxrwx. 1 root root 15 Jun 25 08:38 runlevel0.target -> poweroff.target |
这些就是在模拟不同的运行级别, 可以很清晰的看到2,3,4都是一样的. 我们在使用init的时候, 切换运行等级的命令是init N. 而在systemd中使用的是以子命令的形式: systemctl isolate name.target 另外建议在使用systemd的机器上就不再要用runlevel
来查看运行等级了, 因为意义不大.当然使用也是可以使用的. 那么应该使用什么命令来查看. 在上面已经说过了!其实就是systemctl list-units --type target
这会展示当前已经加载的unit. 如果是获取默认的运行级别, 在过去使用的/etc/inittab, 现在使用的命令是systemctl get-default 如果是修改默认的运行级别呢? 过去我们要修改iinittab这个文件, 但是现在封装的更友好, 我们直接使用systemctl set-default name.target就行了. 其实这一步骤做的操作就是:
1 | [root@WWW system]# systemctl get-default |
所以默认的target就取决于这个软链接的指向.
systemd可以非常快速的切换到救急模式和紧急模式, 命令如下:
1 | [root@WWW ~]# systemctl emergency |
那么emergency和rescue的区别是什么呢? 从加载的target模块就可以看出来了. emergency更加彻底.
在CentOS6上, 我们也可以使用emergency模式, 只需要在grub的e 编辑模式下, 传递emergency这个参数就可以了.
最后我们再来说一下其他的常用命令:
关机, hhh没有想到这个我也会说吧~ 熟知的shutdown当然也可以使用, 但是你也可以使用systemct halt
. 同时也可以使用systemctl poweroff
重启就是systemctl restart
我们还可以挂起系统: 使用systemctl suspend
如果你是虚拟机在实验, 那么这个暂停我是不知道怎么恢复..如果你知道还请告知.使用systemctl hibernate
来使得机器休眠. 其实这个休眠就是systemd的快照功能, 他可以保持当前的工作状态, 当你回头重启的时候还可以继续下去. 当然, 如果不是仅仅做个快照, 还同时挂起, 就使用systemdctl hybrid-sleep
简单的说就是一个是重启, 一个是关闭啦 需要注意的是, 你的登录状态会保留, 所以还是要小心使用.
如果你的服务不能正常启动是因为依赖的话, 那么你可以使用systemctl的子命令来查看:
1 | [root@WWW ~]# systemctl list-dependencies httpd |
所依赖的会使用树形结构表示出来, 还会注明当前的激活情况.
systemd的子命令实在是太多了. 在启用之初曾被人说, 违背了UNIX的simple原则. 当然他确实强大 方便.
Unit设定文件及自定义
关于此项, 暂时忽略. 后续补充.
其他
我们知道在Linux下找回密码只要能够进入并且挂载/, 再重新设定root的密码就可以了. 以前我们使用rescue模式/单用户来操作.但在systemd上这就没有用了.
在新版的systemd 的管理机制中,预设的rescue 模式是无法直接取得root 权限的!还是得要使用root 的密码才能够登入rescure 环境!所以我们透过一个名为rd.break的核心参数来处理!只是需要注意的是, rd.break 是在Ram Disk 里面的作业系统状态,因此你不能直接取得原本的linux 系统操作环境。所以,还需要chroot 的支援. 更由于SELinux 的问题,你可能还得要加上某些特殊的流程才能顺利的搞定root 密码的重新设置. 这样说有些不清楚. 我们来走一个流程.
首先在grub界面使用e进入编辑模式, 在标有linux16的那一行的最后加上rd.break
这个核心参数.
之后就可以执行了,使用ctrl+x,这时开机你会看到这样的界面
这个时候我们不需要输入密码就可以进入系统! 但是注意这个时候我们进入的位置是/sysroot 并且使用mount查看当前挂载情况的时候, 你会发现当前的系统挂载了/sysroot这个目录,并且是仅仅可读不可写的.所以我们要先把他重新挂载成可读写.
1 | switch_root:/# mount -o remount, rw /sysroot |
接着我们进行根切换, 注意这是暂时切换.
1 | switch_root:/# chroot /sysroot |
接着就可以进行密码更改了. 你会发现这时的/sys /proc都是空的.
更改完毕后, 别忘了要先退出这个根. 然后在重新启动就可以了.
关于这些的原理和其他的一些, 在后面的GRUB2中会说明. 后面的GRUB2中会说明.