Dockerfile 介绍
Dockerfile 是用来构建 Docker 镜像的文件,实质是一系列命令和参数构成的脚本文件。当 Dockerfile 文件编写完之后,可以通过 “docker build” 与”docker run” 命令构建并运行新的 Docker 镜像。其中 Dockerfile 定义了进程需要的一切东西,涉及的内容包括执行代码或者文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版本、服务进程和内核进程(当应用进程需要和系统服务、内核进程打交道的时候,需要考虑如何设计 namespace 的权限控制)等等。
Dockerfile、Docker 镜像、Docker 容器三者的关系
Dockerfile 面向开发,Docker 镜像是交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,其中 Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,Docker 容器则可以认为是软件的运行状态,示意图如下:
Dockerfile 编写示例
1 2 3 4 5 6 7 8 9 10 11 12 # Centos7官方的Dockerfile FROM scratch ADD centos-7-docker.tar.xz / LABEL org.label-schema.schema-version="1.0" \ org.label-schema.name="CentOS Base Image" \ org.label-schema.vendor="CentOS" \ org.label-schema.license="GPLv2" \ org.label-schema.build-date="20181205" CMD ["/bin/bash"]
Dockerfile 基础知识
#表示注释 指令按照从上到下的顺序执行 每条指令都会创建一个镜像层,并对镜像进行提交 每条保留字指令都必须为大写字母格式,且后面至少要跟随一个参数 Docker 执行 Dockerfile 的大致流程
Docker 从基础镜像运行一个容器 执行一条指令并对容器作出修改 执行类似”docker commit” 的操作来提交一个新的镜像层 Docker 再基于刚提交的新镜像运行一个新容器 执行 Dockerfile 中的下一条指令,重复上面的执行流程,直到所有指令都执行完成 Dockerfile 指令 - FROM
1 2 3 4 5 6 7 功能:指定基础镜像,并且必须是第一条指令;如果不以任何第三方镜像为基础,那么写法为:FROM scratch 语法: FROM <image> FROM <image>:<tag> FROM <image>:<digest> 三种写法,其中<tag>和<digest> 是可选项,如果没有选择,那么默认值为latest
Dockerfile 指令 - MAINTAINER
1 2 3 功能:指定镜像维护者,可以是维护者的姓名、邮箱地址、网页地址等 语法:MAINTAINER <name>
Dockerfile 指令 - RUN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 功能:指定镜像构建时需要运行的命令,一般用于更新系统、安装应用软件等 语法: RUN <command> RUN ["executable", "param1", "param2"] 第一种写法后边直接跟shell命令,在linux操作系统上默认是"/bin/sh -c",在windows操作系统上默认是"cmd /S /C" 第二种写法是类似于函数调用,可将executable理解成为可执行文件,后面就是两个参数 RUN指令使用\作为换行符 示例: RUN /bin/bash -c "source $HOME/.bashrc; echo $HOME" RUN ["/bin/bash", "-c", "echo hello"] 注意: 多行命令尽量不要写多个RUN,原因是Dockerfile中每一个指令都会建立新的镜像层;多少个RUN就构建了多少个镜像层,会造成镜像的臃肿、多层,不仅仅增加了构建部署的时间,还容易出错
Dockerfile 指令 - ENV
1 2 3 4 5 6 功能:设置环境变量 语法: ENV <key> <value> ENV <key>=<value> <key>=<value> ... 两者的区别就是第一种是一次设置一个,第二种是一次设置多个
Dockerfile 指令 - WORKDIR
1 2 3 4 5 6 7 8 9 10 功能:设置工作目录(即容器创建并启动后,通过终端登录进来所处的目录);对RUN、CMD、ENTRYPOINT、COPY、ADD指令生效,如果目录不存在则会自动创建,可以设置多次 语法: WORKDIR /path/to/workdir 注意: WORKDIR可以解析环境变量,例如: ENV DIRPATH /path WORKDIR $DIRPATH RUN pwd
Dockerfile 指令 - ADD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 功能:将宿主机目录下的文件拷贝进镜像中,且支持url解析与自动解压tar压缩包 语法: ADD <src>... <dest> ADD ["<src>",... "<dest>"] <src>可以是一个本地文件或者是一个本地压缩文件,还可以是一个url(此时类似于wget命令) <dest>路径的填写可以是容器内的绝对路径,也可以是相对于工作目录的相对路径 示例: ADD test relativeDir/ ADD test /relativeDir ADD http://example.com/foobar / 注意: 任何压缩文件通过url的方式进行拷贝,都不会自动解压;同时尽量不要把<scr>写成一个文件夹,如果<src>是一个文件夹,则复制整个目录的内容,包括文件系统元数据
Dockerfile 指令 - COPY
1 2 3 4 5 6 7 8 功能:将宿主机目录下的文件拷贝进镜像中 语法: COPY <src>... <dest> COPY ["<src>",... "<dest>"] 注意: COPY指令只能拷贝本地文件,不支持url解析,不会自动解压tar压缩包,除此之外其他用法与ADD指令一致
Dockerfile 指令 - VOLUME
1 2 3 4 5 6 7 8 功能:数据卷,用于容器内数据的保存和持久化 语法: VOLUME /dataVolume VOLUME ["/dataVolume"] VOLUME /dataVolume1 /dataVolume2 VOLUME ["/dataVolume1","/dataVolume2"] 参数可以是一个JsonArray ,也可以是单个或多个值,上面四种写法都是正确的
Dockerfile 指令 - CMD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 功能:指定容器启动时需要执行的命令 语法: CMD ["executable","param1","param2"] CMD command param1 param2 CMD ["param1","param2"] 第一种使用exec执行,推荐使用 第二种在/bin/sh中执行,提供给需要交互的应用 第三种指定提供给ENTRYPOINT指令的参数 示例: CMD [ "sh", "-c", "echo $HOME"] CMD /bin/bash -c "echo $HOME" CMD [ "echo", "$HOME"] 注意: 每个Dockerfile文件只能有一条CMD命令,如果指定了多条CMD指令,只有最后一条CMD指令会被执行。同时如果用户启动容器时候指定了运行的命令,则会覆盖掉Dockerfile文件中CMD指令指定的命令;例如“docker run -it peter/centos:1.1 ls -al”中的“ls -al”会覆盖Dockerfile文件中的CMD指令。
Dockerfile 指令 - ENTRYPOINT
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 功能:指定容器启动时需要执行的命令 语法: ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2 示例: ENTRYPOINT [ "sh", "-c", "echo $HOME"] ENTRYPOINT /bin/bash -c "echo $HOME" ENTRYPOINT与CMD指令的相同点: 1) 容器启动时才执行指令,运行时机相同 2) 每个Dockerfile文件只能有一条ENTRYPOINT/CMD命令,如果指定了多条ENTRYPOINT/CMD指令,只有最后一条ENTRYPOINT/CMD指令会被执行 ENTRYPOINT与CMD指令的不同点: 1)如果用户启动容器时指定了运行的命令,ENTRYPOINT指令不会被覆盖(会追加后续用户启动容器时指定的命令内容),而CMD指令则会被覆盖 2)如果在Dockerfile中同时写了ENTRYPOINT和CMD指令,并且CMD指令不是一个完整的可执行命令,那么CMD指令的内容将会作为ENTRYPOINT指令的参数 3)如果在Dockerfile中同时写了ENTRYPOINT和CMD指令,并且CMD指令是一个完整的指令,那么它们两个会互相覆盖,谁在最后谁生效
Dockerfile 指令 - ONBUILD
1 2 3 4 5 6 7 8 功能:该指令只对当前镜像的子镜像生效,即父镜像在被子镜像继承后,父镜像Dockerfile中的ONBUILD指令会被触发 语法: ONBUILD [INSTRUCTION] 示例: ONBUILD RUN [ "npm", "install" ] ONBUILD COPY ./package.json /app
Dockerfile 指令 - EXPOSE
1 2 3 4 5 6 7 8 9 功能:暴露容器运行时监听的端口,使容器内的应用可以通过端口和外界通信 语法: EXPOSE port1 EXPOSE port2 EXPOSE port3 注意: EXPOSE指令并不会让容器监听的端口映射到宿主机的端口,如果想使容器监听的端口与宿主机的端口有映射关系,必须在容器启动的时候指定"-P"或者"-p"参数
Dockerfile 指令 - USER
1 2 3 4 5 6 7 8 功能:指定启动容器的用户,可以是用户名或UID 语法: USER admin USER UID 注意: 如果设置了容器以admin用户去运行,那么RUN、CMD、ENTRYPOINT指令都会以这个用户身份去运行
Dockerfile 指令 - STOPSIGNAL
1 2 3 4 功能:指定当容器退出时给系统发送指定的信号 语法: STOPSIGNAL signal
Dockerfile 指令 - ARG
1 2 3 4 5 6 7 8 9 10 11 功能:定义变量 语法: ARG <name>[=<default value>] 示例: ARG user1 ARG buildno=1 注意: 当使用ARG指令定义了一个变量,在执行"docker build"命令构建镜像的时候,使用"--build-arg <varname>=<value>"来指定变量的值;如果用户在构建镜像时指定了一个没有定义在Dockerfile中的变量,那么Docker将会抛出一个Warning;如果ARG定义的变量拥有默认值,那么当构建镜像没有指定变量值的时候,将会使用这个默认值
Dockerfile 指令 - LABEL
1 2 3 4 5 6 7 8 9 10 11 12 13 功能:为镜像指定标签 语法: LABEL <key>=<value> <key>=<value> <key>=<value> ... 示例: LABEL "com.example.vendor"="ACME Incorporated" LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3" 注意: Dockerfile中可以有多个LABEL指令,但是建议只使用一个LABEL指令并写成一行,如太长需要换行则可以使用\符号作为换行符。LABEL指令会继承基础镜像中的LABEL指令,如遇到key相同,则覆盖父镜像的值