实现docker run命令
基于宿主机来创建容器
执行命令
《自己动手写Docker》code-3.1
./mydocker run -ti /bin/bash
代码流程
1. 解析参数。
2. 通过clone来fork一个Namespace隔离的容器进程。
3. 调用自己/proc/self/exe初始化容器(挂载proc文件系统),容器内1号进程就是这个init进程。
4. 调用syscall.Exec来把init进程替换成用户指定的进程。
unshare:已有进程加入到新的namespace中。
setns:已有进程加入到已经存在的namespace中。
clone:创建新进程,该进程加入到新的namespace中。
效果
基于容器镜像来创建容器
没有使用容器镜像时,容器进程继承了父进程的所有挂载点,与宿主机共用rootfs。mount namespace没有隔离,会把宿主机上的proc挂载到容器里面,导致宿主机上的ps -ef命令无法执行。
获取容器快照镜像
docker pull busybox
docker run -d busybox top
docker export -o busybox.tar 容器ID
tar -xvf busybox.tar -C busybox/
修改关键流程
《自己动手写Docker》code-4.1
把pivotRoot函数修改成如下内容(通过chroot来切换根目录,而不是pivot_root,避免报错;Docker优先使用pivot_root,失败后使用chroot)
func pivotRoot(root string) error {
return syscall.Chroot("/root/busybox")
}
执行命令
./mydocker run -ti /bin/sh
效果
容器内的挂载点已经与宿主机不同,不存在宿主机上执行ps -ef报错的问题。