Container 前身 —— chroot 入门

Container 前身 —— chroot 入门

Tags
Linux
Container
Published
December 2, 2024
Author
Johnh3
chroot 在 Linux 系统上,既是一个系统管理命令 chroot(8) ,也是一个系统调用 chroot(2)
为了叙述简单,且后面不会讨论 chroot(2),所以后面一律采用 chroot 表示 chroot(8)
 
chrootchange root directory 的缩写,使用 chroot 命令能够以特殊的根目录去运行命令或者是交互式 shell。
什么意思呢?在 Linux OS 上,根目录就是 / ,表示操作系统中目录结构的根节点。如果改变了根目录,那么所有的资源就只能从新的根节点开始去寻找。
 
那不多说,我们先来运行一个实例看看。
root@1054e3f0a7ed:/# cd ~ root@1054e3f0a7ed:~# mkdir new_root root@1054e3f0a7ed:~# chroot new_root/ chroot: failed to run command '/bin/sh': No such file or directory
 
这里明明指定了一个新的 new_root 来作为 chroot 的新根目录,命令却执行报错了。
这是因为 chroot 命令还需要指定后续的指令参数
chroot [OPTION] NEWROOT [COMMAND [ARG]...]
当我们不去指定指令时,它会默认地执行 $SHELL -i (default: /bin/sh -i)
 
略微思考一下,便可以知道,由于我们的新根目录下什么也没有,那么自然是找不到 /bin/sh 的。
所以很自然的,我们会把 /bin/sh 复制到 new_root 下。
但这是不够的,因为很多命令工具不是静态编译的,它们还需要对应的动态链接库才能够正常运行。
这个时候可以使用 ldd 命令来获取。
 
这里就以 /bin/sh 为例,来看一下它的执行过程:
root@1054e3f0a7ed:~# which sh /usr/bin/sh root@1054e3f0a7ed:~# mkdir new_root/bin root@1054e3f0a7ed:~# cp /usr/bin/sh new_root/bin/ root@1054e3f0a7ed:~# ldd /usr/bin/sh linux-vdso.so.1 (0x00007ffd39faa000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5a380e8000) /lib64/ld-linux-x86-64.so.2 (0x00007f5a382ef000) root@1054e3f0a7ed:~# mkdir new_root/{lib,lib64} root@1054e3f0a7ed:~# cp /lib/x86_64-linux-gnu/libc.so.6 new_root/lib/ root@1054e3f0a7ed:~# cp /lib64/ld-linux-x86-64.so.2 new_root/lib64/ root@1054e3f0a7ed:~# chroot new_root/ #
 
可以看出来,这次我们成功的切换到了新根目录,并且成功的在新根目录中启动了一个 shell
有了 shell 后,我们就可以执行 shell 提供的内置命令了:
# pwd / # cd .. # cd .. # cd .. # pwd / #
但我们似乎并没有办法跳出新根目录,这就意味着新根目录与之前的环境是隔离的,是不是有点容器的感觉了。
 
其实,到这里,基本的 chroot 命令就介绍得差不多了,下面我们再浅浅地挖掘一点点。
chroot 到底是如何做到修改根目录的呢?其实它是通过修改进程的 root 指针实现的,我们可以通过查看进程的 /proc/<pid>/root 来查看对应进程是否处于 chroot 中。
 
这里先使用 screen 开启一个 chroot 的进程,然后 detach 查看进程情况:
root@ede0cf4b8cba:~# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 16:07 pts/0 00:00:00 bash root 209 1 0 16:09 ? 00:00:00 SCREEN root 210 209 0 16:09 pts/1 00:00:00 /bin/sh root 212 210 0 16:09 pts/1 00:00:00 /bin/sh -i root 318 1 0 16:10 pts/0 00:00:00 ps -ef
这里的 212 进程就是我们要找的。
root@ede0cf4b8cba:~# ls -l /proc/212/root lrwxrwxrwx 1 root root 0 Dec 1 16:15 /proc/212/root -> /root/new_root
 
那么, chroot 为什么没有用来做容器的实现呢?这就要扯出 chroot 的安全问题了,至于具体的那就以后再说了。
 
最后,我们来列举一些常用的 chroot 使用场景。
  • 利用隔离性,可以有多个版本的开发环境、测试环境,即使这些版本是互斥的。
  • 通过限制新根目录中的命令工具来提升安全性。比如一个只有应用程序的新根目录,由于没有 shell 等工具,所以即使被找到漏洞了也无法执行很多操作。
  • 当系统损坏无法启动时,可以先用光碟启动,然后挂载原系统分区并 chroot 进入,然后对系统进行修复。
  • 利用隔离性,提供只能访问特定目录的环境,比如 FTP 服务器。
  • 利用隔离性,可以确保不受宿主机上的干扰,比如作为构建环境。
 
相关链接: