欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用go写一个docker(7)-linux的AUFS文件系统

程序员文章站 2022-06-11 17:09:33
...

​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")
}

谢谢阅读。
用go写一个docker(7)-linux的AUFS文件系统