專案原始碼:點選檢視專案原始碼
映象
前面我們用
namespace
和cgroup
構建了一個簡單的容器,但是我們可以發現容器內的目錄還是當前執行程式的目錄,這裡就缺少了映象這麼一個重要的特性。這裡我們先用docker拉一個最精簡的映象busybox
,它是一個集合了非常多unix工具的箱子,提供了一個非常完整而且小巧的系統。
# 拉取busybox
docker pull busybox
# 執行
docker run -d busybox top -b
# 檢視容器ID
docker ps
# 匯出容器
docker export -o busybox.tar
可以看到我們成功匯出了容器內容,下面我解壓縮一下,然後將此資料夾作為容器的只讀層。
mkdir busybox && tar -xvf busybox.tar -C busybox/
注意: 後面為了方便,我們把 busybox.tar 放到 /root 路徑下
docker在啟動容器時,會新建2個layer,write layer和container-layer,write layer 是容器的唯一可讀寫層,而container-layer是為容器新建的只讀層,這裡我們將busybox作為這一層,讀寫層,我們建立一個
writeLayer
資料夾作為這一層,然後將這兩個資料夾掛載到同一個資料夾下,然後將此資料夾作為容器的啟動目錄即可,這個資料夾我們命名為mnt
Linux掛載資料夾
這裡我們有3個資料夾,
mnt
writeLayer
busybox
,我們將writeLayer
busybox
這兩個資料夾掛載到mnt
資料夾下,可以看到這時mnt
和writeLayer
資料夾都是空的,只有busybox
資料夾下有東西,我們掛載之後再看一下
# 掛載
mount -t aufs -o dirs=/root/writeLayer:/root/busybox none /root/mnt
可以看到,
mnt
已經出現了busybox
資料夾裡面的東西,這時我們在writeLayer
資料夾下建立個新的資料夾,然後看看會發生什麼
可以清楚的看到,我們對
writeLayer
做的操作會對映到mnt
資料夾下,docker也是以這種方式來實現你每次修改容器內的東西之後並不會對映象產生影響,因為你做的操作都是writeLayer
層的,而映象是在busybox
,也就是container-init
層。
Go實現掛載
func NewWorkSpace(rootPath string, mntPath string, volume string) error {
// 1. 建立只讀層
err := createReadOnlyLayer(rootPath)
if err != nil {
logrus.Errorf("create read only layer, err: %v", err)
return err
}
// 2. 建立讀寫層
err = createWriteLayer(rootPath)
if err != nil {
logrus.Errorf("create write layer, err: %v", err)
return err
}
// 3. 建立掛載點,將只讀層和讀寫層掛載到指定位置
err = CreateMountPoint(rootPath, mntPath)
if err != nil {
logrus.Errorf("create mount point, err: %v", err)
return err
}
return nil
}
簡單來講就三步,第一步建立只讀層,第二步建立讀寫層,第三步將兩者掛載到同一個資料夾下,具體實現也比較簡單,就是建立資料夾罷了,這裡重點看下怎麼掛載吧
func CreateMountPoint(rootPath string, mntPath string) error {
_, err := os.Stat(mntPath)
if err != nil && os.IsNotExist(err) {
err := os.MkdirAll(mntPath, os.ModePerm)
if err != nil {
logrus.Errorf("mkdir mnt path, err: %v", err)
return err
}
}
dirs := fmt.Sprintf("dirs=%s%s:%s%s", rootPath, common.WriteLayer, rootPath, common.BusyBox)
cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", mntPath)
if err := cmd.Run(); err != nil {
logrus.Errorf("mnt cmd run, err: %v", err)
return err
}
return nil
}
文章會首發於我微信公眾號上,掃碼關注,及時獲取最新內容
本作品採用《CC 協議》,轉載必須註明作者和本文連結