- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
我们经常会使用 docker 或者其他 cri 工具拉取镜像来运行容器,却没有去实际了解 pull 下来的镜像在机器上是怎么存储的。以下以常用的 overlay2 存储驱动为例,解析镜像的存储结构,其他存储驱动也是类似 。
编写如下 Dockerfile 文件 。
FROM ubuntu:latest
ENV author jlz
RUN echo "x1" >> /tmp/test
RUN echo "x2" >> /tmp/test2
RUN echo "x3" >> /tmp/test3
ENTRYPOINT ["/bin/bash", "-c", "sh"]
通过 docker build 命令构建一个镜像 。
docker build -t my-ubuntu:0,1 .
在 overlay2 存储驱动中,镜像层之间的关系可以通过 LowerDir、UpperDir、MergedDir 目录结构表示 对应上面 inspect 出来的镜像 GraphDriver 字段 。
通过 docker inspect {image id} 命令查看镜像信息,如下 。
"Config": {
"Env": [
"author=jlz"
],
"Entrypoint": [
"/bin/bash",
"-c",
"cat /tmp/test"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/mnt/datadisk0/docker/overlay2/dff0bddcffaaa428ea232b202275d48845c11783ea428e9cfa335987cf91805c/diff:/mnt/datadisk0/docker/overlay2/3b5766ed7c43b9417311635ec98d844a98586b9854538975bc4ef12d22edfe1c/diff:/mnt/datadisk0/docker/overlay2/51798d33e8f37ed44c79b7ed5626e95936dd60b8269328557bb6d09f3e353356/diff",
"MergedDir": "/mnt/datadisk0/docker/overlay2/492b8eb5dba9dbb4c72616fe0f8e9423a552d42e5ffe017cbd2e2fb60b3e20a7/merged",
"UpperDir": "/mnt/datadisk0/docker/overlay2/492b8eb5dba9dbb4c72616fe0f8e9423a552d42e5ffe017cbd2e2fb60b3e20a7/diff",
"WorkDir": "/mnt/datadisk0/docker/overlay2/492b8eb5dba9dbb4c72616fe0f8e9423a552d42e5ffe017cbd2e2fb60b3e20a7/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:cdd7c73923174e45ea648d66996665c288e1b17a0f45efdbeca860f6dafdf731",
"sha256:120009c8f50a6cc9022bf7b9fcc7b4f7ef5ba8ea3736dfe974e11780d1a840a0",
"sha256:b6f2b52c36d89acd2e8ce8d85c178c722501dad0ee64de2aa4d15ac18c1cf0fc",
"sha256:7949cc4bef953bb279a2b9b3c27def2a9399706bb1344461299ac4c01c4692df"
]
},
如上 RootFS.Layers 表示这个镜像只有 4 层,因为上面的 Dockerfile 中 base 镜像 ubuntu 本身只有一层,RUN 指令分别对应一层,而 ENV 和 ENTRYPOINT 由于没有涉及到文件系统修改,所以不会有对应的镜像层,他们直接存在于镜像的元数据信息中,如上面的 Config.Env 和 Config.Entrypoint 。
UpperDir:最新的一层镜像层的变更信息(第 n 层),这里对应为 第 4 层,即 RUN echo "x3" >> /tmp/test3 。
LowerDir: 除最新镜像层的所有层(第 1 ~n-1 层),格式为 {n-1}:{n-2}...{1} 。
MergedDir:LowerDir 和 UpperDir 的合并,形成最终的镜像的 rootfs 结构 。
通过这个镜像创建一个容器 。
docker run -it --entrypoint sh {image id}
注意这里的 --entrypoint 参数用于修改容器的 entrypoint 。
在容器中执行命令 echo "hahaha" test4 创建新文件,并通过 docker inspect {container_id} 查看容器存储结构 。
"Config": {
"Entrypoint": [
"sh"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/mnt/datadisk0/docker/overlay2/f2a196d05ccbae06927091297ea503ce59ddf6bc01b8edd686358ca9a41b9abd-init/diff:/mnt/datadisk0/docker/overlay2/492b8eb5dba9dbb4c72616fe0f8e9423a552d42e5ffe017cbd2e2fb60b3e20a7/diff:/mnt/datadisk0/docker/overlay2/dff0bddcffaaa428ea232b202275d48845c11783ea428e9cfa335987cf91805c/diff:/mnt/datadisk0/docker/overlay2/3b5766ed7c43b9417311635ec98d844a98586b9854538975bc4ef12d22edfe1c/diff:/mnt/datadisk0/docker/overlay2/51798d33e8f37ed44c79b7ed5626e95936dd60b8269328557bb6d09f3e353356/diff",
"MergedDir": "/mnt/datadisk0/docker/overlay2/f2a196d05ccbae06927091297ea503ce59ddf6bc01b8edd686358ca9a41b9abd/merged",
"UpperDir": "/mnt/datadisk0/docker/overlay2/f2a196d05ccbae06927091297ea503ce59ddf6bc01b8edd686358ca9a41b9abd/diff",
"WorkDir": "/mnt/datadisk0/docker/overlay2/f2a196d05ccbae06927091297ea503ce59ddf6bc01b8edd686358ca9a41b9abd/work"
},
"Name": "overlay2"
},
可以看到 Config.Entrypoint 被修改为 sh,此时 GraphDriver 中的目录相比 inspect 镜像的结果也发生了变化 。
UpperDir:这个目录包含了容器的可写层,可以看到在容器中创建的 test4 文件。这个目录中的文件可以被修改,但是它们只存在于容器的生命周期中.
LowerDir:这个目录包含了镜像的只读层,也就是镜像的文件系统。结合上面镜像的存储结构可以发现,这里包含了所有的 n 层镜像目录。这些文件是只读的,不能被修改 。
WorkDir:这个目录是 overlay2 文件系统的工作目录,也就是容器内部的工作目录。当你在容器中运行一个命令时,Docker会将该命令的工作目录设置为WorkDir指定的目录.
MergedDir:LowerDir 和 UpperDir 的合并结果,也就是镜像只读层和容器可写层的合并结果.
如果细心的话可以发现 inpect 容器的结果中, LowerDir 除了所有的镜像只读层外,还有一个 init 层 。
“init”结尾的层,夹在只读层和读写层之间。Init 层是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息 。
需要这样一层的原因是,用户往往需要在启动容器时写入一些指定的值比如在/etc/hosts中写入hostname,所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉.
所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的.
最后此篇关于镜像的在节点上的存储结构是怎么样的?的文章就讲到这里了,如果你想了解更多关于镜像的在节点上的存储结构是怎么样的?的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在运行一个辅助角色,并检查 Azure 上托管的存储中是否存在数据。当我将连接字符串用于经典类型的存储时,我的代码可以正常工作,但是当我连接到 V2 Azure 存储时,它会抛出此异常。 “远程服
在我的应用程序的主页上,我正在进行 AJAX 调用以获取应用程序各个部分所需的大量数据。该调用如下所示: var url = "/Taxonomy/GetTaxonomyList/" $.getJSO
大家好,我正在尝试将我的商店导入我的 Vuex Route-Gard。 路由器/auth-guard.js import {store} from '../store' export default
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我正在使用 C# 控制台应用程序 (.NET Core 3.1) 从 Azure Blob 存储读取大量图像文件并生成这些图像的缩略图。新图像将保存回 Azure,并将 Blob ID 存储在我们的数
我想将 Mlflow 设置为具有以下组件: 后端存储(本地):在本地使用 SQLite 数据库存储 Mlflow 实体(run_id、params、metrics...) 工件存储(远程):使用 Az
我的 Windows 计算机上的本地文件夹中有一些图像。我想将所有图像上传到同一容器中的同一 blob。 我知道如何使用 Azure Storage SDKs 上传单个文件BlockBlobServi
我尝试发出 GET 请求来获取我的 Azure Blob 存储帐户的帐户详细信息,但每次都显示身份验证失败。谁能判断形成的 header 或签名字符串是否正确或是否存在其他问题? 代码如下: cons
这是用于编写 JSON 的 NeutralinoJS 存储 API。是否可以更新 JSON 文件(推送数据),而不仅仅是用新的 JS 对象覆盖数据。怎么做到的??? // Javascript
我有一个并行阶段设置,想知道是否可以在嵌套阶段之前运行脚本,所以像这样: stage('E2E-PR-CYPRESS') { when { allOf {
我想从命令行而不是从GUI列出VirtualBox VM的详细信息。我对存储细节特别感兴趣。 当我在GUI中单击VM时,可以看到包括存储部分在内的详细信息: 但是到目前为止,我还没有找到通过命令行执行
我有大约 3500 个防洪设施,我想将它们表示为一个网络来确定流动路径(本质上是一个有向图)。我目前正在使用 SqlServer 和 CTE 来递归检查所有节点及其上游组件,只要上游路径没有 fork
谁能告诉我 jquery data() 在哪里存储数据以及何时删除以及如何删除? 如果我用它来存储ajax调用结果,会有性能问题吗? 例如: $("body").data("test", { myDa
有人可以建议如何为 Firebase 存储中的文件设置备份。我能够备份数据库,但不确定如何为 firebase 存储中的文件(我有图像)设置定期备份。 最佳答案 如何进行 Firebase 存储的本地
我最近开始使用 firebase 存储和 firebase 功能。现在我一直在开发从功能到存储的文件上传。 我已经让它工作了(上传完成并且文件出现在存储部分),但是,图像永远保持这样(永远在右侧加载)
我想只允许用户将文件上传到他们自己的存储桶中,最大文件大小为 1MB,仍然允许他们删除文件。我添加了以下内容: match /myusers/{userId}/{allPaths=**} { al
使用生命周期管理策略将容器的内容从冷访问层移动到存档。我正在尝试以下策略,希望它能在一天后将该容器中的所有文件移动到存档层,但事实并非如此在职的。我设置了选择标准“一天未使用后”。 这是 json 代
对于连接到 Azure 存储端点,有 http 和 https 两个选项。 第一。 https 会带来开销,可能是 5%-10%,但我不支付同一个数据中心的费用。 第二。 http 更快,但 Auth
有人可以帮我理解这一点吗?我创建了Virtual Machine in Azure running Windows Server 2012 。我注意到 Azure 自动创建了一个存储帐户。当我进入该存
我是一名优秀的程序员,十分优秀!