镜像是什么
- 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。
- 所有应用,直接打包
docker
镜像,就可以直接跑起来!
如何得到镜像
- 从远程仓库下载
- 别人拷贝给你
- 自己制作一个镜像
DockerFile
Docker 镜像加载原理
UnionFs (联合文件系统)
-
UnionFs
(联合文件系统):
Union
文件系统(UnionFs
)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下unite several directories into a single virtual filesystem
。
Union
文件系统是Docker
镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。Docker
镜像加载原理 -
docker
的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS
。 -
boots(boot file system)
主要包含bootloader
和Kernel
:
bootloader
主要是引导加kernel
,Linux
刚启动时会加bootfs
文件系统,在Docker
镜像的最底层是boots
。这一层与我们典型的Linux/Unix
系统是一样的,包含boot
加载器和内核。当boot
加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs
转交给内核,此时系统也会卸载bootfs
。 -
rootfs
(root file system),在bootfs
之上。包含的就是典型Linux
系统中的/dev
,/proc,/bin,/etc
等标准目录和文件。rootfs
就是各种不同的操作系统发行版,比如Ubuntu, Centos
等等。
- 平时我们安装进虚拟机的
CentOS
都是好几个G,为什么Docker
这里才200M?
[root@VM-0-6-centos ~]# docker images centos
REPOSITORY TAG IMAGE ID CREATED SIZE
centos latest 300e315adb2f 6 months ago 209MB
- 相当于精简的
OS
,rootfs
可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用Host
的kernel
,自己只需要提供rootfs
就可以了。由此可见对于不同的Linux
发行版,boots
基本是一致的,rootfs
会有差別,因此不同的发行版可以公用bootfs
。虚拟机是分钟级别,容器是秒级!
分层理解
-
分层的镜像
我们可以去下载一个镜像,注意观察下载的日志输出,可以看到是一层层的在下载
思考:为什么
Docker
镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的Base
镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也
只需要加载一份base
镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。 查看镜像分层的方式可以通过
docker image inspect
命令
[root@VM-0-6-centos ~]# docker image inspect centos
[
{
"Id": "sha256:300e315adb2f96afe5f0b2780b87f28ae95231fe3bdd1e16b9ba606307728f55",
"RepoTags": [
"centos:latest"
],
"RepoDigests": [
"centos@sha256:5528e8b1b1719d34604c87e11dcd1c0a20bedf46e83b5632cdeac91b8c04efc1"
],
"Parent": "",
"Comment": "",
"Created": "2020-12-08T00:22:53.076477777Z",
"Container": "395e0bfa7301f73bc994efe15099ea56b8836c608dd32614ac5ae279976d33e4",
"ContainerConfig": {
"Hostname": "395e0bfa7301",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/bash\"]"
],
"Image": "sha256:6de05bdfbf9a9d403458d10de9e088b6d93d971dd5d48d18b4b6758f4554f451",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"DockerVersion": "19.03.12",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash"
],
"Image": "sha256:6de05bdfbf9a9d403458d10de9e088b6d93d971dd5d48d18b4b6758f4554f451",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"Architecture": "amd64",
"Os": "linux",
"Size": 209348104,
"VirtualSize": 209348104,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/03bfa77f95d5017e54c3f87830bf22c24baf84d3876d04cff6fecf7cb15aeb27/merged",
"UpperDir": "/var/lib/docker/overlay2/03bfa77f95d5017e54c3f87830bf22c24baf84d3876d04cff6fecf7cb15aeb27/diff",
"WorkDir": "/var/lib/docker/overlay2/03bfa77f95d5017e54c3f87830bf22c24baf84d3876d04cff6fecf7cb15aeb27/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:2653d992f4ef2bfd27f94db643815aa567240c37732cae1405ad1c1309ee9859"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
理解:
- 所有的
Docker
镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。 - 举一个简单的例子,假如基于
Ubuntu Linux16.04
创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python
包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。 - 在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点。
- 上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
- 下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。
- 文中情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中
Docker
通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux
上可用的存储引撃有AUFS
、Overlay2
、Device Mapper
、Btrfs
以及ZFS
。顾名思义,每种存储引擎都基于Linux
中对应的件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。 -
Docker
在Windows
上仅支持windowsfilter
一种存储引擎,该引擎基于NTFS
文件系统之上实现了分层和CoW [1]
。 - 下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。
特点
-
Docker
镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!