首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

Docker--Docker镜像原理

  • 25-04-24 09:41
  • 3267
  • 6753
blog.csdn.net

docker 是操作系统层的虚拟化,所以 docker 镜像的本质是在模拟操作系统。

联合文件系统(UnionFS)

联合文件系统(UnionFS) 是Docker镜像实现分层存储的核心技术,它通过将多个只读层(Image Layers)和一个可写层(Container Layer)叠加,形成一个虚拟的、统一的文件系统。

核心概念

分层存储:

  • Docker镜像由多个只读层组成,每一层对应一个构建步骤(如RUN、COPY指令)。
  • 这些层通过UnionFS叠加在一起,形成一个逻辑上的完整文件系统。

只读层与可写层:

  • 只读层:镜像的每一层都是只读的,确保了镜像的一致性和不可变性。
  • 可写层:当容器启动时,Docker会在镜像的只读层之上添加一个可写的容器层,用于记录容器的文件修改。

共享与复用:

  • 多个容器可以共享同一个镜像的只读层,节省存储空间。
  • 不同容器之间的可写层相互隔离,互不影响。

工作原理

文件系统的叠加:

  • UnionFS将多个只读层和一个可写层按照顺序叠加,形成一个统一的视图。
  • 当访问文件时,UnionFS会从顶层开始查找,直到找到目标文件为止。

写时复制(Copy-on-Write, CoW):
-== 如果容器需要修改只读层中的文件,UnionFS会先在可写层中创建一个该文件的副本,然后对副本进行修改==。

  • 这种机制避免了直接修改只读层,确保了镜像的不可变性。

透明性:

  • 对于用户来说,UnionFS提供的文件系统视图是透明的,用户无需关心文件的实际存储位置。

实现方式

常见实现:

  • AUFS:早期Docker使用的UnionFS实现,但已逐渐被其他实现取代。
  • OverlayFS:现代Linux内核中广泛使用的UnionFS实现,性能更优。
  • Btrfs、ZFS:其他支持UnionFS的文件系统,但使用较少。

OverlayFS的分层结构:

  • LowerDir:镜像的只读层,由多个目录组成。
  • UpperDir:容器的可写层。
  • WorkDir:用于存储OverlayFS的临时数据。
  • MergedDir:最终呈现给容器的统一文件系统视图。

在Docker中的应用场景

镜像构建:

  • Docker通过UnionFS将多个构建步骤的层叠加,形成一个完整的镜像。
  • 每个层都可以被其他镜像共享,减少了存储空间的占用。

容器运行:

  • 容器启动时,Docker会在镜像的只读层之上添加一个可写层,用于记录容器的文件修改。
  • 这种设计使得容器可以快速启动,并且多个容器可以共享同一个镜像。

镜像分发:
由于镜像的层是共享的,Docker在分发镜像时只需要传输新增的层,大大减少了网络带宽的占用。

UnionFS的优势

存储效率:

  • 通过共享层,减少了存储空间的占用。
  • 写时复制机制避免了重复的数据复制。

性能优化:

  • OverlayFS等现代UnionFS实现具有较高的性能,能够满足容器化应用的需求。

灵活性:

  • 支持动态添加和删除层,方便镜像的管理和更新。

Docker分层存储机制

Docker分层存储机制是Docker镜像构建与运行的核心技术,通过将镜像和容器的数据存储在多个独立的层中,实现了高效、灵活的镜像管理和容器运行。

基本概念

镜像层(Image Layer)

  • Docker镜像由多个只读层组成,每一层对应一个构建步骤(如RUN、COPY、ADD指令)。
  • 这些层通过 联合文件系统(UnionFS) 技术叠加,形成一个逻辑上的完整文件系统。
  • 每个层只存储与前一层相比的增量变化,避免重复数据存储。

容器层(Container Layer)

  • 当容器启动时,Docker会在镜像的只读层之上添加一个可写的容器层。
  • 容器运行时的所有修改(如文件创建、修改、删除)都记录在容器层中,不会影响镜像层。

工作原理

镜像构建

  • 构建镜像时,每执行一条Dockerfile指令,都会生成一个新的镜像层。
  • 例如,执行RUN apt-get update && apt-get install -y nginx会在基础镜像层之上新增一层,记录安装的Nginx软件包。

容器运行

  • 容器启动时,Docker会将镜像的只读层与容器层联合挂载,形成一个可读写的文件系统视图。
  • 容器层是临时的,当容器停止或删除时,容器层的修改会丢失(除非通过卷或绑定挂载持久化数据)。

写时复制(Copy-on-Write, CoW)

  • 当容器需要修改只读层中的文件时,Docker会将该文件复制到容器层,然后在容器层中进行修改。
  • 这种机制保证了镜像层的不可变性,同时提高了容器启动速度。

分层存储的优势

镜像复用与共享

  • 多个容器可以共享同一个镜像的只读层,减少存储空间占用。
  • 例如,多个基于同一基础镜像构建的应用镜像可以共享基础镜像层。

高效构建与部署

  • 镜像构建时,Docker会利用缓存机制。如果某一层的内容没有变化,Docker会直接使用缓存的层,而不需要重新构建。
  • 镜像的分层存储使得镜像的传输和存储更加高效。

版本控制与回滚

  • 每一层的变化都可以被追踪,开发者可以轻松地回滚到之前的版本,或者在不同版本之间切换。
    快速启动
  • 由于容器启动时只需添加一个轻量级的可写层,而不是重新创建整个文件系统,因此容器启动速度非常快。

实现细节

层标识符(Layer ID)

  • 每个镜像层都有一个唯一的标识符,用于在不同的镜像之间共享。

存储驱动(Storage Driver)

  • Docker支持多种存储驱动,如AUFS、OverlayFS、Device Mapper等,这些驱动都实现了分层存储的机制。
    例如,OverlayFS是现代Linux系统中广泛使用的存储驱动,性能更优。

层的内容

  • 每一层包含了文件系统的变化,例如添加、删除或修改的文件。这些变化以增量方式存储,只有发生变化的部分会被存储。

镜像分层存储实战

先拉取镜像

docker pull nginx:1.21.1
  • 1

通过 docker image history 查看如下

root@VM-8-12-ubuntu:/data/ahri# docker history nginx:1.21.1
IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
822b7ec2aaf2   3 years ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
<missing>      3 years ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B        
<missing>      3 years ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
<missing>      3 years ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B        
<missing>      3 years ago   /bin/sh -c #(nop) COPY file:09a214a3e07c919a…   4.61kB    
<missing>      3 years ago   /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7…   1.04kB    
<missing>      3 years ago   /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0…   1.96kB    
<missing>      3 years ago   /bin/sh -c #(nop) COPY file:65504f71f5855ca0…   1.2kB     
<missing>      3 years ago   /bin/sh -c set -x     && addgroup --system -…   63.9MB    
<missing>      3 years ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~buster     0B        
<missing>      3 years ago   /bin/sh -c #(nop)  ENV NJS_VERSION=0.6.1        0B        
<missing>      3 years ago   /bin/sh -c #(nop)  ENV NGINX_VERSION=1.21.1     0B        
<missing>      3 years ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B        
<missing>      3 years ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      3 years ago   /bin/sh -c #(nop) ADD file:4ff85d9f6aa246746…   69.3MB  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

可以看到 dockerfile 和做出来的镜像是对应的,而且不是每一层都占用空间的。

我们再通过inspect命令查看该镜像的存储位置。

root@VM-8-12-ubuntu:/data/ahri# docker image inspect nginx:1.21.1
[
    {
        "GraphDriver": {
            "Data": {
                "LowerDir": "/data/var/lib/docker/overlay2/ec2f5f43a9a6f4e7063fb6ef633103b1bca417f34488a4a48736758f9eb6019f/diff:/data/var/lib/docker/overlay2/e368569b4eb5117dabbb84864913883ecf8f50130097619ce128a7bcdf141092/diff:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1/diff:/data/var/lib/docker/overlay2/0b85066e21c3238a8d0214b82399b41b6fedfbebe48ba8a88ab45d0947089685/diff:/data/var/lib/docker/overlay2/8bdfae00fada474094f86a6fc004d5a2e53d660509fcb3ec987d204b2df5eb20/diff",
                "MergedDir": "/data/var/lib/docker/overlay2/b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/merged",
                "UpperDir": "/data/var/lib/docker/overlay2/b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/diff",
                "WorkDir": "/data/var/lib/docker/overlay2/b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:d000633a56813933cb0ac5ee3246cf7a4c0205db6290018a169d7cb096581046",
                "sha256:63b5f2c0d071d1ac41fe869b0f2321c3adec53d8d51b4a03017d865c38dd41f8",
                "sha256:875b5b50454b905c1046c99ab65e403bf27400bf9c96c157332cda2538698dc2",
                "sha256:ed94af62a494fbea70c27afcedea4c303817196b50e8dd98b5be88cd514aab01",
                "sha256:8e58314e4a4fbd97b70bed2b4c5f4b2911ff7f3e3ee310be89fab1120768d533",
                "sha256:d47e4d19ddecb22dc95d641e9c29192a2d13e8506bc60d1c8f6452685ed63634"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

可以看到 GraphDriver 也就是我们的存储驱动,是 overlay2 的存储驱动;
nginx 的 overlay2 的四个目录也都显示出来了,我们知道 docker 的默认目录是/var/lib/docker,之所以在/data/var/lib/docker 下面是因为我们规划了磁盘,调整了默认的存储目录。

可以看到 lowerdir,upperdir,都位于/data/var/lib/docker/overlay2 下面,因为我们调整过默认存储位置所以对比默认的/var/lib/docker 多了/data;我们进入到

cd /data/var/lib/docker/overlay
  • 1

该目录下,查找我们的nginx,看下文件的怎么存储的

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# tree -P nginx -f |grep "/sbin/nginx"
│   │   │   │   └── ./0b85066e21c3238a8d0214b82399b41b6fedfbebe48ba8a88ab45d0947089685/diff/usr/sbin/nginx
│   │   │   │   └── ./db3ef3edafc0f2fe808eb68b6f53aec88b9c2e6fd525bb7e7cf9bbfec464992b/diff/usr/sbin/nginx
│   │   │   │   └── ./e43ea820aaac10fe0afac4afac18f8fa929ae618868ae467f59f3be0348ce09c/diff/usr/sbin/nginx
│   │           │       └── ./eb2gtnp096i7l1cddihp05s0m/diff/usr/local/nginx/sbin/nginx
│   │   │   │   └── ./ee39d178f8d876a5f2a725528e6de013ffca56e8214eb8e01287ec62d5b90d04/diff/usr/sbin/nginx
│   │           │       └── ./fejtx6ef605fty3ldwkg4m1q6/diff/usr/local/nginx/sbin/nginx
│   │           │       └── ./lkq1gz8jjbyoal36hm586np6k/diff/usr/local/nginx/sbin/nginx

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

-P nginx 选项表示只显示匹配模式nginx的文件或目录名。
从当前目录开始,递归地列出所有匹配 nginx 的文件或目录(通过 tree -P nginx -f)。
然后,通过 grep 进一步过滤,只显示路径中包含 /sbin/nginx 的行。

搜索后可以看到我们找到了多个nginx 文件,因为我们本地有多个 nginx 镜像所以搜到了多个 nginx 文件,通过
lowerdir 的值我们可以确定有一个是和我们 nginx:1.12.1 的匹配上的

同样的方式我们通过 Dockerfile 发现,nginx 还存储了个 docker-entrypoint.sh,我们搜索这个文件,我们发现这个文件也被放到了 diff 目录下面,和我们的 lowerdir 中
一个 layer 是对应的。

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# tree -P "docker-entrypoint.sh" -f | grep "docker-entrypoint.sh"
│   │               └── ./2b130b497b862c6acff53f31ebdbc5ecf772345c2b9ce4326f620bcef741507d/diff/usr/local/bin/docker-entrypoint.sh
│   │   └── ./4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1/diff/docker-entrypoint.sh
│   │   └── ./5b1bddba0c572552b60b6b6652bc91a87ac06b9211ba5624dff834375755cf9e/diff/docker-entrypoint.sh
│   │               └── ./64bc799bb08a0ad3430763f0e542b335290e94672e745aa94a852e4304ef4e3f/diff/usr/local/bin/docker-entrypoint.sh
│   │               └── ./78ba0a0382912a6afddfae1e6284cf44613f06053d091450ae5b81843cf8fd29/diff/usr/local/bin/docker-entrypoint.sh
│   │   └── ./895480d1f77b5a0db270020acb3884a3e6c7060e8b0aa549f2cf6010bfb00218/diff/docker-entrypoint.sh
│   │               └── ./a0040d7c6e1a802554a81abc3647e12a173e718387b65c8818fff523da1bb543/diff/usr/local/bin/docker-entrypoint.sh
│   │   └── ./a015c0762e6d24830c7631bec8e3c7959860090f0ea78b8a1dd2a3b5e2d5fe7f/diff/docker-entrypoint.sh
│   │               └── ./abd0373582a3c3c4cd39e9148cfb2d40eb7d61f74fb677a03eadfb9f8e231b41/diff/usr/local/bin/docker-entrypoint.sh
│   │               └── ./b8969b128b086fc04ce55d73892dedc65421ff3da8753ceab61fe958220eeb3c/diff/usr/local/bin/docker-entrypoint.sh
│   │               └── ./faa473d46c0b34676cec3c287b3ce9350b40657fa5f5df14840e086021fa2b8e/diff/usr/local/bin/docker-entrypoint.sh

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

接下来我们进入 diff 的上一级目录查看

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# cd 4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1
root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1# ls
committed  diff  link  lower  work

  • 1
  • 2
  • 3
  • 4

可以看到 link 文件,里面是每一个 diff 目录的短名称,或者说软链接

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1# cat ./link
J6U3CHDJ5RRYP6ONH2VJLP34P2root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1# 

  • 1
  • 2
  • 3

通过遍历 l 目录我们会发现,整个 docker 的镜像的 diff 目录都被做了对应的软链接,或者说起了个短名称。
在这里插入图片描述

每一个 diff 是一个层级的内容,层级的关系是存放到了 lower 文件中,里面存放着父级的层级。

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# cd 4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1
root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1# cat lower
l/HUIS7U7MEMOI47VSVORK45VAB4:l/BDTHLGWDJQYNWQQP4AH2NAT3BEroot@VM-8-12-ubuntu:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1# 

  • 1
  • 2
  • 3
  • 4

最后我们查看下 mergeddir,发现 merged dir 是不存在的,当我们启动为容器的时候才是有有效的。

root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# ll b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/merged
ls: cannot access 'b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/merged': No such file or directory
root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# docker run -d --name mylayer nginx:1.21.1
f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea
root@VM-8-12-ubuntu:/data/var/lib/docker/overlay2# docker inspect mylayer
[
    {
        "Id": "f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea",
        "Created": "2025-04-15T12:33:55.683157888Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 3747944,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2025-04-15T12:33:56.829866983Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:822b7ec2aaf2122b8f80f9c7f45ca62ea3379bf33af4e042b67aafbf6eac1941",
        "ResolvConfPath": "/data/var/lib/docker/containers/f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea/resolv.conf",
        "HostnamePath": "/data/var/lib/docker/containers/f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea/hostname",
        "HostsPath": "/data/var/lib/docker/containers/f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea/hosts",
        "LogPath": "/data/var/lib/docker/containers/f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea/f1a5126c83a4a010a115b3afb340618302e68834ba95b7e6b3afe4c60e3432ea-json.log",
        "Name": "/mylayer",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "docker-default",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "bridge",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                22,
                134
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "host",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": false,
            "PidsLimit": null,
            "Ulimits": [],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware",
                "/sys/devices/virtual/powercap"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/data/var/lib/docker/overlay2/3dfbd9c0692bc89a1d337ab0638741bd740ffa9b3aadf73f67d159eeb3fec6ae-init/diff:/data/var/lib/docker/overlay2/b35408cd1036fd7aa5d4fb5220f06fe9a56606fb2ad1316a8beca766c886e692/diff:/data/var/lib/docker/overlay2/ec2f5f43a9a6f4e7063fb6ef633103b1bca417f34488a4a48736758f9eb6019f/diff:/data/var/lib/docker/overlay2/e368569b4eb5117dabbb84864913883ecf8f50130097619ce128a7bcdf141092/diff:/data/var/lib/docker/overlay2/4d5612682090b9800340353f0550207d69d15ecf7135353cf09a8c8db252afb1/diff:/data/var/lib/docker/overlay2/0b85066e21c3238a8d0214b82399b41b6fedfbebe48ba8a88ab45d0947089685/diff:/data/var/lib/docker/overlay2/8bdfae00fada474094f86a6fc004d5a2e53d660509fcb3ec987d204b2df5eb20/diff",
                "MergedDir": "/data/var/lib/docker/overlay2/3dfbd9c0692bc89a1d337ab0638741bd740ffa9b3aadf73f67d159eeb3fec6ae/merged",
                "UpperDir": "/data/var/lib/docker/overlay2/3dfbd9c0692bc89a1d337ab0638741bd740ffa9b3aadf73f67d159eeb3fec6ae/diff",
                "WorkDir": "/data/var/lib/docker/overlay2/3dfbd9c0692bc89a1d337ab0638741bd740ffa9b3aadf73f67d159eeb3fec6ae/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "f1a5126c83a4",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "80/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "NGINX_VERSION=1.21.1",
                "NJS_VERSION=0.6.1",
                "PKG_RELEASE=1~buster"
            ],
            "Cmd": [
                "nginx",
                "-g",
                "daemon off;"
            ],
            "Image": "nginx:1.21.1",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": [
                "/docker-entrypoint.sh"
            ],
            "OnBuild": null,
            "Labels": {
                "maintainer": "NGINX Docker Maintainers "
            },
            "StopSignal": "SIGQUIT"
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f2228ea45a64eb766b13fa2e23f85d61598da6ea4bd986e06f10717f69f19a08",
            "SandboxKey": "/var/run/docker/netns/f2228ea45a64",
            "Ports": {
                "80/tcp": null
            },
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "09f0d767349c97d93bcf7c4b4eeecea2df7f68e92de6f92f6e3580618667b82a",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null,
                    "NetworkID": "4fa1564bc0380eab5968a99151790435aff1c91960ca086c48a9ad2a267382f3",
                    "EndpointID": "09f0d767349c97d93bcf7c4b4eeecea2df7f68e92de6f92f6e3580618667b82a",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "DNSNames": null
                }
            }
        }
    }
]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220

我们通过镜像实际存储位置可以看到镜像在存储的时候,通过分层来实现,并通过link 和 lower 完成层与层之间链接关系配置,diff 存放了我们的内容,并且没有什么加密。

overlay 文件系统工作实战

我们首先创建一个目录用来挂载我们的文件系统

mkdir -p /data/myworkdir/fs
  • 1

创建文件系统的工作目录

root@VM-8-12-ubuntu:/data# cd /data/myworkdir/fs
root@VM-8-12-ubuntu:/data/myworkdir/fs# ls
root@VM-8-12-ubuntu:/data/myworkdir/fs# mkdir upper lower merged work

  • 1
  • 2
  • 3
  • 4

准备一些文件

root@VM-8-12-ubuntu:/data/myworkdir/fs# echo "in lower" > lower/in_lower.txt
root@VM-8-12-ubuntu:/data/myworkdir/fs# echo "in upper" > upper/in_upper.txt
root@VM-8-12-ubuntu:/data/myworkdir/fs# echo "In both. from lower" > lower/in_both.txt
root@VM-8-12-ubuntu:/data/myworkdir/fs# echo "In both. from upper" > upper/in_both.txt

  • 1
  • 2
  • 3
  • 4
  • 5

挂载 overlay 目录

mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
  • 1

通过 df -h 可以看到我们完成了挂载

root@VM-8-12-ubuntu:/data/myworkdir/fs# df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            937M     0  937M   0% /dev
tmpfs           198M  836K  197M   1% /run
/dev/vda2        50G   29G   19G  61% /
tmpfs           986M   24K  986M   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           986M     0  986M   0% /sys/fs/cgroup
tmpfs           198M     0  198M   0% /run/user/1000
overlay          50G   29G   19G  61% /data/var/lib/docker/overlay2/3dfbd9c0692bc89a1d337ab0638741bd740ffa9b3aadf73f67d159eeb3fec6ae/merged
overlay          50G   29G   19G  61% /data/myworkdir/fs/merged

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

此时看下目录结构,然后发现 merged 目录自动生成了 3 个文件,可以看到both,lower,upper 都在。merged 目录其实就是用户看到的目录,用户的实际文件操作在这里进行。

root@VM-8-12-ubuntu:/data/myworkdir/fs# tree -a
.
├── lower
│   ├── in_both.txt
│   └── in_lower.txt
├── merged
│   ├── in_both.txt
│   ├── in_lower.txt
│   └── in_upper.txt
├── upper
│   ├── in_both.txt
│   └── in_upper.txt
└── work
    └── work


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

merged 目录下编辑一下in_lower.txt,upper 目录下就会马上出现一个 in_lower.txt,而且内容就是编辑后的。而 lower 目录下的 in_lower.txt 内容不变

root@VM-8-12-ubuntu:/data/myworkdir/fs/merged# vi in_lower.txt
root@VM-8-12-ubuntu:/data/myworkdir/fs/merged# cat in_lower.txt
in lower! after edit!
root@VM-8-12-ubuntu:/data/myworkdir/fs/merged# cd ..
root@VM-8-12-ubuntu:/data/myworkdir/fs# tree -a
.
├── lower
│   ├── in_both.txt
│   └── in_lower.txt
├── merged
│   ├── in_both.txt
│   ├── in_lower.txt
│   └── in_upper.txt
├── upper
│   ├── in_both.txt
│   ├── in_lower.txt
│   └── in_upper.txt
└── work
    └── work

5 directories, 8 files
root@VM-8-12-ubuntu:/data/myworkdir/fs# cat upper/in_lower.txt
in lower! after edit!

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

如果我们删除 in_lower.txt,lower 目录里的"in_lower.txt"文件不会有变化,只是在upper/ 目录中增加了一个特殊文件来告诉 OverlayFS,"in_lower.txt'这个文件不能出现在 merged/ 里了,类似 AuFS 的 whiteout

root@VM-8-12-ubuntu:/data/myworkdir/fs# rm -f merged/in_lower.txt
root@VM-8-12-ubuntu:/data/myworkdir/fs# tree -a
.
├── lower
│   ├── in_both.txt
│   └── in_lower.txt
├── merged
│   ├── in_both.txt
│   └── in_upper.txt
├── upper
│   ├── in_both.txt
│   ├── in_lower.txt
│   └── in_upper.txt
└── work
    └── work

5 directories, 7 files

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
root@VM-8-12-ubuntu:/data/myworkdir/fs# ll upper/
total 16
drwxr-xr-x 2 root root 4096 Apr 15 20:49 ./
drwxr-xr-x 6 root root 4096 Apr 15 20:39 ../
-rw-r--r-- 1 root root   20 Apr 15 20:40 in_both.txt
c--------- 1 root root 0, 0 Apr 15 20:49 in_lower.txt
-rw-r--r-- 1 root root    9 Apr 15 20:39 in_upper.txt

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

注意到 upper 下 in_lower.txt 的文件类型没有 ,而是 c 不是-或者 d

可以看到这种文件系统对于底层来说不影响,共享比较容易,但是如果编辑,删除频繁的话,性能还是比较差的。要不停的拷贝或者标记。

注:本文转载自blog.csdn.net的诡异森林。的文章"https://blog.csdn.net/m0_74068921/article/details/147252706"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

115
云原生
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top