22
33<!-- TOC depthFrom:2 depthTo:3 -->
44
5- - [ Dockerfile 指令] ( #dockerfile -指令 )
6- - [ FROM(指定基础镜像)] ( #from指定基础镜像 )
7- - [ RUN(执行命令)] ( #run执行命令 )
8- - [ COPY(复制文件)] ( #copy复制文件 )
9- - [ ADD(更高级的复制文件)] ( #add更高级的复制文件 )
10- - [ CMD(容器启动命令)] ( #cmd容器启动命令 )
11- - [ ENTRYPOINT(入口点)] ( #entrypoint入口点 )
12- - [ ENV(设置环境变量)] ( #env设置环境变量 )
13- - [ ARG(构建参数)] ( #arg构建参数 )
14- - [ VOLUME(定义匿名卷)] ( #volume定义匿名卷 )
15- - [ EXPOSE(暴露端口)] ( #expose暴露端口 )
16- - [ WORKDIR(指定工作目录)] ( #workdir指定工作目录 )
17- - [ USER(指定当前用户)] ( #user指定当前用户 )
18- - [ HEALTHCHECK(健康检查)] ( #healthcheck健康检查 )
19- - [ ONBUILD(为他人作嫁衣裳)] ( #onbuild为他人作嫁衣裳 )
20- - [ 引用和引申 ] ( #引用和引申 )
5+ - [ 一、 Dockerfile 指令] ( #一dockerfile -指令 )
6+ - [ FROM(指定基础镜像)] ( #from指定基础镜像 )
7+ - [ RUN(执行命令)] ( #run执行命令 )
8+ - [ COPY(复制文件)] ( #copy复制文件 )
9+ - [ ADD(更高级的复制文件)] ( #add更高级的复制文件 )
10+ - [ CMD(容器启动命令)] ( #cmd容器启动命令 )
11+ - [ ENTRYPOINT(入口点)] ( #entrypoint入口点 )
12+ - [ ENV(设置环境变量)] ( #env设置环境变量 )
13+ - [ ARG(构建参数)] ( #arg构建参数 )
14+ - [ VOLUME(定义匿名卷)] ( #volume定义匿名卷 )
15+ - [ EXPOSE(暴露端口)] ( #expose暴露端口 )
16+ - [ WORKDIR(指定工作目录)] ( #workdir指定工作目录 )
17+ - [ USER(指定当前用户)] ( #user指定当前用户 )
18+ - [ HEALTHCHECK(健康检查)] ( #healthcheck健康检查 )
19+ - [ ONBUILD(为他人作嫁衣裳)] ( #onbuild为他人作嫁衣裳 )
20+ - [ 参考资料 ] ( #参考资料 )
2121
2222<!-- /TOC -->
2323
24- ## Dockerfile 指令
24+ ## 一、 Dockerfile 指令
2525
2626### FROM(指定基础镜像)
2727
2828> 作用:** ` FROM ` 指令用于指定基础镜像** 。
29- >
3029
3130所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。就像我们之前运行了一个 ` nginx ` 镜像的容器,再进行修改一样,基础镜像是必须指定的。而 ` FROM ` 就是指定** 基础镜像** ,因此一个 ` Dockerfile ` 中 ` FROM ` 是必备的指令,并且必须是第一条指令。
3231
@@ -56,7 +55,6 @@ FROM scratch
5655> ```
5756>
5857> - _exec_ 格式:`RUN ["可执行文件" , "参数1" , "参数2" ]`,这更像是函数调用中的格式。
59- >
6058
6159既然 `RUN` 就像 Shell 脚本一样可以执行命令,那么我们是否就可以像 Shell 脚本一样把每个命令对应一个 RUN 呢?比如这样:
6260
@@ -107,8 +105,6 @@ RUN buildDeps='gcc libc6-dev make' \
107105
108106### COPY(复制文件)
109107
110- > 作用:
111- >
112108> ** ` COPY ` 指令将从构建上下文目录中 ` <源路径> ` 的文件/目录复制到新的一层的镜像内的 ` <目标路径> ` 位置。**
113109
114110格式:
@@ -144,8 +140,6 @@ COPY --chown=10:11 files* /mydir/
144140
145141### ADD(更高级的复制文件)
146142
147- > 作用:
148- >
149143> ` ADD ` 指令和 ` COPY ` 的格式和性质基本一致。但是在 ` COPY ` 基础上增加了一些功能。
150144>
151145> 比如 ` <源路径> ` 可以是一个 ` URL ` ,这种情况下,Docker 引擎会试图去下载这个链接的文件放到 ` <目标路径> ` 去。下载后的文件权限自动设置为 ` 600 ` ,如果这并不是想要的权限,那么还需要增加额外的一层 ` RUN ` 进行权限调整,另外,如果下载的是个压缩包,需要解压缩,也一样还需要额外的一层 ` RUN ` 指令进行解压缩。所以不如直接使用 ` RUN ` 指令,然后使用 ` wget ` 或者 ` curl ` 工具下载,处理权限、解压缩、然后清理无用文件更合理。因此,这个功能其实并不实用,而且不推荐使用。
@@ -179,8 +173,6 @@ ADD --chown=10:11 files* /mydir/
179173
180174### CMD(容器启动命令)
181175
182- > 作用:
183- >
184176> 之前介绍容器的时候曾经说过,Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。` CMD ` 指令就是用于指定默认的容器主进程的启动命令的。
185177
186178` CMD ` 指令的格式和 ` RUN ` 相似,也是两种格式:
@@ -356,7 +348,7 @@ uid=0(root) gid=0(root) groups=0(root)
356348
357349### ENV(设置环境变量)
358350
359- > 作用: ` ENV ` 指令用于设置环境变量。无论是后面的其它指令,如 ` RUN ` ,还是运行时的应用,都可以直接使用这里定义的环境变量。
351+ > ` ENV ` 指令用于设置环境变量。无论是后面的其它指令,如 ` RUN ` ,还是运行时的应用,都可以直接使用这里定义的环境变量。
360352
361353格式:
362354
@@ -396,8 +388,6 @@ RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-
396388
397389### ARG(构建参数)
398390
399- > 作用:
400- >
401391> ` Dockerfile ` 中的 ` ARG ` 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 ` docker build ` 中用 ` --build-arg <参数名>=<值> ` 来覆盖。
402392>
403393> 构建参数和 ` ENV ` 的效果一样,都是设置环境变量。所不同的是,` ARG ` 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ` ARG ` 保存密码之类的信息,因为 ` docker history ` 还是可以看到所有值的。
@@ -429,8 +419,6 @@ docker run -d -v mydata:/data xxxx
429419
430420### EXPOSE(暴露端口)
431421
432- > 作用:
433- >
434422> ` EXPOSE ` 指令是声明运行时容器提供服务端口,这只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;另一个用处则是在运行时使用随机端口映射时,也就是 ` docker run -P ` 时,会自动随机映射 ` EXPOSE ` 的端口。
435423>
436424> 要将 ` EXPOSE ` 和在运行时使用 ` -p <宿主端口>:<容器端口> ` 区分开来。` -p ` ,是映射宿主端口和容器端口,换句话说,就是将容器的对应端口服务公开给外界访问,而 ` EXPOSE ` 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射。
@@ -439,8 +427,6 @@ docker run -d -v mydata:/data xxxx
439427
440428### WORKDIR(指定工作目录)
441429
442- > 作用:
443- >
444430> 使用 ` WORKDIR ` 指令可以来指定工作目录(或者称为当前目录),以后各层的当前目录就被改为指定的目录,如该目录不存在,` WORKDIR ` 会帮你建立目录。
445431
446432格式:` WORKDIR <工作目录路径> ` 。
@@ -460,10 +446,41 @@ RUN echo "hello" > world.txt
460446
461447因此如果需要改变以后各层的工作目录的位置,那么应该使用 ` WORKDIR ` 指令。
462448
449+ ### LABEL
450+
451+ ` LABEL ` 用于为镜像添加元数据,元数以键值对的形式指定:
452+
453+ ```
454+ LABEL <key>=<value> <key>=<value> <key>=<value> ...
455+ ```
456+
457+ 使用` LABEL ` 指定元数据时,一条` LABEL ` 指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔。推荐将所有的元数据通过一条` LABEL ` 指令指定,以免生成过多的中间镜像。
458+
459+ 如,通过` LABEL ` 指定一些元数据:
460+
461+ ```
462+ LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
463+ ```
464+
465+ 指定后可以通过` docker inspect ` 查看:
466+
467+ ```
468+ $sudo docker inspect itbilu/test
469+ "Labels": {
470+ "version": "1.0",
471+ "description": "这是一个Web服务器",
472+ "by": "IT笔录"
473+ },
474+ ```
475+
476+ * 注意;* ` Dockerfile ` 中还有个` MAINTAINER ` 命令,该命令用于指定镜像作者。但` MAINTAINER ` 并不推荐使用,更推荐使用` LABEL ` 来指定镜像作者。如:
477+
478+ ```
479+ LABEL maintainer="itbilu.com"
480+ ```
481+
463482### USER(指定当前用户)
464483
465- > 作用:
466- >
467484> ` USER ` 指令和 ` WORKDIR ` 相似,都是改变环境状态并影响以后的层。` WORKDIR ` 是改变工作目录,` USER ` 则是改变之后层的执行 ` RUN ` , ` CMD ` 以及 ` ENTRYPOINT ` 这类命令的身份。
468485>
469486> 当然,和 ` WORKDIR ` 一样,` USER ` 只是帮助你切换到指定用户而已,这个用户必须是事先建立好的,否则无法切换。
@@ -597,7 +614,7 @@ CMD [ "npm", "start" ]
597614
598615把这个 ` Dockerfile ` 放到 Node.js 项目的根目录,构建好镜像后,就可以直接拿来启动容器运行。但是如果我们还有第二个 Node.js 项目也差不多呢?好吧,那就再把这个 ` Dockerfile ` 复制到第二个项目里。那如果有第三个项目呢?再复制么?文件的副本越多,版本控制就越困难,让我们继续看这样的场景维护的问题。
599616
600- 如果第一个 Node.js 项目在开发过程中,发现这个 ` Dockerfile ` 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 ` Dockerfile ` ,再次构建,问题解决。� 第一个项目没问题了,但是第二个项目呢?虽然最初 ` Dockerfile ` 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 ` Dockerfile ` ,而第二个项目的 ` Dockerfile ` 就会被自动修复。
617+ 如果第一个 Node.js 项目在开发过程中,发现这个 ` Dockerfile ` 里存在问题,比如敲错字了、或者需要安装额外的包,然后开发人员修复了这个 ` Dockerfile ` ,再次构建,问题解决。第一个项目没问题了,但是第二个项目呢?虽然最初 ` Dockerfile ` 是复制、粘贴自第一个项目的,但是并不会因为第一个项目修复了他们的 ` Dockerfile ` ,而第二个项目的 ` Dockerfile ` 就会被自动修复。
601618
602619那么我们可不可以做一个基础镜像,然后各个项目使用这个基础镜像呢?这样基础镜像更新,各个项目不用同步 ` Dockerfile ` 的变化,重新构建后就继承了基础镜像的更新?好吧,可以,让我们看看这样的结果。那么上面的这个 ` Dockerfile ` 就会变为:
603620
0 commit comments