Dockerfile镜像构建用法

在本章中,主要学习如何构建Docker镜像,其实在Docker公共仓库中已经有大量的镜像,但是并不一定满足我们对镜像的需求,所以我们需要学习如何的构建自己所需要的镜像。

Docker镜像构建

Docker镜像可以通过Docker hub或者阿里云等仓库中获取,这些镜像是由官方或者社区人员提供的,对于Docker用户来说并不能满足我们的需求,但是从无开始构建镜像成本大。常用的数据库、中间件、应用软件等都有现成的Docker官方镜像或社区创建的镜像,我们只需要稍作配置就可以直接使用。
	
使用现成镜像的好处除了省去自己做镜像的工作量外,更重要的是可以利用前人的经验。特别是使用那些官方镜像,因为Docker的工程师知道如何更好的在容器中运行软件。

当然,某些情况下我们也不得不自己构建镜像,比如找不到现成的镜像,比如自己开发的应用程序,需要在镜像中加入特定的功能。

Docker提供了三种构建镜像的方法:
(1) docker commit命令
(2) 基于本地模板导入
(3) Dockerfile构建文件

1、docker commit

docker commit命令可以基于容器创建镜像,创建过程大致分为三步,先创建容器,在容器中安装我们所需要的内容,再使用docker commit将容器打包为镜像即可。
下面展示一个示例:在centos的base镜像中安装vim-common并保存为新镜像。
1、先基于centos7运行容器,容器名为cy,并使用-it生成终端进入容器。
[root@docker ~]# docker run --name cy -it centos:7
2、在容器中安装vim-common。
[root@2dc0f7d06aa8 /]# yum -y install vim-common
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
 * base: mirrors.bupt.edu.cn
 * extras: mirrors.cqu.edu.cn
 * updates: mirrors.cqu.edu.cn
base                                                                             | 3.6 kB  00:00:00     
extras                                                                           | 2.9 kB  00:00:00     
updates                                                                          | 2.9 kB  00:00:00     
(1/4): base/7/x86_64/group_gz                                                    | 153 kB  00:00:00     
(2/4): extras/7/x86_64/primary_db                                                | 247 kB  00:00:00     
(3/4): base/7/x86_64/primary_db                                                  | 6.1 MB  00:00:13     
(4/4): updates/7/x86_64/primary_db                                               |  16 MB  00:00:22     

Installed:
  vim-common.x86_64 2:7.4.629-8.el7_9                                                                   

Dependency Installed:
  vim-filesystem.x86_64 2:7.4.629-8.el7_9                                                               

Complete!
[root@2dc0f7d06aa8 /]#

3、退出容器后,使用docker commit将cy容器打包为镜像,新镜像名为centoscy:7

[root@docker ~]# docker commit cy centoscy:7
sha256:282e38de865e6063499df3829e1a6b3854a178b03976472ef3e2b8ffd40a0008
[root@docker ~]# docker images | grep centos
centoscy     7         282e38de865e   24 seconds ago   391MB
centos       cy        0311eef88179   25 minutes ago   204MB
centos       7         eeb6ee3f44bd   9 months ago     204MB
[root@docker ~]# docker run --name cy2 -it centoscy:7 
[root@f5f2a1d6548c /]# rpm -q vim-common
vim-common-7.4.629-8.el7_9.x86_64
[root@f5f2a1d6548c /]# 

这样一个新的镜像就构建完成了,centoscy:7镜像是在centos:7镜像基础之上创建的,通过查看镜像属性,发现centoscy:7要比centos:7镜像大一些。
然而,Docker并不建议用户通过这种方式构建镜像。这是一种手工创建镜像的方式,容易出错,效率低且可重复性弱。更重要的,使用者并不知道镜像是如何创建出来的,里面是否有恶意程序。也就是说无法对镜像进行审计,存在安全隐患。

2、基于本地模板导入

用户可以直接从一个操作系统模板文件导入一个镜像,主要使用 docker [container] import 命令。命令 格式为 docker [image] import [OPTIONS] file|URL|-[REPOSITORY[:TAG]] ,要直接导入一个镜像,可以使用 OpenVZ 提供的模板来创建,或者用其他已导入的镜像模板来创建。OpenVZ 模板的下载地址为 http://openvz.org/Download/templates/precreated。
如:下载了 ubuntu:12.04 的模板压缩包,之后使用以下命令导入即可:

[root@docker ~]# cat ubuntu-12.04-x86-minimal.tar.gz | docker import - ubuntu:12.04
sha256:88216a4bfde304bde7e1195756880acab7921b368da20e3a8591e71afc81b11e
[root@docker ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
ubuntu       12.04     88216a4bfde3   5 seconds ago       146MB

3、Dockerfile构建文件

(1).docker基本概念

Docker镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是Dockerfile。
Dockerfile是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。有了Dockerfile,当我们需要定制自己额外的需求时,只需在 Dockerfile上添加或者修改指令,重新生成镜像即可,省去了敲命令的麻烦。

(2)文件格式

Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动执行指令。一开始必须要指明所基于的镜像名称,接下来一般会说明维护者信息;后面则是镜像操作指令,例如ADD指令。每执行一条ADD指令,镜像添加新的一层,并提交;最后是CMD指令,来指明运行容器时的操作命令。

示例如下,我们构建一个httpd镜像。

[root@docker ~]# ls
Dockerfile 
[root@docker ~]# vim Dockerfile 
1、第一行必须指定,基础镜像信息
FROM centos:7
2、维护者信息
MAINTAINER chenyu@example.com
 3、镜像操作指令
RUN yum install -y httpd
EXPOSE 80
4、容器启动执行指令
CMD ["/bin/bash"]         

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

[root@docker ~]# docker build -t httpd:cycy /root/
Sending build context to Docker daemon    152MB
Step 1/5 : FROM centos:7
 ---> eeb6ee3f44bd
Step 2/5 : MAINTAINER chenyu@example.com
 ---> Running in d41c5db5b3ec
Removing intermediate container d41c5db5b3ec
 ---> a9c67ae8f88e
Step 3/5 : RUN yum -y install httpd
 ---> Running in e4777ad252f6
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
 * base: mirrors.neusoft.edu.cn
 * extras: mirrors.neusoft.edu.cn
 * updates: mirrors.neusoft.edu.cn
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-97.el7.centos.5 will be installed
--> Processing Dependency: httpd-tools = 2.4.6-97.el7.centos.5 for package: httpd-2.4.6-97.el7.centos.5.x86_64
--> Processing Dependency: system-logos >= 7.92.1-1 for package: httpd-2.4.6-97.el7.centos.5.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-97.el7.centos.5.x86_64
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64
--> Running transaction check
---> Package apr.x86_64 0:1.4.8-7.el7 will be installed
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
---> Package centos-logos.noarch 0:70.0.6-3.el7.centos will be installed
---> Package httpd-tools.x86_64 0:2.4.6-97.el7.centos.5 will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

Installed:
  httpd.x86_64 0:2.4.6-97.el7.centos.5                                          

Dependency Installed:
  apr.x86_64 0:1.4.8-7.el7                                                      
  apr-util.x86_64 0:1.5.2-6.el7                                                 
  centos-logos.noarch 0:70.0.6-3.el7.centos                                     
  httpd-tools.x86_64 0:2.4.6-97.el7.centos.5                                    
  mailcap.noarch 0:2.1.41-2.el7                                                 

Complete!
Removing intermediate container e4777ad252f6
 ---> e7e8c35f9b15
Step 4/5 : EXPOSE 80
 ---> Running in 56b747392c13
Removing intermediate container 56b747392c13
 ---> 65c05b81e846
Step 5/5 : CMD ["/bin/bash"]
 ---> Running in 6f6b7c08c6ab
Removing intermediate container 6f6b7c08c6ab
 ---> b44f420b6834
Successfully built b44f420b6834
Successfully tagged httpd:cycy

通过以上镜像的构建过程可以看出,Dockerfile文件内的指令会逐一运行,构建过程如下:
1、下载centos7镜像。
2、添加镜像构建者信息
3、基于centos7镜像启动容器,安装httpd软件,安装完毕后将容器打包为镜像。
4、基于上一步生成的镜像启动容器,将80端口打开,打开后将容器打包为镜像。
5、基于上一步生成的镜像启动容器,添加容器启动后需要执行的指令,再打包为镜像。

 也就说一条指令就是一层镜像,还可以通过docker history查看镜像的构建过程,这样我们构建的镜像就呈现出透明化,整个构建的过程都可以看到。
[root@docker ~]# docker history httpd:cycy 
IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
b44f420b6834   10 minutes ago   /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
65c05b81e846   10 minutes ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
e7e8c35f9b15   10 minutes ago   /bin/sh -c yum -y install httpd                 203MB     
a9c67ae8f88e   13 minutes ago   /bin/sh -c #(nop)  MAINTAINER chenyu@example…   0B        
eeb6ee3f44bd   9 months ago     /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      9 months ago     /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B      
  <missing>      9 months ago     /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB

(3)镜像缓存

使用DockerFile文件构建完镜像以后,Docker会把构建过程中的每一层临时镜像进行缓存。在构建新镜像时,可以直接使用之前缓存的镜像层,这样能加速镜像的构建。镜像缓存示例如下:

[root@docker ~]# vim Dockerfile 
1、第一行必须指定,基础镜像信息
FROM centos:7
2、维护者信息
MAINTAINER chenyu@example.com
3、镜像操作指令
RUN mkdir /cy         

修改之前的Dockerfile文件,然后我们再构建新的镜像,构建过程如下,通过构建过程可以得知,DockerFile文件里面共三条指令,前两条指令都是用之前构建镜像的缓存,只有第三个指令才重新构建了缓存层。如果希望在构建镜像时不使用缓存,可以在docker build命令中加上–no-cache参数。

(4)dockerfile语法

Dockerfile是由一系列指令和参数构成的脚本,一个Dockerfile里面包含了构建整个镜像的完整指令。Docker通过docker build执行Dockerfile中的一系列指令自动构建镜像,常用的Dockerfile指令有以下几种。

1、FROM

指令必须为Dockerfile文件开篇的第一个非注释行,用于指定构建镜像所使用的基础镜像,后续的指令运行都要依靠此基础镜像所提供的的环境。实际使用中,如果没有指定仓库,docker build会先从本机查找是否有此基础镜像,如果没有会默认去Docker Hub Registry上拉取,再找不到就会报错,格式如下。
FROM [:]
FROM @
Digest:镜像的哈希码,防止镜像被冒名顶替。

2、MAINTAINER

指令用于让Dockerfile的作者提供个人的信息,Dockerfile并不限制MAINTAINER指令的位置,但是建议放在FROM指令之后,在较新的Docker版本中,已经被LABEL替代,格式如下。
MAINTAINER “cy@example.com”

3、LABEL

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

4、COPY

指令用于复制宿主机上的文件到目标镜像中,格式如下。
COPY …
COPY [“”,… “”]
:要复制的源文件或者目录,支持通配符
:目标路径,即正创建的镜像的文件系统路径,建议使用绝对路径,否则,COPY指令会以WORKDIR为其起始路径。如果路径中如果包含空白字符,建议使用第二种格式用引号引起来,否则会被当成两个文件。

5、ADD

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

6、WORKDIR

指令用于指定工作目录,可以指多个,每个WORKDIR只影响他下面的指令,直到遇见下一个WORKDIR为止。WORKDIR也可以调用由ENV指令定义的变量。,格式如下。
WORKDIR 相对路径或者绝对路径

7、VOLUME

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

8、EXPOSE

指令用于指定容器中待暴露的端口。比如容器提供的是一个https服务且需要对外提供访问,那就需要指定待暴露443端口,然后在使用此镜像启动容器时搭配-P的参数才能将待暴露的状态转换为真正暴露的状态,转换的同时443也会转换成一个随机端口,跟-p :443一个意思。EXPOSE指令可以一次指定多个端口,例如:EXPOSE 11111/udp 11112/tcp,格式如下。
EXPOSE [/] [[/] …]

9、ENV

指令用于为镜像定义所需的环境变量,并可被ENV指令后面的其它指令所调用。调用格式为 v a r i a b l e n a m e 或者 variable_name或者 variablename或者{variable_name},使用docker run启动容器的时候加上-e的参数为variable_name赋值,可以覆盖Dockerfile中ENV指令指定的此variable_name的值。但是不会影响到Dockerfile中已经引用过此变量的文件名,格式如下。
ENV
ENV = …

10、RUN

指令运行于docker build过程中运行的程序,可以是任何命令。RUN指令后所执行的命令必须在FROM指令后的基础镜像中存在才行,格式如下。
RUN
RUN [“executable”, “param1”, “param2”]
通常是一个shell命令,系统默认会把后面的命令作为shell的子进程来运行,以"/bin/sh -c"来运行它。
第二种格式的参数是一个JSON格式的数组,其中"executable"为要运行的命令,后面的"paramN"为传递给命令的选项或参数。

11、CMD

指令用于用户指定启动容器的默认要运行的程序,也就是PID为1的进程命令,且其运行结束后容器也会终止。如果不指定,默认是bash。CMD指令指定的默认程序会被docker run命令行指定的参数所覆盖。Dockerfile中可以存在多个CMD指令,但仅最后一个生效。因为一个Docker容器只能运行一个PID为1的进程。类似于RUN指令,也可以运行任意命令或程序,但是两者的运行时间点不同。RUN指令运行在docker build的过程中,而CMD指令运行在基于新镜像启动容器时,格式如下。
CMD command param1 param2
CMD [“executable”,“param1”,“param2”]
CMD [“param1”,“param2”]
前两种语法格式同RUN指令。第一种用法对于CMD指令基本没有意义,因为它运行的程序PID不为1。
第三种则需要结合ENTRYPOINT指令使用,CMD指令后面的命令作为ENTRYPOINT指令的默认参数。如果docker run命令行结尾有参数指定,那CMD后面的参数不生效。

12、ENTRYPOINT

指令类似CMD指令的功能,用于为容器指定默认运行程序。Dockerfile中可以存在多个ENTRYPOINT指令,但仅最后一个生效,与CMD区别在于,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT指令指定的程序,格式如下。
ENTRYPOINT command param1 param2
ENTRYPOINT [“executable”, “param1”, “param2”]
不过,docker run的–entrypoint选项的参数可覆盖ENTRYPOINT指定的默认程序。

13、USER

R用于指定docker build过程中任何RUN、CMD等指令的用户名或者UID。默认情况下容器的运行用户为root,格式如下。
USER [:]
USER [:]

在这里插入图片描述

容器实例

[root@localhost ~]# cat Dockerfile

//基于基础镜像centos:7
FROM centos:7

//维护者信息
LABEL MAINTAINER="lty@qq.com"

//添加Centos-7仓库
//添加epel-7仓库
ADD   Centos-7.repo /etc/yum.repos.d
ADD   epel-7.repo  /etc/yum.repos.d

//安装nginx软件包
RUN yum -y install nginx

//暴露指定端口88
EXPOSE 88


CMD ["/usr/sbin/nginx","-g","daemon off;"]		//指定镜像生成容器后在前台运行

7、构建镜像,镜像名称为nginx:v1

[root@localhost ~]# docker build -t nginx:v1 /root/	
//生成镜像步骤
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
STEP 1/10: FROM centos
STEP 2/10: LABEL MAINTAINER="lty@qq.com"
--> Using cache 58001e044238c3242028d609c57721ae7eab0b5cfcd4435983f7e00c494f9004
--> 58001e04423
STEP 3/10: WORKDIR /usr/src
--> Using cache 754530092c199ee2dfda687adc28e683123020a227a36323a3acab3e2f5913c7
--> 754530092c1
STEP 4/10: ADD   Centos-7.repo /etc/yum.repos.d
--> ff29ef241ad
STEP 5/10: ADD   epel-7.repo /etc/yum.repos.d
--> 030508fd3b2
STEP 6/10: RUN yum -y install nginx
Loaded plugins: fastestmirror, ovl
Repository base is listed more than once in the configuration
Repository updates is listed more than once in the configuration
Repository extras is listed more than once in the configuration
Repository centosplus is listed more than once in the configuration
Determining fastest mirrors
 * base: mirrors.ustc.edu.cn
 * extras: mirrors.ustc.edu.cn
 * updates: mirrors.ustc.edu.cn
Resolving Dependencies

Installed:
  nginx.x86_64 1:1.20.1-9.el7                                                   

Dependency Installed:
  centos-indexhtml.noarch 0:7-9.el7.centos                                      
  centos-logos.noarch 0:70.0.6-3.el7.centos                                     
  gperftools-libs.x86_64 0:2.6.1-1.el7                                          
  make.x86_64 1:3.82-24.el7                                                     
  nginx-filesystem.noarch 1:1.20.1-9.el7                                        
  openssl.x86_64 1:1.0.2k-25.el7_9                                              
  openssl11-libs.x86_64 1:1.1.1k-4.el7                                          

Dependency Updated:
  openssl-libs.x86_64 1:1.0.2k-25.el7_9                                         

Complete!							yum源安装nginx服务
--> 511945168d6
STEP 7/10: EXPOSE 80
--> ce67bae6c31
STEP 8/10: ENV PATH /usr/local/nginx/bin:$PATH
--> 8e5053c64ad
STEP 9/10: CMD  ["-D","FOREGROUND"]
--> 25e1d03c59b
STEP 10/10: ENTRYPOINT ["/usr/local/nginx/bin/httpd"]
COMMIT nginx:v1
--> 4d412883b9f
Successfully tagged localhost/nginx:v1
4d412883b9fbb792c40d99215dd1a0e01acce4ed2e65206a79431a23b806fe75

8、运行容器,容器名称为自己名字的全拼,映射端口88:80

[root@localhost ~]# docker run -it --name liutianyang -p 88:80 4742ec39c004
"9ca386dd2515627326208f9ee9be8d94f52d311fb8d2b99869a0a4ac50745770"
[root@localhost ~]# docker ps -a
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
CONTAINER ID  IMAGE               COMMAND               CREATED        STATUS            PORTS               NAMES
9ca386dd2515  localhost/nginx:v1  /usr/sbin/nginx -...  2 minutes ago  Up 2 seconds ago  0.0.0.0:88->80/tcp  liutianyang
[root@localhost ~]# ss -antl
State    Recv-Q   Send-Q      Local Address:Port       Peer Address:Port   Process   
LISTEN   0        128               0.0.0.0:22              0.0.0.0:*                
LISTEN   0        128               0.0.0.0:88              0.0.0.0:*    

9、进入容器,删除默认网页,写入新的默认网页,网页内容为你们自己名字的全拼

[root@localhost ~]# docker exec -it 9ca386dd2515 /bin/bash
Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
[root@9ca386dd2515 /]# cd /usr/share/nginx/
[root@9ca386dd2515 nginx]# ls
html  modules
[root@9ca386dd2515 nginx]# cd html/
[root@9ca386dd2515 html]# ls
404.html  50x.html  en-US  icons  img  index.html  nginx-logo.png  poweredby.png
[root@9ca386dd2515 html]# rm -rf index.html       
[root@9ca386dd2515 html]# ls
404.html  50x.html  en-US  icons  img  nginx-logo.png  poweredby.png
[root@9ca386dd2515 html]# echo 6666 > index.html
[root@9ca386dd2515 html]# ls
404.html  50x.html  en-US  icons  img  index.html  nginx-logo.png  poweredby.png
[root@9ca386dd2515 html]# cat index.html 
liutianyang
[root@localhost ~]# curl http://192.168.47.137:88
liutianyang

10、通过浏览器,能够正常访问nginx

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值