创建容器
获取busybox
首先使用最精简的镜像—busybox。busybox是一个集合了很多unix工具的箱子,它可以提供非常多在unix环境下使用的命令。
# 安装dockercurl -sSL https://get.daocloud.io/docker | sh# 拉取镜像docker pull busybox# run起来docker run -d busybox top -b# 导出镜像docker export -o busybox.tar adad0ja9d0atar -xvf busybox.tar -C busybox
privot_root
pivot_root 是一个系统调用,主要功能是改变当前的 root 文件系统。privot_root 可以将当前进程的 root 文件系统移动到 put_old 文件夹,然后使 new_root 成为新的 root 文件系统。
pivotRoot 和 chroot 的主要区别:
- pivot_root是把整个系统切换到一个新的root目录,移除对之前root的依赖,以便随时umount原来的文件系统
- chroot是针对某个进程,系统的其他部分依旧运行于老的root目录中
// setUpMount Init 挂载点// 使用mount先去挂在proc文件系统,以后后面通过ps等系统命令去查看进程的资源占用情况//// syscall.MS_NOEXEC 本文件系统中不允许运行其他程序// syscall.MS_NOSUID 本文件系统运行程序,禁止set-user-ID或set-group-ID// syscall.MS_NODEV 所有mount的系统都会默认设定的参数//func setUpMount() {pwd, err := os.Getwd()if err != nil {logrus.Errorf("get current location error: %v", err)return}logrus.Info("current location is: ", pwd)if err = pivotRoot(pwd); err != nil {logrus.Warn(err)}defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEVsyscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), "")syscall.Mount("tmpfs", "/dev", "tmpfs", syscall.MS_NOSUID|syscall.MS_STRICTATIME, "mode=755")}// pivotRoot 改变当前的root文件系统,对应pivot_root系统调用// 可以将当前进程的root文件系统移动到put_old文件夹,然后使new_root成为新的root文件系统。func pivotRoot(root string) error {// 为了使当前root的 老root 和 新root 不在同一个文件系统下,我们把root重新mount了一次// bind mount是把相同的内容换了一个挂载点的挂载方法if err := syscall.Mount(root, root, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {return fmt.Errorf("func[pivotRoot] mount rootfs to itself error: %v", err)}// 创建rootfs/.pivot_root 存储 old_rootpivotDir := filepath.Join(root, ".pivot_root")if err := os.Mkdir(pivotDir, 0777); err != nil {return err}// pivot_root 到新的rootfs,old_root 现在挂载在rootfs/.pivot_root上// 挂载点目前依然可以在mount命令中看到if err := syscall.PivotRoot(root, pivotDir); err != nil {return fmt.Errorf("func[pivotRoot] syscall.PivotRoot error: %v", err)}// 修改当前的工作目录到根目录if err := syscall.Chdir("/"); err != nil {return fmt.Errorf("func[pivotRoot] syscall.Chdir / error: %v", err)}// umount rootfs/.pivot_rootpivotDir = filepath.Join("/", ".pivot_root")if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {return fmt.Errorf("func[pivotRoot] umount pivot_root dir error: %v", err)}return os.Remove(pivotDir)}
执行完 privot_root 系统调用之后,就可以在容器进程,进行一系列的 mount 操作了。如:syscall.Mount("tmpfs", "/dev", "tmpfs", syscall.MS_NOSUID|syscall.MS_STRICTATIME, "mode=755")
tmpfs 是一种基于内存的文件系统,可以使用 RAM 或 swap 分区来储存
暂时使用 cmd.Dir = “/root/busybox” 来指定创建出来的子进程容器的工作目录。后续会支持基于overlay的联合文件系统挂载
效果如下:![T3~4@RVY9UG)7DWF]RE)3_N.png](/uploads/projects/playgo@ddocker/02c0d30f799f90a7b287cb8527953005.png)
看起来效果不错,但是存在一些问题。
BUG
open /proc/self/mountinfo: no such file or directory 挂载信息无法被重复打开读取信息
pivot_root 系统调用似乎没有生效
解决:ubuntu1404更换为debian10
