【Docker篇】Dockerfile构建过程,Dockerfile指令,CMD 和 ENTRYPOINT 的区别

Dockerfile

在前面的文章中我们就说过,镜像可以打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。我们在使用过程中通常会直接拉取官方为我们制作好的镜像,那么我们能不能自己制作镜像呢?

答案是肯定的。使用到的就是Dockerfile。

1. 什么是Dockerfile

Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。

Dockerfile中记录了镜像制作过程中的每一个详细的步骤,我们到官网上看看一个centos的镜像是怎么做出来的。

https://hub.docker.com/_/centos

在这里插入图片描述
在这里插入图片描述

这是官网上centos镜像的Dockerfile,可以看到一个centos镜像里面都包含了哪些内容。

我们也可以仿照此制作自己的镜像。

构建镜像一般有以下几个步骤:

  1. 编写Dockerfile文件
  2. docker build 构建镜像
  3. docker run 运行

2. Dockerfile构建过程

基础知识

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. # 表示注释
  4. 每条指令都会创建一个新的镜像层,并对镜像进行提交

流程

  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器做出修改
  3. 执行类似 docker commit 的操作提交一个新的镜像层
  4. Docker再基于刚提交的镜像运行一个新容器
  5. 执行Dockerfile中的下一条指令直到所有指令都执行完成!

说明
从应用软件的角度来看,Dockerfile,docker镜像与docker容器分别代表软件的三个不同阶段。

  • Dockerfile 是软件的原材料 (代码)
  • Docker 镜像则是软件的交付品 (.apk)
  • Docker 容器则是软件的运行状态 (客户下载安装执)

Dockerfile 面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可!

在这里插入图片描述

Dockerfile:需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。

Docker镜像:在Dockerfile 定义了一个文件之后,Docker build 时会产生一个Docker镜像,当运行Docker 镜像时,会真正开始提供服务;

Docker容器:容器对外提供服务。
在这里插入图片描述

3. Dockerfile指令

关键字

上面我们看了制作centos镜像的Dockerfile,里面就是一些指令,我们这里将一些常用指令进行汇总。

FROM 		# 基础镜像,当前新镜像是基于哪个镜像的
MAINTAINER  # 镜像维护者的姓名和邮箱地址
RUN 		# 容器构建时需要运行的命令
EXPOSE		# 当前容器对外保留出的端口
WORKDIR 	# 指定在创建容器后,终端默认登录的进来工作目录,一个落脚点
ENV 		# 用来在构建镜像过程中设置环境变量
ADD 		# 将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包
COPY 		# 类似ADD,拷贝文件和目录到镜像中!
VOLUME 		# 容器数据卷,用于数据保存和持久化工作
CMD 		# 指定一个容器启动时要运行的命令,Dockerfile中可以有多个CMD指令,但只有最后一个生效!
ENTRYPOINT 	# 指定一个容器启动时要运行的命令!和CMD一样
ONBUILD 	# 当构建一个被继承的Dockerfile时运行命令,父镜像在被子镜像继承后,父镜像的ONBUILD被触发

这里注意ADD和COPY的区别,经常使用

看指令不太好理解,我们通过一张图片来给大家说明。

在这里插入图片描述

4. 实战测试

4.1 制作centos镜像

我们从centos的Dockerfile中可以看出,centos镜像来源于一个base镜像(Scratch),Docker Hub中绝大多数镜像都是通过此基础镜像安装和配置需要的软件构建。

在这里插入图片描述

当我们使用官网提供的centos时会发现很多问题,比如没有vim命令编辑器,查看网络配置ifconfig等等,我们现在做一个镜像,能够使用这些命令。

在这里插入图片描述

  1. 编写Dockerfile
[root@jiangnan centos]# pwd
/home/centos
[root@jiangnan centos]# vim Dockerfile-centos 
[root@jiangnan centos]# cat Dockerfile-centos 
FROM centos:7
MAINTAINER jiangnan<[email protected]>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum install -y vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "----------end--------"
CMD /bin/bash
[root@jiangnan centos]# 

说明:我们这里以centos7为基础镜像。

  1. 构建

docker build -f /home/centos/Dockerfile-centos -t mycentos:1.0 .

-f:指定Dockerfile文件。-t:给镜像命名。后面有个点不要忘了。

[root@jiangnan centos]# docker build -f /home/centos/Dockerfile-centos -t mycentos:1.0 .
Sending build context to Docker daemon  2.048kB
Step 1/10 : FROM centos:7
 ---> eeb6ee3f44bd
Step 2/10 : MAINTAINER jiangnan<[email protected]>
 ---> Running in 6fd0d509a785
Removing intermediate container 6fd0d509a785
 ---> 9945ff2fb154
Step 3/10 : ENV MYPATH /usr/local
........
 ---> a4b55ee0c621
Successfully built a4b55ee0c621
Successfully tagged mycentos:1.0
[root@jiangnan centos]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
mycentos     1.0       a4b55ee0c621   About a minute ago   570MB
centos       7         eeb6ee3f44bd   5 months ago         204MB
[root@jiangnan centos]# 

注意:构建命令最后有个.

  1. 运行
[root@jiangnan centos]# docker run -it mycentos:1.0 /bin/bash
[root@669ce95e0e0b local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:ac:11:00:02  txqueuelen 0  (Ethernet)
        RX packets 7  bytes 586 (586.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[root@669ce95e0e0b local]# vim hello.txt
[root@669ce95e0e0b local]# cat hello.txt 
hello,Docker
[root@669ce95e0e0b local]# 

可以看到我们要的效果达到了。

  1. 查看历史变更步骤

我们前面也说了,Dockerfile中记录了镜像制作过程中的每一个详细的步骤,那我们怎么看呢?

docker history 镜像名ID

[root@jiangnan centos]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED             SIZE
mycentos     1.0       a4b55ee0c621   About an hour ago   570MB
centos       7         eeb6ee3f44bd   5 months ago        204MB
[root@jiangnan centos]# docker history a4b55ee0c621
IMAGE          CREATED             CREATED BY                                      SIZE      COMMENT
a4b55ee0c621   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B        
c7d422106fd9   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
07b9b6147049   About an hour ago   /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B        
20704538d7c4   About an hour ago   /bin/sh -c #(nop)  EXPOSE 80                    0B        
9c58a0593f09   About an hour ago   /bin/sh -c yum -y install net-tools             156MB     
341ac0e40b31   About an hour ago   /bin/sh -c yum install -y vim                   211MB     
52a117dd18a2   About an hour ago   /bin/sh -c #(nop) WORKDIR /usr/local            0B        
746a15b8b0fa   About an hour ago   /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B        
9945ff2fb154   About an hour ago   /bin/sh -c #(nop)  MAINTAINER jiangnan<xxc11…   0B        
eeb6ee3f44bd   5 months ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B        
<missing>      5 months ago        /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B        
<missing>      5 months ago        /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4…   204MB     
[root@jiangnan centos]# 

说明:从这里可以看出我们在Dockerfile中定义每一个步骤都会有记录。而且我们还发现了一个很重要的规律,Dockerfile是由上往下写的,但是镜像是从下往上的,这就验证了我们之前说的镜像是一层一层叠加起来的

4.2 制作tomcat镜像

我们知道tomcat镜像运行需要jdk环境,那么这次我们将jdk连同tomcat一同打包成镜像。

首先准备好jdk和tomcat安装包
在这里插入图片描述

  1. 编写Dockerfile
# 设置基础镜像
FROM centos:7
# 设置作者
MAINTAINER jiangnan<[email protected]>
# 将readme.txt复制到容器中
COPY readme.txt /usr/local
# 将安装包复制到容器中并配置环境变量
ADD jdk-8u161-linux-x64.tar.gz /usr/local
ENV JAVA_HOME /usr/local/jdk1.8.0_161
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

ADD apache-tomcat-9.0.58.tar.gz /usr/local
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.58
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.58
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
# 删除不需要的安装包
RUN rm -f /usr/local/*.tar.gz
# 设置工作目录
WORKDIR /usr/local/apache-tomcat-9.0.58
# 暴露端口
EXPOSE 8080
# 启动tomcat
ENTRYPOINT ["./bin/catalina.sh", "run"]
  1. 构建镜像
[root@jiangnan tomcat]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
mytomcat     1.0       2733bd702ea7   8 seconds ago   604MB
centos       7         eeb6ee3f44bd   5 months ago    204MB
[root@jiangnan tomcat]# 
  1. 运行
[root@jiangnan tomcat]# docker run -dit --name=divtomcat -p 9090:8080 -v /home/tomcat/webapps/:/usr/local/apache-tomcat-9.0.58/webapps mytomcat:1.0
962898ed75522850347bca325ff213f6ce869d2d6a762c0710e61ca8b86ff6da
[root@jiangnan tomcat]# 
  1. 将我们的项目cp到webapps目录下
[root@jiangnan tomcat]# cp -rf music webapps/
[root@jiangnan tomcat]# cd webapps/music/
[root@jiangnan music]# ll
total 24
drwxr-xr-x 2 root root 4096 Feb 26 19:15 css
drwxr-xr-x 2 root root 4096 Feb 26 19:15 images
-rw-r--r-- 1 root root 2707 Feb 26 19:15 index.html
drwxr-xr-x 2 root root 4096 Feb 26 19:15 js
[root@jiangnan music]# 

/home/tomcat/webapps/和/usr/local/apache-tomcat-9.0.58/webapps进行了挂载。

  1. 外网进行访问

在这里插入图片描述

4.3 CMD 和 ENTRYPOINT 的区别

我们之前说过,两个命令都是指定一个容器启动时要运行的命令。

CMD:Dockerfile 中可以有多个CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换!
ENTRYPOINT: docker run 之后的参数会被当做参数传递给 ENTRYPOINT,之后形成新的命令组合!

测试:

CMD

  1. 新建一个Dockerfile
[root@jiangnan cmd]# pwd
/home/cmd
[root@jiangnan cmd]# ll
total 4
-rw-r--r-- 1 root root 32 Feb 26 14:53 Dockerfile
[root@jiangnan cmd]# cat Dockerfile 
FROM centos
CMD [ "ls", "-a" ]
[root@jiangnan cmd]# 
  1. 构建镜像
[root@jiangnan cmd]# docker build -f Dockerfile -t cmdtest .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
latest: Pulling from library/centos
a1d0c7532777: Pull complete 
Digest: sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177
Status: Downloaded newer image for centos:latest
 ---> 5d0da3dc9764
Step 2/2 : CMD [ "ls", "-a" ]
 ---> Running in bd1a6bba4aee
Removing intermediate container bd1a6bba4aee
 ---> 29a1a1704d9a
Successfully built 29a1a1704d9a
Successfully tagged cmdtest:latest
[root@jiangnan cmd]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED              SIZE
cmdtest      latest    94e05d54db92   About a minute ago   231MB
tomcat       latest    fb5657adc892   2 months ago         680MB
centos       latest    5d0da3dc9764   5 months ago         231MB
  1. 运行
[root@jiangnan cmd]# docker run 94e05d54db92
.
..
.dockerenv
bin
dev
etc
......
usr
var
[root@jiangnan cmd]# 
  1. 参数传递

当我们运行容器,实际上执行了ls -a的命令,就看到了3中的效果,如果我们想执行的是ls -al该怎么做呢?理论上后面加上参数就可以,比如

[root@jiangnan cmd]# docker run cmd -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
[root@jiangnan cmd]# 

问题:我们可以看到可执行文件找不到的报错,executable file not found。
之前我们说过,跟在镜像名后面的是 command,运行时会替换 CMD 的默认值。
因此这里的 -l 替换了原来的 CMD,而不是添加在原来的 ls -a 后面。而 -l 根本不是命令,所以自然找不到。
那么如果我们希望加入 -l 这参数,我们就必须重新完整的输入这个命令:

[root@jiangnan cmd]# docker run cmd ls -al
total 56
drwxr-xr-x   1 root root 4096 Feb 26 07:06 .
drwxr-xr-x   1 root root 4096 Feb 26 07:06 ..
-rwxr-xr-x   1 root root    0 Feb 26 07:06 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
..........
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var
[root@jiangnan cmd]# 

ENTRYPOINT

  1. 编写Dockerfile
[root@jiangnan entrypoint]# pwd
/home/entrypoint
[root@jiangnan entrypoint]# touch Dockerfile
[root@jiangnan entrypoint]# vim Dockerfile 
[root@jiangnan entrypoint]# cat Dockerfile 
FROM centos
ENTRYPOINT [ "ls", "-a" ]
[root@jiangnan entrypoint]# 
  1. 构建镜像
[root@jiangnan entrypoint]# docker build -f Dockerfile -t entrypoint .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM centos
 ---> 5d0da3dc9764
Step 2/2 : ENTRYPOINT [ "ls", "-a" ]
 ---> Running in 07ae62691ce1
Removing intermediate container 07ae62691ce1
 ---> 7a01d22d4b6b
Successfully built 7a01d22d4b6b
Successfully tagged entrypoint:latest
[root@jiangnan entrypoint]# 
  1. 运行
[root@jiangnan entrypoint]# docker run entrypoint
.
..
.dockerenv
bin
dev
etc
......
tmp
usr
var
[root@jiangnan entrypoint]# 
  1. 参数传递
[root@jiangnan entrypoint]# docker run entrypoint -l
total 56
drwxr-xr-x   1 root root 4096 Feb 26 07:12 .
drwxr-xr-x   1 root root 4096 Feb 26 07:12 ..
-rwxr-xr-x   1 root root    0 Feb 26 07:12 .dockerenv
.......
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var
[root@jiangnan entrypoint]# 

和cmd中的测试一样,我们直接跟了-l,但是cmd报错,而ENTRYPOINT成功了。

在这里插入图片描述

5. 发布镜像(了解)

上面的四步做完,只能算是单机版玩耍,而要实现多个环境使用,需要镜像发布。

我们这里演示将镜像发布到阿里云镜像仓库,首先要开通阿里云账号,创建命名空间和镜像仓库。

在这里插入图片描述

按照步骤做即可。

[root@jiangnan entrypoint]# docker login --username=xxxxxx registry.cn-beijing.aliyuncs.com
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@jiangnan entrypoint]# 

看到Login Succeeded说明登录成功了。

[root@jiangnan entrypoint]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
entrypoint   latest    7a01d22d4b6b   18 minutes ago   231MB
cmdtest      latest    94e05d54db92   30 minutes ago   231MB
tomcat       latest    fb5657adc892   2 months ago     680MB
centos       latest    5d0da3dc9764   5 months ago     231MB
[root@jiangnan entrypoint]# docker tag 7a01d22d4b6b registry.cn-beijing.aliyuncs.com/xxc-study/mybuild:1.0
[root@jiangnan entrypoint]# docker push registry.cn-beijing.aliyuncs.com/xxc-study/mybuild:1.0
The push refers to repository [registry.cn-beijing.aliyuncs.com/xxc-study/mybuild]
74ddd0ec08fa: Pushed 
1.0: digest: sha256:29a034073345d4e389b407042b84d4a6fd2392716a80196ed1d5a44526c67d73 size: 529
[root@jiangnan entrypoint]# 

在这里插入图片描述
在这里插入图片描述

6. 总结

在这里插入图片描述

  1. Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
  2. Dockerfile中记录了镜像制作过程中的每一个详细的步骤。
    在这里插入图片描述
    我的微信公众号先已开通,各位小伙伴们可以关注我,后面文章会进行同步,方便查看哦。
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45842494/article/details/123151006
今日推荐