Docker 镜像原理(五)

首页 / 🐋Docker / 正文

一、Docker 镜像原理

1、镜像

  Docker 镜像是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。

  以我们的 docker pull tomcat 为例,在下载的过程中我们可以看到 docker 的镜像好像是在一层一层的在下载。

[root@localhost ~]# docker pull tomcat
Using default tag: latest
latest: Pulling from library/tomcat
0e29546d541c: Pull complete 
9b829c73b52b: Pull complete 
cb5b7ae36172: Pull complete 
6494e4811622: Pull complete 
668f6fcc5fa5: Pull complete 
dc120c3e0290: Pull complete 
8f7c0eebb7b1: Pull complete 
77b694f83996: Pull complete 
0f611256ec3a: Pull complete 
4f25def12f23: Pull complete 
Digest: sha256:9dee185c3b161cdfede1f5e35e8b56ebc9de88ed3a79526939701f3537a52324
Status: Downloaded newer image for tomcat:latest
docker.io/library/tomcat:latest

  镜像包含着容器运行时所需要的代码以及其它组件,它是一种分层结构,每一层都是只读的(read-only layers)。构建镜像时,会一层一层构建,前一层是后一层的基础。镜像的这种分层存储结构很适合镜像的复用以及定制。

  构建容器时,通过在镜像的基础上添加一个可写层(writable layer),用来保存着容器运行过程中的修改。

img

2、联合文件系统(UnionFS)

  Docker 的镜像实际上由一层一层的文件系统组成,这种层级的文件系统 UnionFS。Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

​  特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。

3、Docker镜像加载原理

  bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

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

19827908-823b1f9e4726c37b

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

4、分层镜像

  特点:共享资源。比如,有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

  Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层称为"容器层","容器层"之下为"镜像层"。

5、查看镜像

我们有2种方法查看镜像:

  1. 使用docker inspect:获取镜像的元数据
  2. 使用docker history:查看镜像的构建历史

  理论上,一个容器的镜像,最多可以有127层,怎么查看镜像的层数?

  通过 docker Inspect 命令,寻找 RootFS 代码片段,在 Layers 中,有多少行 (sha256) 就代表镜像有多少层。

docker inspect nginx #根据镜像nginx,查看镜像详细信息
"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:2edcec3590a4ec7f40cf0743c15d78fb39d8326bc029073b41ef9727da6c851f",
                "sha256:e379e8aedd4d72bb4c529a4ca07a4e4d230b5a1d3f7a61bc80179e8f02421ad8",
                "sha256:b8d6e692a25e11b0d32c5c3dd544b71b1085ddc1fddad08e68cbd7fda7f70221",
                "sha256:f1db227348d0a5e0b99b15a096d930d1a69db7474a1847acbc31f05e4ef8df8c",
                "sha256:32ce5f6a5106cc637d09a98289782edf47c32cb082dc475dd47cbf19a4f866da",
                "sha256:d874fd2bc83bb3322b566df739681fbd2248c58d3369cb25908d68e7ed6040a6"
            ]
        },

使用docker history可以看到镜像的构建历史。

docker history nginx 
IMAGE          CREATED        CREATED BY                                      SIZE      COMMENT
605c77e624dd   6 months ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B        
<missing>      6 months ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B        
<missing>      6 months ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
<missing>      6 months ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B        
<missing>      6 months ago   /bin/sh -c #(nop) COPY file:09a214a3e07c919a…   4.61kB    
<missing>      6 months ago   /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7…   1.04kB    
<missing>      6 months ago   /bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b0…   1.96kB    
<missing>      6 months ago   /bin/sh -c #(nop) COPY file:65504f71f5855ca0…   1.2kB     
<missing>      6 months ago   /bin/sh -c set -x     && addgroup --system -…   61.1MB    
<missing>      6 months ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~bullseye   0B        
<missing>      6 months ago   /bin/sh -c #(nop)  ENV NJS_VERSION=0.7.1        0B        
<missing>      6 months ago   /bin/sh -c #(nop)  ENV NGINX_VERSION=1.21.5     0B        
<missing>      7 months ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B        
<missing>      7 months ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B        
<missing>      7 months ago   /bin/sh -c #(nop) ADD file:09675d11695f65c55…   80.4MB 

  在Dockerfile中一般,每一行的添加ADD、COPY、RUN,或者创建新(配置)文件的命令,都会触发新建一层镜像,这层镜像一般会被称为中间层镜像,中间层镜像存在的意义:加速镜像构建、重复利用资源。

二、Docker 镜像操作案例

  使用 docker commit 提交容器副本使之成为为一个新的镜像,在此示例中,我们使用 ubuntu 镜像为例,原始的默认ubuntu镜像不带vim命令,我们在外网连通的情况下,安装 vim 软件,安装完成后commit为新的ubuntu镜像。

# 运行 unbntu 镜像
[root@localhost ~]# docker run -it ubuntu bash

# 配置更新
root@393af6f0b855:/# apt-get update

# 安装 vim
root@393af6f0b855:/# apt-get install -y vim

# 验证
root@393af6f0b855:/# vim a.txt
root@393af6f0b855:/# cat a.txt 
aaa

# 提交容器副本使之成为一个新Ubuntu镜像
[root@localhost ~]# docker commit -m="vim cmd add ok" -a="whb" 393af6f0b855 myubuntu:v1

# 查看镜像
[root@localhost ~]# docker images
REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
myubuntu        v1        a7a511fae0fb   9 seconds ago   178MB
# commit 语法
 docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的镜像名称:[tag]
打赏
文章目录