docker镜像结构

一、docker镜像揭秘

从整体的角度来讲,一个完整的Docker镜像可以支撑一个Docker容器的运行,在Docker容器运行过程中主要提供文件系统。例如一个centos:7的镜像,提供了一个基本的centos:7的发行版,当然此镜像是不包含操作系统Linux内核的。
从根本上讲,一个容器不过是一个正在运行的进程,并对其应用了一些附加的封装功能,以使其与主机和其他容器隔离。容器隔离的最重要方面之一是每个容器都与自己的专用文件系统进行交互。该文件系统由Docker镜像提供。镜像包括运行应用程序所需的一切代码或二进制文件,运行时,依赖项以及所需的任何其他文件系统对象。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1、镜像通过Docker Daemon守护进程生成容器

2、json文件中指定了一些Env(环境变量)、Cmd(命令),这些json文件由/bin/bash环境来进行解析运行

3、镜像层的layer内容可以理解为它对应的文件系统,也就是数据,运行成容器时数据原封不动的拷贝到容器,

​ rootfs也就是容器中的文件系统,镜像是只读模版的,不能修改数据,只有到容器中才能对数据有写的权限

二、docker镜像与docker容器的关系

Docker镜像是Docker容器运行的基础,没有Docker镜像,就不可能有Docker容器,这也是Docker的设计原则之一。
可以理解的是Docker镜像毕竟是镜像,属于静态的内容。而Docker容器就不一样了,容器属于动态的内容。动态的内容,大家很容易联想到进程,内存,CPU等之类的东西。的确,Docker容器作为动态的内容,都会包含这些。

为了便于理解,大家可以把Docker容器,理解为一个或多个运行进程,而这些运行进程将占有相应的内存,相应的CPU计算资源,相应的虚拟网络设备以及相应的文件系统资源。而Docker容器所占用的文件系统资源,则通过Docker镜像的镜像层文件来提供。

那么作为静态的镜像,如何才有能力转化为一个动态的Docker容器呢?

其实,转化的依据是每个镜像的json文件,Docker可以通过解析Docker镜像的json的文件,获知应该在这个镜像之上运行什么样的进程,应该为进程配置怎么样的环境变量,此时也就实现了静态向动态的转变。
是由Docker守护进程来完成这个转化工作的。Docker容器实质上就是一个或者多个进程,而容器的父进程就是Docker守护进程(Docker Daemon)。这样的,转化工作的执行就不难理解了。Docker守护进程 手握Docker镜像的json文件,为容器配置相应的环境,并真正运行Docker镜像所指定的进程,完成Docker容器的真正创建。Docker容器运行起来之后,Docker镜像json文件就失去作用了。此时Docker镜像的绝大部分作用就是为Docker容器提供一个文件系统,供容器内部的进程访问文件资源

三、docker镜像分层结构

1、base镜像

(1)不依赖其他镜像,从scratch构建(难度大)

(2)以此为基础镜像,进行扩展

base镜像通常都是各种Linux发行版的Docker镜像。不同Linux发行版的区别主要就是rootfs。比如Ubuntu 14.04使用upstart管理服务,apt管理软件包;而 CentOS7使用systemd和yum。这些都是用户空间上的区别,Linux kernel差别不大。所以Docker可以同时支持多种Linux镜像,模拟出多种操作系统环境。容器只能使用Docker host的kernel,并且不能修改。

在这里插入图片描述

2、分层结构

Docker里的镜像绝大部分都是在别的镜像的基础上去进行创建的,也就是使用镜像的分层结构。实际上,Docker Hub中99%的镜像都是通过在base镜像中安装和配置需要的软件构建出来的。

在这里插入图片描述

简单镜像构建:
[root@stw ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
nginx        latest    41f689c20910   6 weeks ago   192MB
httpd        latest    65005131d37e   7 weeks ago   117MB
centos       7         eeb6ee3f44bd   4 years ago   204MB
[root@stw ~]# vim Dockerfile
[root@stw ~]# cat Dockerfile
FROM centos:7
RUN mkdir /galaxy
RUN touch /galaxy/cy
CMD ["/bin/bash"]
[root@stw ~]# docker build -t galaxy:v1 .   //-t 镜像名称  Dockerfile的父目录
[+] Building 1.6s (7/7) FINISHED                                  docker:default
 => [internal] load build definition from Dockerfile                        0.0s
 => => transferring dockerfile: 108B                                        0.0s
 => [internal] load metadata for docker.io/library/centos:7                 0.0s
 => [internal] load .dockerignore                                           0.0s
 => => transferring context: 2B                                             0.0s
 => [1/3] FROM docker.io/library/centos:7                                   0.0s
 => [2/3] RUN mkdir /galaxy                                                 0.9s
 => [3/3] RUN touch /galaxy/cy                                              0.4s
 => exporting to image                                                      0.1s
 => => exporting layers                                                     0.1s
 => => writing image sha256:358cb5259f154f9213baee360b391d4a912d03bc375857  0.0s
 => => naming to docker.io/library/galaxy:v1                                0.0s
[root@stw ~]# pwd
/root
[root@stw ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
galaxy       v1        358cb5259f15   19 seconds ago   204MB
nginx        latest    41f689c20910   6 weeks ago      192MB
httpd        latest    65005131d37e   7 weeks ago      117MB
centos       7         eeb6ee3f44bd   4 years ago      204MB
[root@stw ~]# docker history galaxy:v1  //查看构建的历史记录
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
358cb5259f15   46 seconds ago   CMD ["/bin/bash"]                               0B        buildkit.dockerfile.v0
<missing>      46 seconds ago   RUN /bin/sh -c touch /galaxy/cy # buildkit      0B        buildkit.dockerfile.v0
<missing>      46 seconds ago   RUN /bin/sh -c mkdir /galaxy # buildkit         0B        buildkit.dockerfile.v0
<missing>      4 years ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      4 years ago      /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      4 years ago      /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB     
3、容器层

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如/galaxy,上层的/galaxy会覆盖下层的/galaxy,也就是说用户只能访问到上层中的文件 /galaxy。在容器层中,用户看到的是一个叠加之后的文件系统,(容器层的数据是从镜像层复制到容器中)

在这里插入图片描述

四、docker镜像构建的三种方法

1、docker commit命令

2、基于本地模版导入

3、Dockerfile构建文件

1、docker commit命令

docker commit命令可以基于容器创建镜像,创建过程大致分为三步,先创建容器,在容器中安装我们所需要的内容,再使用docker commit将容器打包为镜像即可。

案例展示:
(1)先基于centos7运行容器,容器名为stw,并使用-it生成终端进入容器
[root@stw ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
galaxy       v1        358cb5259f15   3 hours ago   204MB
nginx        latest    41f689c20910   6 weeks ago   192MB
httpd        latest    65005131d37e   7 weeks ago   117MB
centos       7         eeb6ee3f44bd   4 years ago   204MB
[root@stw ~]# docker run --name stw -it centos:7 /bin/bash
[root@48a18e33e824 /]#  
(2)在容器中创建一个文件
[root@48a18e33e824 /]# mkdir /yyqx  
[root@48a18e33e824 /]# ls
anaconda-post.log  dev  home  lib64  mnt  proc  run   srv  tmp  var
bin                etc  lib   media  opt  root  sbin  sys  usr  yyqx
(3)退出容器后,使用docker commit将容器直接打包成为镜像,新镜像名为centos:v1
[root@48a18e33e824 /]# exit
exit
[root@stw ~]# docker ps -a
CONTAINER ID   IMAGE      COMMAND       CREATED          STATUS                     PORTS     NAMES
48a18e33e824   centos:7   "/bin/bash"   43 seconds ago   Exited (0) 6 seconds ago             stw
[root@stw ~]# docker commit stw centosstw:v1
sha256:8afcbcc87f39b44568a22ba6403c402b907cb50577fb735183495884a31460e3
[root@stw ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
centosstw    v1        8afcbcc87f39   10 seconds ago   204MB
galaxy       v1        358cb5259f15   3 hours ago      204MB
nginx        latest    41f689c20910   6 weeks ago      192MB
httpd        latest    65005131d37e   7 weeks ago      117MB
centos       7         eeb6ee3f44bd   4 years ago      204MB
(4)将新生成的镜像运行成容器,进入容器,查看刚刚创建的目录
[root@stw ~]# docker run -itd --name stw2 centosstw:v1
de44b55d5341e382111556dee14766b57c14501877643aad4fa301e7a41942c4
[root@stw ~]# docker exec -it stw2 /bin/bash
[root@de44b55d5341 /]# ls
anaconda-post.log  dev  home  lib64  mnt  proc  run   srv  tmp  var
bin                etc  lib   media  opt  root  sbin  sys  usr  yyqx

然而,Docker并不建议用户通过这种方式构建镜像。这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。更重要的,使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。

2、基于本地模版导入

用户可以直接从一个操作系统模板文件导入一个镜像,主要使用 docker [container] import 命令。命令格式为 docker [image] import [OPTIONS] file|URL|-[REPOSITORY[:TAG]] ,

要直接导入一个镜像,可以使用 OpenVZ 提供的模板来创建,或者用其他已导入的镜像模板来创建。OpenVZ 模板的下载地址为 http://openvz.org/Download/templates/precreated

(1)下载了 ubuntu:12.04 的模板压缩包,之后使用以下命令导入即可
[root@stw ~]# docker import ubuntu-12.04-x86-minimal.tar.gz stwbuntu:v1
sha256:73ae18a02dfaef8e492fafd1957b779e51978357e9c8c7402a48aa0f7d654817
[root@stw ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
stwbuntu     v1        73ae18a02dfa   9 seconds ago    146MB
centosstw    v1        8afcbcc87f39   12 minutes ago   204MB
galaxy       v1        358cb5259f15   3 hours ago      204MB
nginx        latest    41f689c20910   6 weeks ago      192MB
httpd        latest    65005131d37e   7 weeks ago      117MB
centos       7         eeb6ee3f44bd   4 years ago      204MB
3、Dockerfile手动构建(常见方法)

Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile上添加或者修改指令,重新生成镜像即可,省去了敲命令的麻烦。

1、第一行必须指定,基础镜像信息

​ FROM centos:7

2、维护者信息(可写可不写,现在一般用LABEL代替)

​ MAINTAINER stw@example.com

3、镜像操作指令

​ RUN yum install -y httpd

​ EXPOSE 80

4、容器启动执行指令
 CMD ["/bin/bash"]

​ CMD [“/usr/sbin/httpd”,“-D”,“FOREGROUND”] //httpd

把构建容器所需要的指令都存放在Dockerfile文件中,这个文件的名字是固定的,不能够更改,再使用docker build命令构建容器, 使用 - t 定义新的镜像名,如果构建镜像的Dockerfile文件不在当前目录下可以使用 - f 指定Dockerfile文件路径,示例如下

[root@docker ~]# docker build -t httpd:cycy /root/      //  /root:Dockerfile父目录的名称

dockerfile语法:

5、LABEL指令用于让用户为镜像指定各种元数据(键值对的格式),

​ LABEL <key>=<value> ````<key>=<value>

6、COPY指令用于复制宿主机上的文件到目标镜像中,

​ COPY <src>... <dest>

7、ADD指令跟COPY类似,不过它还支持使用tar文件和URL路径。当拷贝的源文件是tar文件时,会自动展开为一个目录并拷贝进新的镜像中;然而通过URL获取到的tar文件不会自动展开。主机可以再联网的情况下,docker build可以将网络上的某文件引用下载并打包到新的镜像中,

​ ADD <src>... <dest>

8、WORKDIR指令用于指定工作目录,可以指多个,每个WORKDIR只影响他下面的指令,直到遇见下一个WORKDIR为止。WORKDIR也可以调用由ENV指令定义的变量。

​ WORKDIR 相对路径或者绝对路径 (相当于Linux中的cd)

9、VOLUME指令用于在镜像中创建一个挂载点目录。Volume有两种类型:绑定挂载卷和docker管理的卷。在Dockerfile中只支持Docker管理的卷,也就是说只能指定容器内的路径,不能指定宿主机的路径,

​ VOLUME <mountpoint>

​ VOLUME [“<mountpoint>”]

10、EXPOSE指令用于指定容器中待暴露的端口

​ EXPOSE 80

11、ENV指令用于为镜像定义所需的环境变量(使用docker run启动容器的时候加上-e的参数为variable_name赋值,可以覆盖Dockerfile中ENV指令指定的此variable_name的值)

​ ENV <key> <value>

​ ENV <key>=<value> ...

12、RUN指令运行于docker build过程中运行的程序,可以是任何命令。RUN指令后所执行的命令必须在FROM指令后的基础镜像中存在才行

​ RUN <command>

13、CMD指令用于用户指定启动容器的默认要运行的程序,如果不指定,默认是bash,CMD指令指定的默认程序会被docker run命令行指定的参数所覆盖,Dockerfile中可以存在多个CMD指令,但仅最后一个生效,因为一个Docker容器只能运行一个PID为1的进程。

​ CMD command param1 param2

​ CMD [“executable”,“param1”,“param2”]

​ CMD [“param1”,“param2”]

14、ENTRYPOINT指令类似CMD指令的功能,用于为容器指定默认运行程序。Dockerfile中可以存在多个ENTRYPOINT指令,但仅最后一个生效,与CMD区别在于,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT指令指定的程序

​ ENTRYPOINT command param1 param2

​ ENTRYPOINT [“executable”, “param1”, “param2”]

注意:不过,docker run的–entrypoint选项的参数可覆盖ENTRYPOINT指定的默认程序

15、USER用于指定docker build过程中任何RUN、CMD等指令的用户名或者UID。默认情况下容器的运行用户为root

​ USER <user>[:<group>]

​ USER <UID>[:<GID>]

案例:下载安装httpd
1、提前将Centos-7.repo、epel-7.repo两个包导入
[root@stw ~]# rz -E
rz waiting to receive.
[root@stw ~]# rz -E
rz waiting to receive.
[root@stw ~]# ls
anaconda-ks.cfg  Dockerfile  epel-7.repo           Pictures   ubuntu-12.04-x86-minimal.tar.gz
Centos-7.repo    Documents   initial-setup-ks.cfg  Public     Videos
Desktop          Downloads   Music                 Templates
2、编写Dockerfile
[root@stw ~]# vim Dockerfile
[root@stw ~]# cat Dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/*
ADD Centos-7.repo /etc/yum.repos.d/
ADD epel-7.repo /etc/yum.repos.d/
RUN yum -y install httpd
EXPOSE 80
CMD ["/usr/sbin/httpd","-D","FOREGROUND"]
3、使用docker build 命令构建
[root@stw ~]# docker build -t stwhttpd:v1 .
[+] Building 52.9s (10/10) FINISHED                                            docker:default
 => [internal] load build definition from Dockerfile                                     0.0s
 => => transferring dockerfile: 230B                                                     0.0s
 => [internal] load metadata for docker.io/library/centos:7                              0.0s
 => [internal] load .dockerignore                                                        0.0s
 => => transferring context: 2B                                                          0.0s
 => CACHED [1/5] FROM docker.io/library/centos:7                                         0.0s
 => [internal] load build context                                                        0.0s
 => => transferring context: 3.27kB                                                      0.0s
 => [2/5] RUN rm -rf /etc/yum.repos.d/*                                                  1.3s
 => [3/5] ADD Centos-7.repo /etc/yum.repos.d/                                            0.1s
 => [4/5] ADD epel-7.repo /etc/yum.repos.d/                                              0.1s
 => [5/5] RUN yum -y install httpd                                                      50.1s
 => exporting to image                                                                   1.0s 
 => => exporting layers                                                                  1.0s 
 => => writing image sha256:765a412de5175942298396a0b1184f5d55ce53fd85097f80caca6b77014  0.0s 
 => => naming to docker.io/library/stwhttpd:v1                                           0.0s 
4、基于镜像运行成容器,测试访问
[root@stw ~]# docker images                                                                   
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE                                   
stwhttpd     v1        765a412de517   3 minutes ago    535MB
stwbuntu     v1        73ae18a02dfa   46 minutes ago   146MB
centosstw    v1        8afcbcc87f39   59 minutes ago   204MB
galaxy       v1        358cb5259f15   4 hours ago      204MB
nginx        latest    41f689c20910   6 weeks ago      192MB
httpd        latest    65005131d37e   7 weeks ago      117MB
centos       7         eeb6ee3f44bd   4 years ago      204MB
[root@stw ~]# docker run -itd --name stwhttpd1 -P stwhttpd:v1
913c3b69e446b27b27ffc8a243fa9ba5920471792b8d3391b740bdae0d0976ea
[root@stw ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS                                     NAMES
913c3b69e446   stwhttpd:v1    "/usr/sbin/httpd -D …"   5 seconds ago    Up 3 seconds    0.0.0.0:32768->80/tcp, :::32768->80/tcp   stwhttpd1
de44b55d5341   centosstw:v1   "/bin/bash"              58 minutes ago   Up 58 minutes                                             stw2

在这里插入图片描述

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐