最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

今日热门![Docker] 将容器打包成镜像、镜像分层机制详解

来源:博客园
目录
  • commit 命令
  • 创建一个容器
  • 打包镜像
  • 联合文件系统
    • 联合文件系统实践
      • 前置准备
      • 不使用联合文件系统的挂载
      • 使用联合文件系统进行挂载
      • 写时复制机制

commit 命令

# 将容器打包成镜像的命令,:TAG可有可无docker commit -m="commit信息" -a="作者名" 容器ID 你的镜像名:TAG

创建一个容器

# 以Mariadb为例,我们启动一个mariadb镜像,然后进入这个镜像做一些修改docker run -it mariadb bash

上面的命令是创建一个 mariadb镜像的容器并进入这个容器,我们在要在这个容器里新建一个文件夹,然后把我们修改过的这个容器打包成一个新的镜像新建一个test文件夹现在我们已经准备好了要打包的容器啦


【资料图】

打包镜像

因为需要容器ID,我们先查看一下容器ID

# 如果你的容器正在运行中,用这个命令docker ps# 如果你的容器当前没有运行,那就用这个命令来查看容器信息docker ps -a

第一行就是我们要打包的容器,执行 commit命令:

docker commit -m="test commit" -a="kirizi" 30f034aea26a my_image01:1.0

执行成功返回了镜像ID,再用 docker images命令看看我们的所有镜像:可以看到第一行就是我们刚刚创建的my_image01:1.0,并且注意看最后一列 SIZE列,我们的my_image01mariadb的镜像大小几乎是一样的。

# 查看镜像信息docker inspect 镜像ID

我们使用docker inspect来看看我们的镜像和原始镜像的区别在哪儿这是我们的镜像的信息,一些值得注意的信息

# 这个image id是我们用来创建这个容器的mariadb的镜像id,Volumes是"Image": "a748acbaccae",# docker的文件分层机制,可以看到我们的镜像文件分了9层"RootFS": {"Type": "layers","Layers": ["sha256:6515074984c6f8bb1b8a9962c8fb5f310fc85e70b04c88442a3939c026dbfad3","sha256:ef35264eddcdd186fd3a3a994135ee9848f945d75c2ed81fb3db2adf6c3d2fa7","sha256:daec9799caa31439c45c0eda941688a825b2c16abc63cace00d6f6d15c540ce3","sha256:fd44d9fa9cd41d4a154323aa232b22e650b45ad92085a249f9febcd97b2af209","sha256:e77dd0f2e017c73e064e20c166f30e2dd11ed9534a773c848c9bb73a7d6c4004","sha256:cdbb3a99fe5526710d8c51ae42e6eb1a106fa53fb4494c3a9ea7326a88460002","sha256:9a3285a0ae185ce0cc550989d474f5ec59f687fb5f9f3af48dd9fecc942c0900","sha256:9d646cb6b224d9bf1400b776ea4c2684371815902a48abe77e6fdd5058040fbe","sha256:6e28cb318b18cec6896c847a8291f1dc0c8653ee2560a6ee19ff3ad1995737ff"]},

再看看原始的 mariadbimage的信息其他地方都跟my_image01差不多,就不贴上来了,主要看看这个 RootFS字段,可以发现我们自己的镜像有9层,而这个只有8层,并且这8层和my_image01的前8层是一样的,这就是 docker的镜像分层存储机制,也就是联合文件系统。

联合文件系统

联合文件系统(union file system),直接用百度去搜这个关键词搜出来的都是个 docker 相关的东西,但其实联合文件系统不是 docker 创造出来的,它是一种 linux 文件系统。联合文件系统工作在其他文件系统的上一层,它聚合了多个文件系统里的文件到同一个根目录下,比起文件系统,它更像是一个挂载机制。在上图我们可以看到由 XFSext3这两个文件系统控制的不同的路径都被挂载到了 /mnt目录下,比较流行的联合文件系统有 UnionFS, AUFS, OverlayFS等,docker默认使用的文件系统是overlay2,可以使用docker info命令查看当前的文件系统:

OverlayFS为例,我们做几个实验看看联合文件系统是怎么工作的:

联合文件系统实践

前置准备

# 我这里是起一个ubuntu docker容器来进行这个实验,大家如果觉得麻烦也可以直接用自己的宿主机进行# 用docker进行实验的话要记得--privileged=True加这个命令,不然mount命令会因为没有权限而执行失败docker run --name ubuntu01 -it --privileged=True ubuntu:18.04 bash# 创建一个文件夹用来存放我们实验用的各种文件mkdir test_unionfscd test_unionfs# 创建几个基础文件夹mkdir layer1 layer2 layer3 union_layer# 创建虚拟磁盘分区dd if=/dev/zero of=fs1 bs=1024 count=1024dd if=/dev/zero of=fs2 bs=1024 count=1024dd if=/dev/zero of=fs3 bs=1024 count=1024# 创建几个不同的文件系统mkfs -t ext2 fs1mkfs -t ext3 fs2mkfs -t ext4 fs3# 挂载分区到基础文件夹mount fs1 layer1mount fs2 layer2# 创建几个文件touch layer1/file_of_layer1 layer1/fileecho "file from layer1" > layer1/filetouch layer2/file_of_layer2 layer2/fileecho "file from layer2" > layer2/file# 取消挂载umount layer1umount layer2

不使用联合文件系统的挂载

# 挂载fs1到union_layermount fs1 union_layerls union_layercat union_layer/file# 挂载fs2到union_layermount fs2 union_layerls union_layercat union_layer/file

可以看到当我们把 fs2挂载到 union_layer的时候原本挂载的 fs1里的东西就看不见了,只能看见新挂载的fs2里的文件(fs1还是挂载在union_layer上的,因为我们没有取消挂载,可以使用df命令查看当前所有挂载的目录,可以看到union_layer是挂载着两个文件系统的),也就是一个挂载点不能同时挂载多个卷,但是联合文件系统却可以做到这一点

使用联合文件系统进行挂载

# 在实验一里我们挂载了文件系统到 union_layer,先取消挂载,因为我们挂载了两个文件系统,所以要执行两次umount union_layerumount union_layer# 挂载文件系统 -o ro 表示使用只读模式,也就是我们无法修改该文件系统中的原始文件,layer1、layer2 模拟docker image 里的的只读层mount -o ro fs1 layer1mount -o ro fs2 layer2# layer3模拟 docker 容器的最顶层,也就是可读写的容器层,所以它需要读写权限mount fs3 layer3# 创建工作目录mkdir layer3/upper layer3/workdir# 使用 overlay 作为联合文件系统mount -t overlay -o \lowerdir=layer1:layer2,\upperdir=layer3/upper,\workdir=layer3/workdir \none union_layerls union_layer

现在 union_layer里可以同时看到 layer1layer2里的文件了,如果我们在union_layer里修改file file_of_layer1 file_of_layer2这些文件会怎么样呢,看看实验三:

写时复制机制

# 在layer3是无法看见layer1和layer2里的文件的,这里的layer3就是模拟的我们docker里的container layercat layer3/file>"No such file or directory"# 看看layer1里的file文件里有啥cat layer1/file"file from layer1"# 看看layer2里的file文件里有啥cat layer2/file>"file from layer2"cat union_layer/file>"file from layer1"# 当前layer3/upper里是没有东西的,如果我们在挂载了layer1和layer2的union_layer层里进行了文件的修改# 那么修改之后的文件会存储在layer3/upper,这也就是linux里的写时复制(cow)技术cat layer3/upper/file> No such file or directoryecho "file from union_layer" > union_layer/file# 可以看到现在layer3/upper/file里已经有了我们刚刚写到union_layer/file里的内容了cat layer3/upper/file> "file from union_layer"# image 层 layer1 里的内容不变cat layer1/file> "file from layer1"# 移除挂载层里的文件rm union_layer/file# image层里的文件不会受到影响,它是只读的ls layer1> file  file_of_layer1  lost+foundll layer3/upper/file> c--------- 1 root root 0, 0 Jan  7 15:17 layer3/upper/file

再回到 docker中,我们来看看在 docker里是到底怎么通过联合文件系统实现镜像分层的:结合上面的实验再看这张图是不是就很清晰啦,我们实验中的 layer1layer2模拟的是 docker 里的 image layerlayer3模拟的是container layer,挂载的那个 union_layer模拟的是container mountcontainer mount层让我们可以同时看到container layerimage layer里的文件内容,而我们的修改都会存储在container layer,不会影响到image layerimage layer是可以复用的只读层,就像我们文章一开始所打包的那个镜像,我们使用一个镜像创建了容器,并且在这个容器里新建了一个文件,把我们新建了文件的这个容器打包成新的镜像,这个新的镜像只比原来的镜像多了一层,这一层就是图上的container layer

关键词: 文件系统 可以使用