3. 切换根目录是什么概念
introduction
容器的表现, 我们已经说了如何限制资源, 不同于小型监狱, 这一节我们说说"pivot-root"是如何防止你在宿主机上 "到处乱窜"的. "pivot-root 用于切换rootfs". 想要知道怎么切换的rootfs, 就要先知道rootfs是啥
什么是rootfs
TLDR: 就是/
. 在Linux中所有的文件系统都会有一个挂载位, rootfs 作为一种文件系统, 就挂载在"/". 所以我们说 rootfs 挂在哪儿, 哪儿就是"/". 有了 rootfs 以后, 其他文件系统就有了根路径, 他们挂载的位置就是相对于 rootfs 的路径, 我举个最简单的例子:
$ mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /run type tmpfs (rw,nosuid,noexec,relatime)
...
有一个名称 sysfs , 类型为 sysfs 的文件系统, 挂载在 "/sys"目录下
有一个名称 proc , 类型为 proc 的文件系统, 挂载在 "/proc"目录下
有一个名称 tmpfs , 类型为 tmpfs 的文件系统, 挂载在 "/run"目录下
那什么是切换rootfs
在上面我们已经说了, rootfs(/, 根路径)下挂载了很多, 各种类型的文件系统, 现在我们切换 rootfs 到 A去, 是不是他们就全都挂载到A上去了? 那么上面的那些挂载是不是, 都变成了 A/sys , A/proc, A/run了, 多说无益, 直接开整
涉足无人之地
# 创建了一个路径
$ mkdir pivot
# 并在这个路径下挂载了大小为1G, 类型为 tmpfs 的临时文件系统.
$ mount -n -t tmpfs -o size=1G none pivot
# 进入这个临时文件系统, 并制造一个地方用于挂载之前的rootfs
$ cd pivot && mkdir old-rootfs
# 开始切换rootfs, 现在令pivot成为新的rootfs, 并将之前的挂载都挂到old下
$ unshare -m && pivot_root . old-rootfs
# 看看我们现在在哪儿
$ pwd
/root/pivot
# 你再仔细看看我们在哪儿????
$ cd . && pwd
/
# 什么鬼? 放我出去!!!
$ ls && mount && ps
-bash: ls: command not found
-bash: mount: command not found
-bash: ps: command not found
哈哈, 爽了吧? 翻车了, 你现在已经进入无人之地了, 这就是你进入一个完全空白镜像以后, 你能看到的东西, 毛都没, 是真的连根毛都没. 你之所以看到这些吓人的 "Command Not Found" 是因为文件系统现在全挂到 old-rootfs下了, 那么至于你现在在的位置, 就是新的 "/" 根路径, 这个路径下除了 old-rootfs 什么都没有.
正是因为没有 /bin/{ls, mount, ps}这些装备, 才会让你感觉好像直接遁入了虚空一样, 你现在可以通过 logout / exit / control+D 的方式退出无人之地, 然后我们准备一些装备, 再进去好了~
再次进入无人之地
这次我们要准备一些装备, 第一次, 我们先准备个ls工具, 当成手电筒, 查看查看情况 :
# 准备bin文件夹, 我们到时候需要用这个文件夹里的ls工具
$ cd pivot && mkdir bin
$ cp /bin/ls ./bin
# ls工具依赖一些库, 然后我们也搞来这些库
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007ffe79396000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f4382997000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f43825cd000)
libpcre.so.3 => /lib/x86_64-linux-gnu/libpcre.so.3 (0x00007f438235d000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4382158000)
/lib64/ld-linux-x86-64.so.2 (0x00005644db278000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f4381f3b000)
$ mkdir lib lib64
$ cp /lib/x86_64-linux-gnu/<xxx> ./lib
$ cp /lib64/ld-linux-x86-64.so.2 ./lib64
# 好! 再来一次! 结界! 启用!
$ unshare -m &&
pivot_root . old-rootfs/ &&
cd . && pwd
/
# 可以了这一回!
$ ls
bin lib lib64 old-rootfs
终于, 我们打开了手电筒(ls), 看到了我们处在新的结界(根目录)中, 手电筒照亮了脚下, 看到了我们带进结界的工具, 有bin, lib, lib64, 还看到废墟: old-rootfs, 此时所有之前的文件系统全都挂载在old-rootfs, 但是我们现在用 "/"当成根目录, 因此废墟里面满满的工具, 库, 都跟我们没关系, 你都用不了, 你只有一个手电筒.
尾巴
这次我们从零开始想象, 如果是空白镜像我们会看到什么, 如何带一些工具进镜像, 我们会看到什么, 这个过程基本解答了:
pivot-root: 如何创造一个完全空白的结界, 这是我们囚禁容器内进程的方法, 将它困在结界里
bin/lib/lib64: 如何让你的空白结界里带有一些工具, 让容器内进程可以开始做一些事, 这些工具, 由底层存储驱动 aufs / dm / overlay 联合多层镜像最后一起提供
跟chroot的区别? 他俩都能达到囚禁的效果, 但是pivot-root直接将当前进程所在namespace下的所有文件系统全部转移了. 而chroot还要依赖之前的文件系统, 你看在我们的例子中, 我们重建了一套 tmpfs , 结界里的内容都会存在这里, 到时候umount一下废墟, 再删除废墟路径, 就真的完全什么都没有了.
写完这些可能已经11:40了, 但当时, 在我第二次进入结界的时候, 我真的一点没感觉累, 我觉得很兴奋, 我有一种我反复穿梭表世界 / 里世界的感觉, 我感觉我好像在玩 Undertale 一样, 我进入了地底世界, 我只带了一个手电筒照着路慢慢往前走, 前面就是怪物王国的废墟, 就会有 Flowey 羊妈 Sans Papyrus 在等着我, 这种感觉真的很让人兴奋
Last updated
Was this helpful?