为何要写这一篇呢?其实在之前的文章docker 学习笔记中没有展开讲,我们都知道使用docker build
命令或使用Docker Hub的自动构建功能构建Docker镜像时,都需要一个Dockerfile文件。Dockerfile文件是一个由一系列构建指令组成的文本文件,docker build
命令会根据这些构建指令完成Docker镜像的构建。
目录
1. FROM
2. RUN
3. CMD
4. ENTRYPOINT
5. LABEL
6. EXPOSE
7. ENV
8. ADD
9. COPY
10. VOLUME
11. USER
12. WORKDIR
13. ARG
14. ONBUILD
15. STOPSIGNAL
16. SHELL
构建上下文
docker build
命令会根据Dockerfile文件及上下文构建新Docker镜像。
构建上下文是指Dockerfile所在的本地路径或一个URL
(Git
仓库地址)。构建上下文环境会被递归处理,所以,构建所指定的路径还包括了子目录,而URL
还包括了其中指定的子模块。
构建镜像的运行环境
构建会在Docker后台守护进程(daemon)中执行,而不是CLI
中。
构建前,构建进程会将全部内容(递归)发送到守护进程。大多情况下,应该将一个空目录作为构建上下文环境,并将Dockerfile文件放在该目录下。
在构建上下文中使用的Dockerfile文件,是一个构建指令文件。为了提高构建性能,可以通过.dockerignore
文件排除上下文目录下,不需要的文件和目录。
后台守护进程首先会对Dockerfile进行语法检查,有语法错误时会返回,通过后才会执行!
缓存
Docker 守护进程会一条一条的执行Dockerfile中的指令,而且会在每一步提交并生成一个新镜像,最后会输出最终镜像的ID。生成完成后,Docker 守护进程会自动清理你发送的上下文。
Dockerfile文件中的每条指令会被独立执行,并会创建一个新镜像,RUN cd /tmp
等命令不会对下条指令产生影响。Docker 会重用已生成的中间镜像,以加速docker build
的构建速度。
构建缓存仅会使用本地父生成链上的镜像。如果不想使用本地缓存的镜像,也可以通过--cache-from
指定缓存。指定后将再不使用本地生成的镜像链,而是从镜像仓库中下载。
以下是一个使用了缓存镜像的执行过程(Using cache):
$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1/4 : FROM alpine:3.2
---> 31f630c65071
Step 2/4 : MAINTAINER [email protected]
---> Using cache
---> 2a1c91448f5f
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
---> Using cache
---> 21ed6e7fbb73
Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
---> Using cache
---> 7ea8aef582cc
Successfully built 7ea8aef582cc
Dockerfile文件格式
FROM
,FROM
指令用于指定一个基础镜像#
开头的行,Docker会认为是注释。但#
出现在指令参数中时,则不是注释。# 注释
指令 参数# Comment
RUN echo 'we are running some # of cool things'
下面将开始介绍本文的重点内容,Dockerfile中使用指令。
FROM
指令用于指定其后构建新镜像所使用的基础镜像。FROM
指令必是Dockerfile文件中的首条命令,启动构建流程后,Docker将会基于该镜像构建新镜像,FROM
后的命令也会基于这个基础镜像。
FROM
FROM:
FROM:
tag
或digest
是可选的,如果不使用这两个值时,会使用latest
版本的基础镜像
RUN
用于在镜像容器中执行命令,RUN
指令创建的中间镜像会被缓存,并会在下次构建中使用。其有以下两种命令执行方式:
shell
执行,在这种方式会在shell
中执行命令,Linux下默认使用/bin/sh -c
,Windows下使用cmd /S /C
。格式:RUN exec
执行,格式:RUN ["executable", "param1", "param2"]也可以在同一行中,通过分号分隔命令:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
CMD
用于指定在容器启动时所要执行的命令。CMD
在Dockerfile文件中仅可指定一次,指定多次时,会覆盖前的指令。
另外,如果docker run
运行容器时,使用了Dockerfile中CMD
相同的命令,就会覆盖Dockerfile中的CMD
命令。比如:Dockerfile文件中使用CMD ["/bin/bash"],运行时指令$sudo docker run -i -t itbilu/test 就会发生覆盖。
如果不想使用CMD
中指定的命令,就可以在docker run
命令的结尾指定所要运行的命令:$sudo docker run -i -t itbilu/test /bin/ps,这时,docker run
结尾指定的/bin/ps
命令覆盖了Dockerfile的CMD
中指定的命令。
CMD
有以下三种格式:
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
CMD和RUN
CMD
用于指定在容器启动时所要执行的命令,而RUN
用于指定镜像构建时所要执行的命令。但功能实现上也有相似之处:
docker run -t -i itbilu/static_web_server /bin/true
等价于:
cmd ["/bin/true"]
ENTRYPOINT
用于给容器配置一个可执行程序。Dockerfile中只允许有一个ENTRYPOINT
命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT
指令。也就是说,每次使用镜像创建容器时,通过ENTRYPOINT
指定的程序都会被设置为默认程序。ENTRYPOINT
有以下两种形式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
ENTRYPOINT
与CMD
非常类似,不同的是通过docker run
执行的命令不会覆盖ENTRYPOINT
,而docker run
命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT
。docker run
运行容器时指定的参数都会被传递给ENTRYPOINT
,且会覆盖CMD
命令指定的参数。如,执行docker run
时,-d
参数将被传递给入口点。也可以通过docker run --entrypoint
重写ENTRYPOINT
入口点。比如:Dockerfile中有ENTRYPOINT ["/usr/bin/nginx"],运行时$sudo docker run -i -t itbilu/test -g "daemon off;",最终在容器中执行的命令为/usr/sbin/nginx -g "daemon off;"。
LABEL
用于为镜像添加元数据,元数以键值对的形式指定,一条LABEL
指定可以指定一或多条元数据,指定多条元数据时不同元数据之间通过空格分隔:LABEL version="1.0" description="这是一个Web服务器" by="IT笔录"
推荐将所有的元数据通过一条LABEL
指令指定,以免生成过多的中间镜像。
注:Dockerfile中还有个MAINTAINER
命令,该命令用于指定镜像作者。但MAINTAINER
并不推荐使用,更推荐使用LABEL
来指定镜像作者。如:LABEL maintainer="itbilu.com"
EXPOSE
用于指定容器在运行时监听的端口:EXPOSE EXPOSE
并不会让容器的端口访问到主机。要使其可访问,需要在docker run
运行容器时通过-p
来发布这些端口,或通过-P
参数来发布EXPOSE
导出的所有端口。
ENV
用于设置环境变量,其有以下两种设置形式:
ENV
ENV
这些环境变量不仅可以构建镜像过程(在ENV
命令之后)使用,使用该镜像创建的容器中也可以使用。
ENV ITBILU_PATH /home/itbilu/
WORKERDIR $ITBILU_PATH
$ docker run -i -t itbilu/test
root@196ca123c0c3:/# cd $ITBILU_PATH
root@196ca123c0c3:/home/itbilu#
ADD
用于复制构建环境中的文件或目录到镜像中。URL
,但不能访问构建上下文之外的文件或目录,
来指定目标位置。其有以下两种使用方式:
ADD
ADD ["
ADD http://wordpress.org/latest.zip $ITBILU_PATH,$ITBILU_PATH
是我们使用ENV
指定的一个环境变量。
COPY
同样用于复制构建环境中的文件或目录到镜像中。COPY
指令非常类似于ADD
,不同点在于COPY
只会复制构建目录下的文件,不能使用URL
也不会进行解压操作。其有以下两种使用方式:
COPY
COPY ["
VOLUME
用于创建挂载点,即向基于所构建镜像创始的容器添加卷:VOLUME ["/data"]。一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
VOLUME
让我们可以将源代码、数据或其它内容添加到镜像中,而又不并提交到镜像中,并使我们可以多个容器间共享这些内容。运行容器时,需-v
参将能本地目录绑定到容器的卷(挂载点)上,以使容器可以访问宿主机的数据。
ENV ITBILU_PATH /home/itbilu/
VOLUME [$ITBILU_PATH]
$ sudo docker run -i -t -v ~/code/itbilu:/home/itbilu/ itbilu/test
root@31b0fac536c4:/# cd /home/itbilu/
root@31b0fac536c4:/home/itbilu# ls
USER
用于指定运行镜像所使用的用户,用户可以使用用户名、UID
或GID
,或是两者的组合。
使用USER
指定用户后,Dockerfile中其后的命令RUN
、CMD
、ENTRYPOINT
都将使用该用户。镜像构建完成后,通过docker run
运行容器时,可以通过-u
参数来覆盖所指定的用户。
USER user
USER user:group
USER uid
USER uid:gid
USER user:gid
USER uid:group
WORKDIR
用于在容器内设置一个工作目录,通过WORKDIR
设置工作目录后,Dockerfile中其后的命令RUN
、CMD
、ENTRYPOINT
、ADD
、COPY
等命令都会在该目录下执行。在使用docker run
运行容器时,可以通过-w
参数覆盖构建时所设置的工作目录。
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
pwd
最终将会在/a/b/c
目录中执行
ARG
用于指定传递给构建运行时的变量,
ARG site
ARG build_user=IT笔录
$sudo docker build --build-arg site=itiblu.com -t itbilu/test .
以上我们指定了site
和build_user
两个变量,其中build_user
指定了默认值。在使用docker build
构建镜像时,可以通过--build-arg
参数来指定或重设置这些变量的值
ONBUILD
用于设置镜像触发器,当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发。
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
STOPSIGNAL
用于设置停止容器所要发送的系统调用信号:STOPSIGNAL signal。所使用的信号必须是内核系统调用表中的合法的值,如:9
、SIGKILL
。
SHELL
用于设置执行命令(shell
式)所使用的的默认shell
类型:SHELL ["executable", "parameters"]。SHELL
在Windows环境下比较有用,Windows下通常会有cmd
和powershell
两种shell
,可能还会有sh
。这时就可以通过SHELL
来指定所使用的shell
类型:
FROM microsoft/windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello
总结
Dockerfile是由一系列命令
和参数
组成的一个文件。其中,每条件命令都要大写(如:FROM
),且其后都要跟一个参数(如:ubuntu:16.04
)。构建镜像时,Dockerfile中的命令会按顺序从上到下执行,在编写Dockerfile文件时应注意各条命令的顺序安排。Dockerfile
文件中的每条命令,都会创建一个新的镜像层并会提交镜像。