Dockerfile的结构分红了若干部分,每一个部分之间的前后顺序有明确的要求:java
部分 | 命令 |
---|---|
基础镜像信息 | FROM |
维护者信息 | MAINTAINER |
镜像操做指令 | RUN 、COPY 、ADD 、EXPOSE 、WORKDIR 、ONBUILD 、USER 、VOLUME 等 |
启动时命令 | CMD , ENTRYPOINT |
以携程Apollo开源项目的Dockerfile为例:nginx
# Dockerfile for apollo-adminservice # 1. Copy apollo-adminservice-${VERSION}-github.zip to current directory # 2. Build with: docker build -t apollo-adminservice . # 3. Run with: docker run -p 8090:8090 -d -v /tmp/logs:/opt/logs --name apollo-adminservice apollo-adminservice FROM openjdk:8-jre-alpine MAINTAINER ameizi <sxyx2008@163.com> ENV VERSION 1.5.0-SNAPSHOT ENV SERVER_PORT 8090 # DataSource Info ENV DS_URL "" ENV DS_USERNAME "" ENV DS_PASSWORD "" RUN echo "http://mirrors.aliyun.com/alpine/v3.8/main" > /etc/apk/repositories \ && echo "http://mirrors.aliyun.com/alpine/v3.8/community" >> /etc/apk/repositories \ && apk update upgrade \ && apk add --no-cache procps unzip curl bash tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone ADD apollo-adminservice-${VERSION}-github.zip /apollo-adminservice/apollo-adminservice-${VERSION}-github.zip RUN unzip /apollo-adminservice/apollo-adminservice-${VERSION}-github.zip -d /apollo-adminservice \ && rm -rf /apollo-adminservice/apollo-adminservice-${VERSION}-github.zip \ && sed -i '$d' /apollo-adminservice/scripts/startup.sh \ && chmod +x /apollo-adminservice/scripts/startup.sh \ && echo "tail -f /dev/null" >> /apollo-adminservice/scripts/startup.sh EXPOSE $SERVER_PORT CMD ["/apollo-adminservice/scripts/startup.sh"]
Dockerfile中使用#
进行行注释。git
格式:github
ADD <src> <dest>
从src
复制文件到容器中的dest
。web
注意:docker
src
能够是文件、目录、URL或压缩包,可是必须在构建上下文也就是Dockerfile所在的目录中dest
以/
结尾,则认为src
是一个目录;dest
不以/
结尾,则认为src
是一个文件。src
是可识别的压缩包格式(gzip, bzip2, xz),则Docker会自动解压到容器的指定dest
,dest
中重名的文件不会被覆盖。dest
不存在,则会自动建立dest
(含路径中的任何目录),新建立的文件和目录的模式为755
,UIG和GID都是0。ARG
设置构建时的环境变量,这些指定的参数在容器运行时再也不有用。ubuntu
示例数组
ARG build # 声明一个构建参数,但没有赋缺省值 ARG webapp_user=wasuser # 声明一个构建参数并指定缺省值
在docker build
命令构建镜像时,经过--build-arg
指定构建参数的值,例如:bash
docker build --build-arg build=12345 -t darren/test_image .
此时构建Dockerfile中使用到的build
的实际值是12345
,而webapp_user
的实际值是其缺省值。app
CMD
指定容器启动时执行的一条命令。
不一样于RUN
命令,RUN
指令指定镜像被构建时要执行的命令,CMD
指定容器启动时要执行的命令。
每一个Dockerfile只有一个CMD
命令,若是指定了多条CMD
命令,则只有最后一条会被执行。
启动容器时若是经过命令行指定了运行的命令,将会覆盖Dockerfile中指定的CMD
命令。
Docker推荐使用数组语法设置要执行的命令:
CMD ["/bin/bash", "-l"]
COPY
相似于ADD
:
格式:
COPY <src> <dest>
注意:
COPY
不支持URL和压缩包。src
是一个目录,则将其中的全部文件拷贝到dest
,而不含src
自己;dest
必须是一个绝对路径与CMD
指令相似,一样指定容器启动时执行的命令。
docker run
命令中指定的任何参数都会被当作参数再次传递给ENTRYPOINT
指定的命令。
格式:
ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command arg1 arg2
示例:
在Dockerfile中:
ENTRYPOIINT ["/usr/sbin/nginx"]
在docker run
命令中:
docker run -t -i darren/test_image -g "daemon off;"
其中的参数-g "daemon off;"
会传递给ENTRYPOINT
指定的命令,接在ENTRYPOINT
以后,所以,最终实际在启动容器时执行的至关于ENTRYPOINT
指令:
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]
其含义是前台进程的形式运行Nginx守护进程。
当ENTRYPOINT
和CMD
同时使用时,全部命令行中指定的参数会传递给ENTRYPOINT
指令,覆盖CMD
指定的参数;当命令行没有额外指定参数时,则ENTRYPOINT
以CMD
指定的参数做为默认的输入。
示例:
ENTRYPOINT ["/usr/sbin/nginx"] CMD ["-h"]
此时能够在docker run
命令中显示指定参数从而修改ENTRYPOINT
指令的参数,或者使用CMD
传给ENTRYPOINT
指令的参数,至关于/usr/sbin/nginx -h
,即显示Nginx的帮助。
ENV
设置环境变量,设置的环境变量在容器运行时能够在容器内获取和使用,后续的RUN
指令等可使用ENV
指令设置的环境变量。
示例:
ENV RVM_PATH=/home/rvm RVM_ARCHFLAGS="-arch amd64"
ENV JAVA_HOME /path/to/java WORKDIR $JAVA_HOME
ENV
指令指定的环境变量会保存到构建的全部容器中,例如Linux容器中经过env
命令来查看容器运行时的环境变量。
docker run
命令中经过-e
选项传递的环境变量只对该命令启动的容器当次运行生效。
声明容器对外暴露的端口号:
EXPOSE <port1> EXPOSE <port1> <port2> <port3>
运行时容器真实暴露的端口以命令行中的设定为准,若是在启动一个容器时但愿使用其Dockerfile中声明的端口,则使用-P
选项:
docker run -P your-docker-image
FROM
指定构建使用的基础镜像,FROM
命令必须写在其余的指令前。
格式:
FROM <image> FROM <image>:<tag> FROM <image>@<digest>
LABEL
指令添加的元数据须要以键值对的形式指定。
示例:
LABEL version="1.0.0" LABEL description="This description illustrates \ that label-values can span multi lines." LABEL key1="v1" k2="v2" k3="v3"
注意:
LABEL
指令的值中,\
能够用来换行。LABEL
中执行docker inspect
命令来查看镜像的标签用于为Dockerfile署名。
示例:
MAINTAINER darren<darren@darren_s.com>
RUN
不一样于CMD
指令,RUN
能够在Dockerfile中出现和执行屡次。
在Shell终端中执行命令,Linux中默认是/bin/sh -c
,Windows中是cmd /s /c
。
格式:
RUN <command> RUN ["executable", "arg1", "arg2", ..., "argN"]
示例:
RUN ["/bin/sh", "-c", "echo Hello Wolrd!"]
指定启动时的用户,后续的指令都将以该用户执行命令。
示例:
USER wasuser
使用USER
指令的各类方式
USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group
如不经过USER
指令指定用户,默认的用户为root
。
能够在docker run
命令中经过-u
选项覆盖该指令的值。
向容器添加卷,一个卷是能够存在于一个或多个容器内的特定目录。
使容器内的一个目录具备持久化存储的功能,被指定的目录既能够被容器自己使用,也能够共享给其余容器。
示例:
VOLUME /mnt/data
该指令为每一个基于该镜像建立的容器建立一个名为/mnt/data
的挂载点。也能够指定多个卷:
VOLUME ["/mnt/project1", "/mnt/project2"]
从镜像建立容器时,在容器内设置一个工做目录。
至关于Linux中的cd
命令,用于切换到指定的工做目录,后续的指令都将在指定的工做目录下执行。
WORKDIR
指令能够屡次出现,在不一样的工做目录之间进行切换:
WORKDIR /opt/webapp/db RUN bundle install WORKDIR /opt/webapp RUN [ "rackup" ]
启动容器时可使用-w
选项覆盖工做目录:
docker run -it -w /var/log ubuntu pwd
会将容器内的工做目录设置为/var/log
。
为镜像添加触发器,当镜像A被做为镜像B的基础镜像,在构建镜像B时,会执行镜像A的ONBUILD
指令。
注意:
ONBUILD
指令按照其在镜像A中声明的顺序依次执行ONBUILD
指令只能被继承一次,即若是镜像C再以镜像B做为基础镜像,构建镜像C时不会触发镜像A的ONBUILD
指令。ONBUILD
指令在镜像B的FROM
指令后当即执行。FROM
、MAINTAINER
、ONBUILD
指令是不能出如今ONBUILD
指令中的。示例
镜像A中:
ONBUILD ADD . /var/www
镜像B
FROM 镜像A
则会在构建镜像B的Step 0 : FROM
阶段就执行镜像A的ONBUILD
指令,即将构建上下文中的全部内容添加到/var/www
目录