Dockerfile可以用来自动构建镜像,极大方便了环境构建,如果熟悉前端的同学可以把它抽象为webpack,fis构建工具.那么Dockerfile只是一个配置文件里边包含了许多已经定义好的执行指令.
Docker build
构建命令如下:
sudo docker build -t test -f /test/Dockerfile /test/
指令的格式
#comment
INSTRUCTION arguments
.dockerignore
屏蔽规则:
*
匹配任意字符, !
包含该文件
例子:屏蔽md文件但是不屏蔽LICENCE.md
./*.md
!LICENCE.md
指令集合
第一个必须的指令FROM
FROM 作为第一个必须的指令,需要指明构建的基础镜像.
FROM image
#或者
FROM image:tag
CMD,RUN与ENTRYPOINT指令
RUN
RUN 指令将会执行任意的命令在当前镜像之上会构建新的一层,并提交构建结果.
每次执行RUN命令都会生成一个提交,因此尽量确保RUN指令可以合并的尽量进行合并.
格式如下:
RUN ["executable", "param1", "param2"] #exec模式(首推的)
RUN <command> #shell模式:command可以直接是/bin/bash XX
示例:
FROM ubuntu
RUN echo "This is a test."
RUN ["/bin/bash", "echo ", "This is test"]
CMD
CMD主要是未执行的容器运行时提供一个默认运行的命令.可以配合ENTRYPOINT指令,为其提供参数.
格式
CMD ["executable","param1","param2"] #EXECFORM
CMD ["param1","param2"] #为ENTRYPOINT提供参数
CMD command param1 param2 #(shell模式)
示例:
FROM ubuntu
CMD echo "This is a test."
CMD ["/bin/bash", "echo ", "This is test"]
ENTRyPOINT
在容器运行时提供命令
格式:
ENTRYPOINT command param1 param2
ENTRYPOINT ["executable", "param1", "param2"]
示例:
FROM ubuntu
CMD echo "This is a test."
CMD ["This is test"]
注意事项
- 在shell模式下解析需要注意
$HOST
变量的替换.例如:CMD [ "echo", "$HOME" ]
不会被正确解析,但是CMD [ "sh", "-c", "echo", "$HOME" ]
这样就会正确解析变量,加入sh
会正确处理. - CMD与ENTRYPOINT一起使用时,必须为exec模式
三者之间的差别
CMD:在容器运行时执行,并且可以为ENTRYPOINT提供参数,只可以执行一次,如果Dockerfile多次出现CMD会执行最后一个CMD指令.当命令行出现参数时,只有CMD命令会被替换掉.例:
CMD echo "Hello world"
,命令行执行docker run -it <image> /bin/bash
.RUN:在构建时执行,可以多次执行但每次会构建一个镜像层,构建太多的层会影响效率.
ENTRYPOINT:官方文档说是为了配置docker容器,其实也是运行一个命令,但是不会被命令行当中的参数替换.如果需要构建容器后必须执行这条命令且不会被覆盖,那么可以使用ENTRPOINT.
LABEL
可以用LABEL指令添加为镜像源信息.没添加一个LABEL会为镜像添加一个新的层,因此不推荐使用太多LABEL.
LABEL <key>=<value> <key>=<value> <key>=<value> ...
ENV
ENV定义一些系统级别的变量,需要注意这个是持久存储的.
格式
ENV <key>=<value> ...
MAINTAINER
MAINtAINER指定镜像的维护的作者.
MAINTAINER CoderLiu
EXPOSE
这个命令只是制定了那个端口会被容器监听,不会指定主机的端口映射,以及哪个端口被暴露到主机
格式:
EXPOSE <port> [<port>...]
ADD与COPY
ADD和COPY指令都可以讲当前构建的环境当中的目录或文件COPY到镜像当中去.
Dockerfile最佳实践文章指出:推荐使用COPY命令,它得执行可能更符合预期.
格式分别如下:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
示例:
ADD ~/www/test/* /test
COPY ["/test*", "/test/"]
ADD与COPY差别
- ADD支持src为URL
- ADD 操作
<src>
如果是tar包,会被自动解压到src
目录当中.
VOLUME
指定容器的挂载点可以直接挂载到容器的目录当中.
格式:
VOLUME ["/data"]
USER
USER指令设置运行镜像时的用户并且会让RUN,CMD与ENTRYPOINT执行都会使用该用户.
格式
USER test
WORKDIR
WORKDIR可以用于切换当前工作目录,RUN, CMD, ENTRYPOINT, COPY, ADD会根据这个命令操作的最终目录下,执行操作.
WORKDIR可以进行多次切换目录的操作.
格式:
WORKDIR /path/to/dir
WORKDIR /test
RUN pwd #输出/test
ONBUILD
ONBUILD指令是为了提供一个更好的构建方式,使用ONBUILD修饰的指令在构建基础镜像时不会被执行,但是在构建子镜像时候才会被执行,也就是在子镜像FROM
引用父镜像后才会被执行.
格式
ONBUILD INSTRUCTION
示例:
基础镜像名称为testbase:
FROM ubuntu
ONBUILD COPY . /usr/src/app
ONBUILD RUN /usr/src/app/mybuild.sh
子镜像:
FROM testbase
#这时候ONBUILD才会被执行
构建注意事项
- 构建镜像时,最好在一个空的目录或者只包含了必须文件,构建目录下需要包含
Dockerfile
文件.构建完成吼我们可以将镜像推送到Docker Hub. - 构建时需要注意当前构建的上下文,可以在运行
docker build
时用-f
指定构建的Dockerfile
以及构建的上下文的目录.-t
指定构建的tag. - 构建时留意缓存,例如
RUN apt-get update
与RUN apt-get update && apt-install -y nginx
有很大差别,第一个apt-get update
的执行结果会被缓存,第二个apt-get update
不会生成新的缓存(RUN会单独生成一个镜像层).一般情况下推荐使用第二个RUN
指令. - ADD与COPY操作的源文件会checksum,校验文件是否被修改,如果和缓存当中一致那么会使用缓存,否则会重新执行指令但是和atime,或者mtime没有关系.这与RUN的缓存机制不一样,只要RUN运行命令没有改变那么就可以读取缓存,不会根据命令结果进行校验.
- 尽量在一个容器只运行一个进程,保持容器的横向扩展.依赖的容器可以通过网络连接起来.