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

​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目录为空。

root@xxg-txy:~/aufs2# ls
root@xxg-txy:~/aufs2# mkdir base mnt top
root@xxg-txy:~/aufs2# touch base/base.txt base/common.txt
root@xxg-txy:~/aufs2# touch top/common.txt top/top.txt
root@xxg-txy:~/aufs2# tree
.
├── base
│   ├── base.txt
│   └── common.txt
├── mnt
└── top
    ├── common.txt
    └── top.txt
​
3 directories, 4 files

写点内容到这些文件中:

root@xxg-txy:~/aufs2# echo 'base' > base/base.txt 
root@xxg-txy:~/aufs2# echo 'base' > base/common.txt 
root@xxg-txy:~/aufs2# echo 'top' > top/common.txt 
root@xxg-txy:~/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目录下会看到有了三个文件:

root@xxg-txy:~/aufs2# ls mnt/
base.txt  common.txt  top.txt

我们看看这三个文件的内容:

root@xxg-txy:~/aufs2# cat mnt/base.txt 
base
root@xxg-txy:~/aufs2# cat mnt/common.txt 
top
root@xxg-txy:~/aufs2# cat mnt/top.txt 
top

可以看到common.txt文件里的内容是top/common.txt的。

3.体验

我们修改一下mnt目录下的base.txt的内容,再看看base目录下的bast.txt文件有无变化:

root@xxg-txy:~/aufs2# echo 'mnt' > mnt/base.txt 
root@xxg-txy:~/aufs2# cat mnt/base.txt 
mnt
root@xxg-txy:~/aufs2# cat base/base.txt 
base

可以看到base/base.txt并无变化。此时看下top目录,会发现top下多了一个base.txt,并且内容是mnt:

root@xxg-txy:~/aufs2# ls top/
base.txt  common.txt  top.txt
root@xxg-txy:~/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")
}

谢谢阅读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值