rootfs 与容器技术
回到我们在 Linux 的环境,运行我们的“容器”:
/root/test/container
我们是不是可以像虚拟机中的操作系统一样,在容器中“为非作歹”了呢?
那!当!然!不!行!啦!
1. 为什么需要 rootfs
先忽略 Cgroup 机制。在容器中探索时,不知大家是否发现,/bin,/etc,/var ...
等等目录下的内容,它们与宿主机的目录完全一致。你在这些目录里的更改一样会影响到宿主机。聪明的读者一定发现了,我们创建进程的时候不是指定开启 Mount Namespace 了吗,为什么不生效呢?
即使我们启用了 Mount Namespace,但它需要手动指定挂载时才能生效,我们在代码中指定容器进程中的 /tmp
目录使用空的内存盘挂载,所以我们在容器中访问到的 /tmp
目录是空的,与宿主机不一致的。
实现起来也不算复杂,我们知道 Linux 的目录结构都是从 /
开始的,如果我们制作一份 /
目录,然后在容器进程启动的时候将它切换挂载到容器的 /
,就可以解决这个问题。而像这种完整包含根目录的拷贝,我们称呼它:rootfs。
2. 构建 rootfs
cd /root/test/
mkdir rootfs
# 为rootfs提供初始目录结构和核心依赖库
sudo rpm -ivh --nodeps --root /home/root/test/rootfs https://mirrors.aliyun.com/centos/8/BaSEOS/x86_64/os/Packages/centos-release-8.1-1.1911.0.9.el8.x86_64.rpm
# 为rootfs安装vim 工具和gcc编译环境
sudo dnf --installroot=/root/test/rootfs install vim gcc --nogpgcheck
3. 使用 rootfs
在 Linux 环境的 /root/test/
目录下,已经有一份打包好的 rootfs,我们直接使用它即可。
我们来探查一下它的目录结构:
tree -L 1
发现它与宿主机的/
目录的结构一致, 因为它就是我们容器将要使用的/
。
下面我们让我们的容器使用这个 rootfs,编写一个 helloworld 程序
Tip: 下面我们会使用到 chroot, chroot 是在 unix 系统的一个操作,针对正在运作的软件行程和它的子进程,改变它外显的根目录。一个运行在这个环境下,经由 chroot 设置根目录的程序,它不能够对这个指定根目录之外的文件进行访问动作,不能读取,也不能更改它的内容。Namespace Mount 事实上就是受到 chroot 的启发改进而来的。
cd /root/test/
## 运行容器环境
./container
## chroot切换到rootfs
chroot /root/rootfs /bin/bash
# 进入容器中的home目录,编写代码 helloworld.c并编译执行
cd /home
vim helloworld.c
#include <stdio.h>
int main()
{
// printf() 中字符串需要引号
printf("Hello, World!");
return ;
}
保存后编译运行
cc helloworld.c -o helloworld
./helloworld
我们将看到终端中显示:
hello, world!
4. 拓展思考
如果 多个项目同时使用这个容器,他们之间如何隔离文件系统呢?
直接拷贝或者重新构建多个 rootfs 似乎可行,但这浪费了空间
如果…?