编程技术分享平台

网站首页 > 技术教程 正文

docker根目录切换原理 docker容器根目录

xnh888 2024-12-22 21:31:09 技术教程 31 ℃ 0 评论

最近在看docker的原理,涉及namespace、cgroup、rootfs

namespace是通过在fork新的子进程的时候加入各种namespace参数来进行隔离

cgroup是通过在/sys/fs/cgroup/下的各个subsystem中创建目录,指定配额参数,并将pid放入tasks中就可以生效

但对于rootfs隔离,只知道使用的是pivot_root切换了进程的根文件系统目录,但一直不太明白具体实现原理,挺好奇就研究一下

pivot_root

首先我们来看pivot_root的man手册

http://man7.org/linux/man-pages/man2/pivot_root.2.html

DESCRIPTION         
       pivot_root() changes the root mount in the mount namespace of the
       calling process.  More precisely, it moves the root mount to the
       directory put_old and makes new_root the new root mount.  The calling
       process must have the CAP_SYS_ADMIN capability in the user namespace
       that owns the caller's mount namespace.

       pivot_root() changes the root directory and the current working
       directory of each process or thread in the same mount namespace to
       new_root if they point to the old root directory.  (See also NOTES.)
       On the other hand, pivot_root() does not change the caller's current
       working directory (unless it is on the old root directory), and thus
       it should be followed by a chdir("/") call.

       The following restrictions apply:

       -  new_root and put_old must be directories.

       -  new_root and put_old must not be on the same mount as the current
          root.

       -  put_old must be at or underneath new_root; that is, adding some
          nonnegative number of "/.." prefixes to the pathname pointed to by
          put_old must yield the same directory as new_root.

       -  new_root must be a path to a mount point, but can't be "/".  A
          path that is not already a mount point can be converted into one
          by bind mounting the path onto itself.

       -  The propagation type of the parent mount of new_root and the
          parent mount of the current root directory must not be MS_SHARED;
          similarly, if put_old is an existing mount point, its propagation
          type must not be MS_SHARED.  These restrictions ensure that
          pivot_root() never propagates any changes to another mount
          namespace.

       -  The current root directory must be a mount point.  
  1. pivot_root改变当前进程所在mount namespace内的所有进程的root mount移到put_old,然后将new_root作为新的root mount;
  2. pivot_root并没有修改当前调用进程的工作目录,通常需要使用chdir("/")来实现切换到新的root mount的根目录。

rount mount可以理解为rootfs,也就是“/”,pivot_root将所在mount namespace的“/”改为了new_root 注意,pivot_root没有改变当前调用进程的工作目录 注意,pivot_root的调用前提需要明确在fork进程时指定mount namespace参数

主要约束条件:

  1. new_root和put_old都必须是目录
  2. new_root和put_old不在同一个mount namespace中
  3. put_old必须是new_root,或者是new_root的子目录
  4. new_root必须是mount point,且不能是当前mount namespace的“/”

注意,pivot_root(new_root, put_old),且chdir("/")后,put_old是“/”的子目录,可以unmount

在docker中,使用pivot_root实现rootfs切换和隔离,也遵循pivot_root的使用约束

  1. 首先创建一个new_root的临时子目录作为put_old,然后调用pivot_root实现切换
  2. chdir("/")
  3. umount put_old and clear

pivot_root(".",".")

在实际使用时,发现一个特殊的case,可以避免使用临时目录,就是pivot_root(".", ".")

pivot_root(".", ".")将当前“/”作为rootfs,将/proc/self/cwd作为put_old,从而避免必须创建子目录,但这时需要先unmount(".")再chdir("/")

https://github.com/opencontainers/runc/commit/f8e6b5af5e120ab7599885bd13a932d970ccc748

chroot vs pivot_root vs switch_root

chroot只改变当前进程的“/”

pivot_root改变当前mount namespace的“/”

switch_root和chroot类似,但是专门用来初始化系统时候使用的(initramfs),不仅会chroot,而且会删除旧根下的所有内容,释放内存,只能由pid=1的进程使用,其他地方用不到

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表