Docker動手教程3.3:容器鏡像構建2

内容摘要

  1. dockerfile 常用指令
  2. RUN/CMD/ENTRYPOINT区别

Dockerfile 常用指令

前面初步讲解了Dockerfile,这节详细介绍Dockerfile用到的指令和语法。

下面来看一个较为完整的Dockerfile,内容如下:

# dockerfile haha
FROM centos
MAINTAINER [email protected]
WORKDIR /mydir
RUN touch mytext
COPY test .
ADD busybox-1_29_0.tar.gz .
ENV VERSION "1.0.2"
CMD echo "I am cmd"
CMD echo $VERSION
ENTRYPOINT sleep 1000000

先不解释上面命令的意义,运行该文件构建镜像。

在构建镜像前,先在根目录下创建 test 文件夹,在其下面创建Dockerfile,以及准备构建使用的test文件,使用Xftp将busybox的压缩包上传到test目录下。

具体操作见下面操作截图:

Docker动手教程3.3:容器镜像构建2

说明:busybox文件的压缩包自行在github上下载。

构建镜像,命令为:

docker build -t centos-with-busybox .
Docker动手教程3.3:容器镜像构建2

从上面 Step 信息可以看出,构建步骤是按照我们在Dockerfile中的命令先后顺序执行的,最后生成的镜像 SIZE 比基础镜像要多 9M。

运行容器,检查构建是否成功, 命令为:

docker run -d --name centos-with-busybox1 centos-with-busybox
Docker动手教程3.3:容器镜像构建2

进入容器可以看到当前目录为 mydir,而且里面包含 创建的文件以及拷贝进去的文件,busybox压缩包已经被解压。

使用docker history 指令查看刚才构建的镜像:

Docker动手教程3.3:容器镜像构建2

从红框中可以看到 dockerfile 文件中执行的操作步骤。

下面详细解释下 dockerfile 文件用到的命令:

FROM:表示基于什么基础镜像进行构建

MAINTAINER:构建者信息,说明是谁构建的

WORKDIR:指定后续执行步骤的工作目录,比如拷贝文件,创建文件操作在哪个目录下执行

RUN:在容器运行命令,比如创建文件 touch xxx.txt

COPY:拷贝数据,即将主机上的文件拷贝到容器中去

ADD:也是拷贝数据,不同的是,如果被拷贝文件是压缩文件,那么拷贝到容器后会自动解压缩

ENV:指定环境变量,该环境变量可以在Dockerfile文件中使用,同时在容器中也生效

CMD:容器启动时运行的命令

ENTRYPOINT:同CMD相似,但也有区别

RUN/CMD/ENTRYPOINT 区别

从上面可以看出 RUN/CMD/ENTRYPOINT 都可以运行命令,那它们的区别是什么呢?

RUN 和 CMD/ENTRYPOINT的区别比较清楚:RUN主要用于在容器安装软件,操作文件和文件夹等,CMD/ENTRYPOINT主要用于启动容器,但是有很大的差别。

下面通过实验逐步分析二者之不同:

修改 Dockerfile 文件,内容如下:

# dockerfile haha
FROM centos
MAINTAINER [email protected]
WORKDIR /mydir
RUN touch mytext
COPY test .
ADD busybox-1_29_0.tar.gz .
ENV VERSION "1.0.2"
CMD echo "I am cmd"
CMD echo $VERSION

按照上面步骤重新构建镜像并运行,命令为:

docker run -it --name centos-with-busybox centos-with-busybox
Docker动手教程3.3:容器镜像构建2

镜像构建就不展示截图,镜像名为:centos-with-busybox,创建的容器也使用这个名字。

可以看到容器运行结果为环境变量VERSION的版本信息,但是倒数第二行的CMD命令没有输出,说明只有最后一个CMD命令生效。

下面换个方式运行容器,在 docker run 后面指定运行参数:

命令为:

docker run -it --name centos-with-busybox centos-with-busybox /bin/bash
Docker动手教程3.3:容器镜像构建2

指定 /bin/bash 作为启动参数,发现没有输出环境变量VERSION的版本信息,说明CMD命令被 /bin/bash 取代了。

那么ENTRYPOINT会如何表现呢?

修改Dockerfile,内容如下:

# dockerfile haha
FROM centos
MAINTAINER [email protected]
WORKDIR /mydir
RUN touch mytext
COPY test .
ADD busybox-1_29_0.tar.gz .
ENV VERSION "1.0.2"
CMD echo "I am cmd"
CMD echo $VERSION
ENTRYPOINT echo "I am entrypoint"

先不加参数运行容器,命令为:

docker run -it --name centos-with-busybox centos-with-busybox
Docker动手教程3.3:容器镜像构建2

可见打印信息和Dockerfile中规定的字符串一致。

带上参数运行:

docker run -it --name centos-with-busybox centos-with-busybox /bin/bash
Docker动手教程3.3:容器镜像构建2

和上面一致,仍旧打印出一样的字符串。

对于ENTRYPOINT而言,无论 docker run 是否带有执行命令,都会执行,而CMD则相反。

问题:如果先后出现两个ENTRYPOINT命令,那么先出现的会执行吗?

修改Dockerfile,内容如下:

# dockerfile haha
FROM centos
MAINTAINER [email protected]
WORKDIR /mydir
RUN touch mytext
COPY test .
ADD busybox-1_29_0.tar.gz .
ENV VERSION "1.0.2"
CMD echo "I am cmd"
CMD echo $VERSION
ENTRYPOINT echo "I am entrypoint 1"
ENTRYPOINT echo "I am entrypoint 2"

构建镜像,并启动容器,命令为:

docker run -it --name centos-with-busybox centos-with-busybox
Docker动手教程3.3:容器镜像构建2

只运行了第二个ENTRYPOINT指令,第一个被忽略。

在这点上,ENTRYPOINT和CMD一样,即如果有多条该命令,只会执行最后一条。

CMD和ENTRYPOINT的区别决定了二者使用上不同:

1、由于CMD命令可以被docker run的命令替换,因此它可以用来设置默认启动命令,如果用户不想使用默认命令,就可以在docker run指令中指定自己的容器启动命令;

2、ENTRYPOINT 是必须执行的命令,所以往往用来启动应用程序或者服务,设置容器启动命令最好使用ENTRYPOINT,不要使用CMD。

3、ENTRYPOINT可以和CMD结合起来使用,充分结合二者的优点,可以使容器启动更加方便。

下面显示下如何结合使用ENTRYPOINT和CMD两个命令:

修改Dockerfile,内容如下:

FROM centos
MAINTAINER [email protected]
WORKDIR /mydir
RUN touch mytext
COPY test .
ADD busybox-1_29_0.tar.gz .
ENV VERSION "1.0.2"
ENTRYPOINT ["echo","I am"] 
CMD ["entrypoint1"]

构建镜像并运行,命令为:

docker run -it centos-with-busybox
Docker动手教程3.3:容器镜像构建2

输出内容为: I am entrypoint1

带命令执行docker run,命令为:

docker run -it centos-with-busybox entrypoint2 
Docker动手教程3.3:容器镜像构建2

输出内容为: I am entrypoint2

容器启动携带的参数entrypoint2,覆盖了entrypoint1。

对比两种运行方式,可以看到二者输出不同。

ENTRYPOINT命令是静态的,CMD命令可以动态变更,上面将二者结合起来了。

因此在启动容器时:不变部分使用ENTRYPOINT执行命令,可变部分使用CMD,用户在运行容器时给出参数取代CMD命令。从而做到动静结合,容器运行更加灵活,更容易控制。

实验

使用dockerfile命令构建一个镜像


分享到:


相關文章: