从sysV的init说起

首先是庆祝我们开源小站再次搬家。这次的地址是阿里云。

从某种角度上来看,*nix操作系统的方式无外乎几个函数接口:fork/vfork()和exec() 也就是说所有的进程实例都应该有一个自己的父进程。然后就出现了一个鸡生蛋的问题:谁是第一个进程?

最简单的办法就是自己找,执行一下ps -ef

root@litrin-de-xubuntu:~# ps -ef | head
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10月16 ? 00:00:12 /sbin/init splash
root 2 0 0 10月16 ? 00:00:00 [kthreadd]
root 4 2 0 10月16 ? 00:00:00 [kworker/0:0H]
root 5 2 0 10月16 ? 00:00:00 [kworker/u48:0]
root 7 2 0 10月16 ? 00:00:00 [mm_percpu_wq]
root 8 2 0 10月16 ? 00:00:00 [ksoftirqd/0]
root 9 2 0 10月16 ? 00:00:14 [rcu_sched]
root 10 2 0 10月16 ? 00:00:00 [rcu_bh]
root 11 2 0 10月16 ? 00:00:00 [migration/0]

在这里你可以看到有个/sbin/init的进程PID=1,它就是系统最初的进程。你的service、控制台、甚至挂装磁盘的操作都应当被看作是通过init启动的命令。

如果你用过简单的init命令,你应该知道可以通过init 命令切换运行等级,而对于较早版本的Linux,所有的运行等级都通过/etc/inittab文件进行配置。也就是说,init的任务就是是读取这个inittab的配置,然后启动不同的命令而已。

下一个问题就马上变成了:什么时候系统会调用init命令?

对于Linux这种脱胎于SysV的操作系统来说,当内核被grub加载之后会自动寻找并执行/sbin/init这个命令。
随着当下的系统越来越复杂,init的缺点也逐渐暴露了出来。串行启动会使启动过程变得无比冗长;不够灵活,就那么0~6个配置,而且还有0和6是不能用的;不支持资源隔离,CPU绑定;不支持崩溃回溯等等。于是我们现在各大发行版中都逐步用systemd取代传统的init。当然其他的类似解决方案如upstart什么的也有很多。

说到逐步,其实我们可以通过简单的方式直接废弃init,那就是kerenel的init参数,编辑/etc/default/grub文件,添加如下内容然后执行update-grub更新grub配置即可。

GRUB_CMDLINE_LINUX="init=/lib/systemd/systemd"

从之前的介绍中你应该可以很清楚的明白了这个命令行的含义。系统将会首先加载systemd作为pid1的父进程。对于systemd管理的系统,你可以通过systemd-cgls 命令列出的树图了解系统进程之间的派生关系。对应的cgroup的目录下也会有相同的文件结构,你可以简单的通过这些cgroup文件来控制不同的系统资源给每个进程/服务。

  • *.service: 放置着由systemd基础配置直接启动/关闭的 进程。
  • *.scope: 由PID1直接fork出来的进程
  • *.slice: 根据树状结构重新整理的service列表。在这些目录中,你可以根据用户/系统/用户id/session ID这种更为灵活的方式找到对应进程的cgroup配置。

这里有个题外话,很多文档上介绍的通过修改grub配置文件进入单用户模式找回root密码的方式事实上也是直接将pid1的进程设置成为/bin/sh,绕开各种权限控制强行进入系统的。

 

推荐阅读:
一开始学习Linux时,曾经有
我个人觉得这并不是一个很困扰人
算起来Litrin在生产环境中

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据