本身動手寫docker-4

4.構造鏡像

示例代碼(更新到4.2)git

4.1 使用busybox基本鏡像構造容器

  • docker export -o busybox.tar c5a45bda498e(容器id) 能夠起一個busybox的後臺運行容器,經過export導出文件系統,查看下結構
  • pivot_root系統調用,用於改變root文件系統
    • int pivot_root(const char *new_root, const char *put_old); 會將原先的root文件系統move到put_old,而後以new_root做爲調用進程的新的root文件系統
  • pivot_rootchroot的區別:
    • pivot_root把進程切換到一個新的root目錄,對以前root文件系統的再也不有依賴,這樣你就可以umount原先的root文件系統。
    • chroot只是更改了root目錄,還會依賴老的文件系統,主要使用的目的通常是爲了限制用戶的訪問。
  • pivot_root相關代碼:
func pivotRoot(root string) error {
	//這個root目錄在以前經過cmd.Dir='/path/busybox'設置好了
	// new_root 和put_old 必須不能同時存在當前root 的同一個文件系統中,須要經過--bind從新掛載一下
	if err := syscall.Mount(root, root, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("mount --bind PWD PWD error ")
	}
	pivotDir := filepath.Join(root, old_root)
	if err := os.Mkdir(pivotDir, 0777); err != nil {
		return err
	}
	if err := syscall.PivotRoot(root, pivotDir); err != nil {
		return fmt.Errorf("privot_root error %v", err)
	}
	log.Infof("now change dir to root")
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %v", err)
	}
	// 更新下文件路徑
	pivotDir = filepath.Join("/", old_root)
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("umount pivot_root dir %v", err)
	}
	return os.Remove(pivotDir)
}
複製代碼

4.2 使用AUFS包裝busybox

  • 上一步構建好以後其實全部的操做都會影響busybox目錄,須要將鏡像和容器作隔離
  • 大體的思路是在進入init進程進行pivotRoot以前,須要加上如下操做
    • 啓動容器時,將兩個目錄AUFS掛載到(ex:path/mnt),一個是read-wirte一個是read-only(通常是鏡像文件,ex:busybox的文件系統)
    • 退出時卸載而且刪除read-write文件系統
  • 流程以下

比較關鍵的就一步掛載AUFSgithub

func CreateMountPoint(rootUrl string, mntUrl string) {
	if err := os.Mkdir(mntUrl, 0777); err != nil {
		log.Errorf("Mkdir dir %s error. %v", mntUrl, err)
	}
	dirs := "dirs=" + rootUrl + "writeLayer:" + rootUrl + "busybox"
	cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", mntUrl)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Errorf("%v", err)
	}
}
複製代碼

4.3實現volumn數據卷

就是實現docker run -v xxx:yyy,支持掛載外部文件到容器中去docker

  • 相較於4.2的實現,在啓動容器時在mnt掛載完成後多了一步掛載volumn
func MountVolume(rootURL string, mntURL string, volumeURLs []string)  {
	parentUrl := volumeURLs[0]
	if err := os.Mkdir(parentUrl, 0777); err != nil {
		log.Infof("Mkdir parent dir %s error. %v", parentUrl, err)
	}
	containerUrl := volumeURLs[1]
	containerVolumeURL := mntURL + containerUrl
	if err := os.Mkdir(containerVolumeURL, 0777); err != nil {
		log.Infof("Mkdir container dir %s error. %v", containerVolumeURL, err)
	}
	dirs := "dirs=" + parentUrl
	cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", containerVolumeURL)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Errorf("Mount volume failed. %v", err)
	}

}
複製代碼
  • 在退出時加一步umount操做,和掛載順序相反。
  • 大體流程

4.4 實現簡單鏡像打包(略)

實現相似docker commit xxx的功能spa

  • 比較簡單就是在容器運行時 tar 壓縮下 path/mnt的文件
相關文章
相關標籤/搜索