linux container tech - hanyong/note GitHub Wiki
Linux 容器技术
chroot
执行 chroot 需要 root 权限 (CAP_SYS_CHROOT
)。
创建一个空文件夹 newroot
测试。报错如下:
$ mkdir newroot
$ cd newroot/
$ sudo chroot .
chroot: failed to run command ‘/bin/bash’: No such file or directory
chroot 默认尝试执行 ${SHELL} -i
,即 /bin/bash -i
,而 newroot
是一个空目录,没有 /bin/bash
这个文件。
chroot 之后的进程只能访问 newroot
下的文件, 拷贝程序到 newroot
下需要将其所有依赖文件一起拷贝过来。
为简化起见,可以拷贝静态编译版的 busybox 过来测试。
busybox 堪称嵌入式 Linux 系统的瑞士军刀,包含各种常用的 Linux 基本命令。
$ rsync -t /bin/busybox bin/
>f+++++++++ busybox
$ sudo chroot . /bin/busybox sh
BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.
/ # id
uid=0 gid=0 groups=0
为方便使用,可让 busybox 在 newroot
下安装常用命令的软连接。
mkdir -p sbin usr/sbin usr/bin
sudo chroot . /bin/busybox --install -s
chroot 之后的进程可以显式指定其他用户和组,这样可以进一步限制 chroot 之后的进程权限。
$ sudo chroot --userspec 500:500 . id
uid=500 gid=500 groups=500
用户和组可以用本机用户名和组名指定,但最终也会换成 uid/gid,内核只关心 id,不关心 name。 发现指定本机 uid 时, 会自动设置本机 uid 对应的 gid, 但 groups 不会设置(?)。
Linux 下有一些关键的系统目录,如 /proc
, /sys
, /dev/pts
等。
简单 chroot 后,需要访问这些目录的命令将无法正常工作,如 ps
命令需要读 /proc
信息。
$ sudo chroot --userspec $USER . mount
mount: no /proc/mounts
$ sudo chroot --userspec $USER . ps
PID USER COMMAND
ps: can't open '/proc': No such file or directory
$ sudo chroot --userspec $USER . tty
not a tty
如果 chroot 之后的进程有 root 权限,可以自己挂载这些目录。
挂载后 /proc
, /dev
等可访问到宿主机上的相关信息 (但 mount 只能访问 newroot
目录下的挂载信息),放宽了权限。
mkdir -p proc sys dev/pts
mount -t proc proc proc/
mount -t sysfs sysfs sys/
mount -t devtmpfs devtmpfs dev/
mount -t devpts devpts dev/pts/
这些挂载是在宿主机上生效的,退出 chroot 后依然存在。 可以在宿主机上查看这些挂载:
$ mount | grep newroot
proc on /home/hanyong/newroot/proc type proc (rw,relatime)
sysfs on /home/hanyong/newroot/sys type sysfs (rw,relatime)
devtmpfs on /home/hanyong/newroot/dev type devtmpfs (rw,relatime,size=5089012k,nr_inodes=1272253,mode=755)
devpts on /home/hanyong/newroot/dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
重新执行 chroot 以普通用户执行命令仍然可以访问这些功能:
$ sudo chroot --userspec $USER . mount
proc on /proc type proc (rw,relatime)
sysfs on /sys type sysfs (rw,relatime)
devtmpfs on /dev type devtmpfs (rw,relatime,size=5089012k,nr_inodes=1272253,mode=755)
devpts on /dev/pts type devpts (rw,relatime,mode=600,ptmxmode=000)
$ sudo chroot --userspec $USER . ps
PID USER COMMAND
1 0 {systemd} /sbin/init
$ sudo chroot --userspec $USER . tty
/dev/pts/1
用户需要在恰当的时候手动卸载这些挂载点:
umount proc/ sys/ dev/pts/ dev/
proot
proot 看起来与 chroot 类似, 但:
- 用户态实现,不需要 root 权限。
- 自动处理挂载点,使用更友好。
使用上述 newroot
目录测试如下:
$ proot -r . -w / id
uid=1001 gid=1000 groups=4,24,27,30,46,113,129,131,132,500,1000
-r
指定新的文件系统 root 目录, -w
指定 proot 后的工作目录, 因为默认的当前目录不存在, 指定系统根目录 /
。
proot 后的进程以当前用户运行,因为没有 root 权限,没有切换用户的能力。
同样默认情况下 mount, ps 等命令不能正常工作。
/proc
为空目录但未挂载,ps 返回空但未报错。
$ proot -r . -w / mount
mount: no /proc/mounts
observer.hany@ali-59375n:~/tmp/newroot
$ proot -r . -w / ps
PID USER COMMAND
observer.hany@ali-59375n:~/tmp/newroot
$ proot -r . -w / tty
not a tty
proot 可以自动处理挂载点,使用 -b
参数指定挂载点即可。
除了标准系统目录,也可以指定自定义挂载点。
如 -b $PWD:$PWD
使 proot 后的进程也使用宿主机上的当前目录,这也是默认的工作目录。
$ proot -r . -w / -b /proc -b /sys -b /dev -b /dev/pts mount
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
# ... ...
$ proot -r . -w / -b /proc -b /sys -b /dev -b /dev/pts ps
PID USER COMMAND
1 0 {systemd} /sbin/init
# ... ...
$ proot -r . -w / -b /proc -b /sys -b /dev -b /dev/pts tty
/dev/pts/1
$ proot -r . -b /proc -b /sys -b /dev -b /dev/pts -b $PWD:$PWD readlink -f .
/home/hanyong/newroot
为了简化用户操作, proot 提供了 -R
参数, 自动设置常用挂载点。
$ proot -R . ls
bin dev etc home proc run sbin sys tmp usr var
mount, ps 等看到的都是宿主机上的状态。 proot 的自动 mount 也是用户态实现的,所以宿主机上 mount 看不到这些挂载点。 proot 进程退出后这些挂载点也自动消失。