自己写一个docker(2)-文件系统的处理
# 核心操作
主要核心是一个syscall(SYS_pivot_root, new_root, put_pld);
这个系统调用。
pivot_root系统调用用于切换根目录,需要两个参数:新根目录(new_root)和旧根目录(put_old)。在调用 pivot_root 后,新根目录 new_root 成为新的 /(根目录),而当前的根目录(即调用前的 /)被移动到 put_old 指定的位置。
通过使用 pivot_root,可以将原始的根文件系统移动到一个安全的位置(通常是新根目录内的一个子目录),然后将一个全新的文件系统设为根文件系统。这种做法可以有效隔离原始根文件系统,防止容器内的应用程序访问或修改关键系统文件。
# 前置操作
mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL);
1
将当前的根文件系统(以及所有挂载的子文件系统)重新挂载为 MS_PRIVATE。这样做的目的是防止挂载事件传播到或从其他挂载命名空间.
隔离挂载事件:将挂载点设置为 MS_PRIVATE 可以防止挂载事件在这个挂载点与外部(其他挂载点)之间传播。这意味着在该挂载点上进行的任何挂载或卸载操作不会影响到系统的其他部分,也不会受到外部影响。
安全性和隔离性:在容器和其他隔离环境中,这种挂载隔离确保了更高级别的安全性和稳定性。容器内部的改变不会意外地影响到宿主机,反之亦然。
# 将指定的根挂载目录转换为一个挂载点
这句话说的有点绕。用户肯定会为我们的容器指定一个新的目录,用于当做容器内部的根目录,但是,pivot_root要求new_root必须是一个挂载点,不能只是一个普通目录。所以我们必须创建一个挂载点,并且让这个挂载点指向用户指定的目录。
string mount_dir = "/tmp/tmp.XXXXXX";
mkdtemp(mount_dir.data());
mount(config.mount_dir.data(), mount_dir.data(), NULL, MS_BIND | MS_PRIVATE, NULL);
1
2
3
2
3
# 创建一个目录用于挂载当前的根目录
string old_mount_basename ="/oldroot.XXXXXX";
string old_mount_dir = mount_dir + old_mount_basename;
mkdtemp(old_mount_dir.data());
1
2
3
2
3
# 切换根目录
syscall(SYS_pivot_root, mount_dir.data(), old_mount_dir.data());
1
# 删除原来的目录
chdir("/"); //取消挂载原来的根目录。因为旧的目录就挂载在新的根目录下面,因此先切换到新的根目录
umount2(old_mount_basename.data(), MNT_DETACH);
rmdir(old_mount_basename.data());
1
2
3
2
3
编辑 (opens new window)
上次更新: 2024/12/04, 16:28:16