Docker - 镜像构建教程2(使用Dockerfile构建镜像)

作者: hangge 发布时间: 2019-09-06 浏览: 653 次 编辑

    Docker 提供了两种构建镜像的方法:docker commit 命令与 Dockerfile 构建文件。日常使用中推荐通过后者(Dockerfile)来构建镜像,下面通过样例进行演示。

一、使用 Dockerfile 构建镜像样例

1,创建一个 Dockerfile 文件

(1)Dockerfile 其实是一个文本文件,记录了镜像构建的所有步骤。我们可以通过 vi 命令创建它。

1
vi Dockerfile


(2)Dockerfile 里的内容如下:

  • 第一行:执行 FROM,将 Apache Server 作为 base 镜像。

  • 第二行:执行 COPY,将 index.html 这个文件复制到镜像里的 /usr/local/apache2/htdocs/ 目录下。

1
2
FROM httpd
COPY index.html /usr/local/apache2/htdocs/


(3)根据前面定义的构建步骤,需要将一个外部文件复制到镜像中。所有我们在同级目录下创建一个 index.html 文件,内容如下:

1
欢迎访问 hangge.com


2,构建镜像

(1)运行 docker build 命令开始构建镜像:

参数说明:

  • -t 表示将新镜像命名为 hangge_server

  • 末尾的 指明 build context 为当前目录

  • Docker 默认会从 build context 中查找 Dockerfile 文件,我们也可以通过 -f 参数指定 Dockerfile 的位置。

1
docker build -t hangge_server .


(2)上面执行后会显示出详细的构建过程。

原文:Docker - 镜像构建教程2(使用Dockerfile构建镜像)


3,使用镜像

(1)下面我们使用 docker run 命令运行我们构建的自定义镜像:

1
docker run -it -d -p 80:80  hangge_server


(2)运行后我们使用浏览器访问,可以看到这个 index.html 确实已经包含在这个镜像中。

原文:Docker - 镜像构建教程2(使用Dockerfile构建镜像)

二、设置镜像的 tag

当我们执行 docker build 命令制作镜像时,使用 -t 参数为镜像取个名字。实际上一个特定镜像的名字由两部分组成:repository 和 tag。其中 tag 常用于描述镜像的版本信息。

1,不手动设置 tag

(1)上面样例中我们没有特别指定 tag

1
docker build -t hangge_server .


(2)那么就会默认使用 latest,即上面效果相当于:

1
docker build -t hangge_server:latest .

原文:Docker - 镜像构建教程2(使用Dockerfile构建镜像)


2,创建时指定 tag

(1)tag 常用于描述镜像的版本信息:

1
docker build -t hangge_server:2.4 .


(2)当然 tag 也可以是任意字符串:

1
docker build -t hangge_server:trusty .


3,给已有的镜像打 tag

(1)我们可以通过 docker tag 命令方便地给现有的镜像打 tag,比如下面将 latest 打上 3.1.0 的 tag

1
docker tag hangge_server hangge_server:3.1.0

原文:Docker - 镜像构建教程2(使用Dockerfile构建镜像)


(2)又比如下面将 latest 移到 4.1.0

1
docker tag hangge_server:4.1.0 hangge_server:latest


三、Dockerfile 常用指令

1,FROM

用于指定基础镜像。如果不以任何镜像为基础,那么写法为:FROM scratch

2,MAINAINER

设置镜像的作者,可以是任意字符串。

3,COPY 

将文件从 build context 复制到镜像。COPY 支持如下两种形式:

  • COPY src dest

  • COPY ["src", "dest"]

注意src 只能指定 build context 中的文件或目录。

4,ADD

与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tarziptgzxz 等),文件会被自动解压到 dest

5,ENV

设置环境变量,环境变量可被后面的指令使用。下面是一个设置和使用的样例:

1
2
ENV MY_VERSION 1.3
RUN apt-get install -y mypackage=$MY_VERSION


6,EXPOSE

指定容器中的进程会监听某个端口,Docker 可以将该端口暴露出来。

1
EXPOSE 8081 8082


7,VOLUME

    用于指定持久化目录,实现挂载功能,授权访问从容器内到主机上的目录。用于 containers 之间共享数据,将本地文件夹或者其他容器中的文件夹挂在到这个容器中等。具体用法可以参考我之前写的一篇文章:

8,WORKDIR

为后面的 RUNCMDENTRYPOINTADD 或 COPY 指令设置镜像中的当前工作目录。

1
WORKDIR /root


9,RUN

(1)RUN 指令将在当前镜像基础上执行指定命令(即在最顶部执行命令),并提交为新的镜像,也就是多少个 RUN 就构建了多少层镜像。

(2)RUN 指令通常用于安装应用和软件包。下面是使用 RUN 安装多个包的例子:

1
2
3
4
5
6
RUN apt-get update && apt-get install -y \ 
 bzr \
 cvs \
 git \
 mercurial \
 subversion


10,CMD

(1)CMD 是构建容器后调用,也就是在容器启动时才进行调用。

注意Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效。

(2)CMD 指令允许用户指定容器的默认执行的命令,CMD 命令会在容器启动且 docker run 没有指定其他命令时运行。 

  • 比如下面镜像构建以后,使用 docker run -it [image] 运行容器将会输出:Hello world

1
CMD echo "Hello world"


(3)如果 docker run 后面带上其它参数,那么 CMD 会被忽略掉。

  • 比如我们使用 docker run -it [image] /bin/bash 运行容器命令 bash 将被执行,而 Hello world 则不会输出。


11,ENTRYPOINT

(1)ENTRYPOINT 和 CMD 很像:

  • 只能写一条,如果写了多条,那么只有最后一条生效

  • 它们的运行时机相同,都是容器启动时才运行

(2)ENTRYPOINT 与 CMD 不同的地方在于 ENTRYPOINT 不会被忽略,一定会被执行,即使运行 dokcer run 时指定了其它命令。

(3)如果我们在 Dockerfile 中同时写了 ENTRYPOINT 和 CMD,并且 CMD 指令不是一个完整的可执行命令,那么 CMD 指定的内容将会作为 ENTRYPOINT 的参数。

1
2
3
FROM ubuntu
ENTRYPOINT ["top""-b"]
CMD ["-c"]


(4)如果我们在 Dockerfile 种同时写了 ENTRYPOINT 和 CMD,并且 CMD 是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效。

    比如下面 ls -al 将会执行,top -b 则不会执行

1
2
3
FROM ubuntu
ENTRYPOINT ["top""-b"]
CMD ls -al


原文链接:https://www.hangge.com/blog/cache/detail_2407.html