docker镜像详解

Docker镜像详解

什么是镜像

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需要的所有内容,包括代码,运行时(一个程序在运行或者在被执行的依赖)、库,环境变量和配置文件。
所有应用,直接打包docker,可以直接运行

Docker镜像加载原理

Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统是UnionFS联合文件系统。
Docker的镜像实际由一层一层的文件系统组成:

  • bootfs(boot file system)主要包含bootloader和kernel。bootloader主要是引导加载kernel,完成后整个内核就都在内存中了。此时内存的使用权已由bootfs转交给内核,系统卸载bootfs。可以被不同的Linux发行版公用。
  • rootfs(root file system),包含典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是各种不同操作系统发行版(Ubuntu,Centos等)。因为底层直接用Host的kernel,rootfs只包含最基本的命令,工具和程序就可以了。
  • 分层理解
    所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的容器层。
    容器在启动时会在镜像最外层上建立一层可读写的容器层(R/W),而镜像层是只读的(R/O)。

rootfs (root file system),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc, /bin, /etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。Rootfs(根文件系统),在引导之上。包含的就是典型linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。Rootfs就是各种不同的操作系统发行版,比如Ubuntu,CentOS等等。
image.png

平时我们安装进虚拟机的CentOS都是好几个G,为什么Docker这里才200M ?
image.png

对于一个精简的oS, rootfs 可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别,因此不同的发行版可以公用bootfs。

分层理解

我们去下载一个镜像,注意下载日志,可以发现是分层进行下载的
image.png

思考∶为什么Docker镜像要采用这种分层的结构呢?

最大的好处,我觉得莫过于是资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

:::tips
查看镜像分层的方式可以通过docker image inspect命令!
:::

[root@localhost ~]# docker image inspect redis:latest [ { "Id": "sha256:7614ae9453d1d87e740a2056257a6de7135c84037c367e1fffa92ae922784631", "RepoTags": [ "redis:latest" ], "RepoDigests": [ "redis@sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339" ], "Parent": "", "Comment": "", "Created": "2021-12-21T12:42:49.755107412Z", "Container": "13d25f53410417c5220c8dfe8bd49f06abdbcd69faa62a9b877de02464bb04a3", "ContainerConfig": { "Hostname": "13d25f534104", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "6379/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOSU_VERSION=1.12", "REDIS_VERSION=6.2.6", "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz", "REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "CMD [\"redis-server\"]" ], "Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec", "Volumes": { "/data": {} }, "WorkingDir": "/data", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": {} }, "DockerVersion": "20.10.7", "Author": "", "Config": { "Hostname": "", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": false, "AttachStderr": false, "ExposedPorts": { "6379/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "GOSU_VERSION=1.12", "REDIS_VERSION=6.2.6", "REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.6.tar.gz", "REDIS_DOWNLOAD_SHA=5b2b8b7a50111ef395bf1c1d5be11e6e167ac018125055daa8b5c2317ae131ab" ], "Cmd": [ "redis-server" ], "Image": "sha256:e093f59d716c95cfce82c676f099b960cc700432ab531388fcedf79932fc81ec", "Volumes": { "/data": {} }, "WorkingDir": "/data", "Entrypoint": [ "docker-entrypoint.sh" ], "OnBuild": null, "Labels": null }, "Architecture": "amd64", "Os": "linux", "Size": 112691373, "VirtualSize": 112691373, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/e9108002980c92a086707dd3fdaf92585a359803f62463eec03d44d552432e9e/diff:/var/lib/docker/overlay2/ee41879c2adad89d8e0847e4186d01a39dbaa48c3f71fcd725ca55278ee84c14/diff:/var/lib/docker/overlay2/d48921882961deb5ec301f7877e5a529f094475c25a044240f35957b013e2b9b/diff:/var/lib/docker/overlay2/b699114ebaf4efdba2086f24f289bbd2223f6159811f6d2ddf00f0184030883e/diff:/var/lib/docker/overlay2/3186fbc839e6e7d6ecc565b3378d22494f1ec8ee9454f8335a82883dbf21e450/diff", "MergedDir": "/var/lib/docker/overlay2/67146a76f119a87a206599fb753914929ecfd2093f19fa08d8893fbf7c0ee298/merged", "UpperDir": "/var/lib/docker/overlay2/67146a76f119a87a206599fb753914929ecfd2093f19fa08d8893fbf7c0ee298/diff", "WorkDir": "/var/lib/docker/overlay2/67146a76f119a87a206599fb753914929ecfd2093f19fa08d8893fbf7c0ee298/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f", "sha256:9b24afeb7c2f21e50a686ead025823cd2c6e9730c013ca77ad5f115c079b57cb", "sha256:4b8e2801e0f956a4220c32e2c8b0a590e6f9bd2420ec65453685246b82766ea1", "sha256:529cdb636f61e95ab91a62a51526a84fd7314d6aab0d414040796150b4522372", "sha256:9975392591f2777d6bf4d9919ad1b2c9afa12f9a9b4d260f45025ec3cc9b18ed", "sha256:8e5669d8329116b8444b9bbb1663dda568ede12d3dbcce950199b582f6e94952" ] }, "Metadata": { "LastTagTime": "0001-01-01T00:00:00Z" } } ] 

image.png
所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。
该镜像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。、
image.png
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
image.png

上图中的镜像层跟之前图中的略有区别,主要目的是便于展示文件。
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。
image.png
image.png

这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中。Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW[1].下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
image.png

特点:
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!

image.png

commit镜像

docker commit 提交镜像成为一个新的副本 #原理与git相似 docker commit -m ="提交的一些信息" -a="作者" 容器id 镜像名:[tag] 

实战测试:

#启动一个默认的tomcat #发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认 webapps下面是没有文件的! #拷贝进去了基本的文件 #1.复制文件 [root@localhost ~]# docker exec -it c488a6848f7d /bin/bash root@c488a6848f7d:/usr/local/tomcat# cd webapps root@c488a6848f7d:/usr/local/tomcat/webapps# ls root@c488a6848f7d:/usr/local/tomcat/webapps# cd ../ root@c488a6848f7d:/usr/local/tomcat# cp -r webapps.dist/* webapps root@c488a6848f7d:/usr/local/tomcat# cd webapps root@c488a6848f7d:/usr/local/tomcat/webapps# ls ROOT docs examples host-manager manager #2.查看运行状态 [root@localhost ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c488a6848f7d fb5657adc892 "catalina.sh run" 3 hours ago Up 3 hours 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp tender_zhukovsky #3.进行镜像提交 [root@localhost ~]# docker commit -a=““"utoujun" -m="add webapps app" c488a6848f7d tomcat02:1.0 sha256:855f0e3d5375642f9a80d3b59e903c7e14984490372a41ae46750192996fa616 #4、将我们操作过的容器通过commit提交为一个镜像! 我们以后就使用我们修改过的镜像即可, 这就是我们自己的一个修改的镜像 

image.png

如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们以前学习VM时候,快照!

原文链接:https://www.cnblogs.com/yutoujun/p/16927531.html

© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享