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)上面执行后会显示出详细的构建过程。
3,使用镜像
(1)下面我们使用 docker run 命令运行我们构建的自定义镜像:
1 | docker run -it -d -p 80:80 hangge_server |
(2)运行后我们使用浏览器访问,可以看到这个 index.html 确实已经包含在这个镜像中。
二、设置镜像的 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 . |
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 |
(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 是归档文件(tar、zip、tgz、xz 等),文件会被自动解压到 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
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 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