1. 程式人生 > 其它 >用go寫一個docker(7)-linux的AUFS檔案系統

用go寫一個docker(7)-linux的AUFS檔案系統

技術標籤:運維和開發docker

​namespace和cgroup解決的是容器的資源隔離和限制問題。容器的另一個特點是映象分層,我們可以在基礎映象上加自己定製的東西。今天我們就以AUFS為例,來看看docker的檔案系統。

什麼是AUFS

AUFS 的全稱是 Advanced Multi-layered unification filesytem,它的主要功能是:把多個目錄結合成一個目錄,對外使用。以下面為例,我們先直觀地體驗一下。

1.準備工作

準備三個目錄,分別命名為:base,mnt,top。在base目錄下建立名為base.txt 和 common.txt檔案,在top目錄下建立名為common.txt和top.txt檔案,mnt目錄為空。

[email protected]:~/aufs2# ls
[email protected]:~/aufs2# mkdir base mnt top
[email protected]:~/aufs2# touch base/base.txt base/common.txt
[email protected]:~/aufs2# touch top/common.txt top/top.txt
[email protected]:~/aufs2# tree
.
├── base
│   ├── base.txt
│   └── common.txt
├── mnt
└── top
    ├── common.txt
    └── top.txt
​
3 directories, 4 files

寫點內容到這些檔案中:

[email protected]:~/aufs2# echo 'base' > base/base.txt 
[email protected]:~/aufs2# echo 'base' > base/common.txt 
[email protected]:~/aufs2# echo 'top' > top/common.txt 
[email protected]:~/aufs2# echo 'top' > top/top.txt

2.使用AUFS掛載

用aufs把base和top 掛載到mnt:

mount -t aufs -o br=./top:./base none ./mnt

稍微說下這裡的mount命令引數:

-t aufs:mount的檔案型別,這裡使用aufs
-o:傳遞個 aufs 的選項,每個檔案型別的選項不同
none:這個本來是裝置的名字,但是我們並沒有用到任何裝置,只會用到資料夾,因此這裡為 none
./mnt:掛載點,也就是我們要把目錄最終掛到哪個目錄

執行該命令後,在mnt目錄下會看到有了三個檔案:

[email protected]:~/aufs2# ls mnt/
base.txt  common.txt  top.txt

我們看看這三個檔案的內容:

[email protected]:~/aufs2# cat mnt/base.txt 
base
[email protected]:~/aufs2# cat mnt/common.txt 
top
[email protected]:~/aufs2# cat mnt/top.txt 
top

可以看到common.txt檔案裡的內容是top/common.txt的。

3.體驗

我們修改一下mnt目錄下的base.txt的內容,再看看base目錄下的bast.txt檔案有無變化:

[email protected]:~/aufs2# echo 'mnt' > mnt/base.txt 
[email protected]:~/aufs2# cat mnt/base.txt 
mnt
[email protected]:~/aufs2# cat base/base.txt 
base

可以看到base/base.txt並無變化。此時看下top目錄,會發現top下多了一個base.txt,並且內容是mnt:

[email protected]:~/aufs2# ls top/
base.txt  common.txt  top.txt
[email protected]:~/aufs2# cat top/base.txt 
mnt

是不是有點神奇,這個讀寫步驟是怎麼樣的呢?

AUFS讀寫步驟

預設情況下,最上層的目錄為讀寫層,且只有一個(比如top就是最上層)

下層可以有一個或多個只讀層(比如base和top)

讀檔案時,從最上層開始逐層往下找,讀取第一個找到的檔案

寫檔案時,如果最上層有該檔案,則直接寫該檔案;否則從上往下逐層找,找到檔案後把檔案複製到最
上層,寫這個複製的檔案;如果都沒有找到該檔案,則在最上層建立一個。

刪除檔案時,會在最上層建立一個以.wh開頭加上檔名的檔案,比如在mnt下執行rm base.txt命令後,會在top目錄下建立一個.wh.base.txt的檔案,標記該檔案已刪除,但不會刪除base目錄下的base.txt

在go上測試使用

例項程式碼如下:

package main
​
import (
    "os"
    "os/exec"
    "log"
)
​
const path = "/opt/aufs/"
​
func writeFile(filename string, content string){
    f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }
    _, err = f.Write([]byte(content))
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()
}
​
func main(){
​
    // 定義目錄
    baseDir := path + "base"
    topDir := path + "top"
    mntDir := path + "mnt"
​
    // 建立目錄
    if err := os.MkdirAll(baseDir, 0777); err != nil {
        log.Fatal(err)
    }
    if err := os.MkdirAll(topDir, 0777); err != nil {
        log.Fatal(err)
    }
    if err := os.MkdirAll(mntDir, 0777); err != nil {
        log.Fatal(err)
    }
​
    // 建立檔案
    writeFile(baseDir + "/" + "common.txt","base\n")
    writeFile(baseDir + "/" + "base.txt","base\n")
    writeFile(topDir + "/" + "common.txt","top\n")
    writeFile(topDir + "/" + "top.txt","top\n")
​
    // 掛載
    dirs := "br=" + topDir + ":" + baseDir
    cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none",mntDir)
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    if err := cmd.Run(); err != nil {
        log.Fatal(err)
    }
​
    // 寫一個檔案測試
    writeFile(mntDir + "/" + "test.txt","test\n")
}

謝謝閱讀。