创建容器

获取busybox

首先使用最精简的镜像—busybox。busybox是一个集合了很多unix工具的箱子,它可以提供非常多在unix环境下使用的命令。

  1. # 安装docker
  2. curl -sSL https://get.daocloud.io/docker | sh
  3. # 拉取镜像
  4. docker pull busybox
  5. # run起来
  6. docker run -d busybox top -b
  7. # 导出镜像
  8. docker export -o busybox.tar adad0ja9d0a
  9. tar -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目录中
  1. // setUpMount Init 挂载点
  2. // 使用mount先去挂在proc文件系统,以后后面通过ps等系统命令去查看进程的资源占用情况
  3. //
  4. // syscall.MS_NOEXEC 本文件系统中不允许运行其他程序
  5. // syscall.MS_NOSUID 本文件系统运行程序,禁止set-user-ID或set-group-ID
  6. // syscall.MS_NODEV 所有mount的系统都会默认设定的参数
  7. //
  8. func setUpMount() {
  9. pwd, err := os.Getwd()
  10. if err != nil {
  11. logrus.Errorf("get current location error: %v", err)
  12. return
  13. }
  14. logrus.Info("current location is: ", pwd)
  15. if err = pivotRoot(pwd); err != nil {
  16. logrus.Warn(err)
  17. }
  18. defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
  19. syscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), "")
  20. syscall.Mount("tmpfs", "/dev", "tmpfs", syscall.MS_NOSUID|syscall.MS_STRICTATIME, "mode=755")
  21. }
  22. // pivotRoot 改变当前的root文件系统,对应pivot_root系统调用
  23. // 可以将当前进程的root文件系统移动到put_old文件夹,然后使new_root成为新的root文件系统。
  24. func pivotRoot(root string) error {
  25. // 为了使当前root的 老root 和 新root 不在同一个文件系统下,我们把root重新mount了一次
  26. // bind mount是把相同的内容换了一个挂载点的挂载方法
  27. if err := syscall.Mount(root, root, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
  28. return fmt.Errorf("func[pivotRoot] mount rootfs to itself error: %v", err)
  29. }
  30. // 创建rootfs/.pivot_root 存储 old_root
  31. pivotDir := filepath.Join(root, ".pivot_root")
  32. if err := os.Mkdir(pivotDir, 0777); err != nil {
  33. return err
  34. }
  35. // pivot_root 到新的rootfs,old_root 现在挂载在rootfs/.pivot_root上
  36. // 挂载点目前依然可以在mount命令中看到
  37. if err := syscall.PivotRoot(root, pivotDir); err != nil {
  38. return fmt.Errorf("func[pivotRoot] syscall.PivotRoot error: %v", err)
  39. }
  40. // 修改当前的工作目录到根目录
  41. if err := syscall.Chdir("/"); err != nil {
  42. return fmt.Errorf("func[pivotRoot] syscall.Chdir / error: %v", err)
  43. }
  44. // umount rootfs/.pivot_root
  45. pivotDir = filepath.Join("/", ".pivot_root")
  46. if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
  47. return fmt.Errorf("func[pivotRoot] umount pivot_root dir error: %v", err)
  48. }
  49. return os.Remove(pivotDir)
  50. }

执行完 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
看起来效果不错,但是存在一些问题。

BUG

open /proc/self/mountinfo: no such file or directory 挂载信息无法被重复打开读取信息
image.png

pivot_root 系统调用似乎没有生效
ZLGSA8W8R5$6NUF6~O)1)GL.png

解决:ubuntu1404更换为debian10