示例代碼(更新到4.2)git
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_root
和chroot
的區別:
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)
}
複製代碼
- 上一步構建好以後其實全部的操做都會影響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)
}
}
複製代碼
就是實現
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操做,和掛載順序相反。
- 大體流程
實現相似
docker commit xxx
的功能spa
- 比較簡單就是在容器運行時 tar 壓縮下 path/mnt的文件