6-Dockerfile常用指令
Dockerfile
Docker可以通过阅读Dockerfile来自动构建镜像,Dockerfile是一个文本文档,其中包含用户可以在命令行上调用的所有命令,使用docker build可以自动创建镜像。
Dockerfile的基本结构
Dockerfile一般分为4个部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时指令
2、Dockerfile格式
# Comment
INSTUCTION arguments
说明:
-
Dockerfile指令不区分大小写,不过官方约定为大写,便于和参数区分
-
Dockfile文件名首字母必须大写。
-
Dockerfile按照顺序运行指令,Dockerfile中的所有shell命令都应是容器中支持的命令。
-
开头表示为注释行
-
Dockerfile的第一个非注释行必须用FROM指令启动,指定要从哪里构建基础镜像。
-
基于Dockerfile做镜像,且需要引用本地文件,工作目录必须为Dockerfile当前目录的子目录或者子目录中的内容。
-
.dockerignore文件
- build时忽略.dockerignore文件中的文件
# comment */temp* */*/temp* temp?此文件将发生以下行为:
规则 行为 # comment忽略。 */temp*排除名称以 temp根的任何直接子目录开头的文件和目录。例如,/somedir/temporary.txt排除纯文件,排除目录/somedir/temp。*/*/temp*排除 temp从根以下两个级别的任何子目录开始的文件和目录。例如,/somedir/subdir/temporary.txt被排除。temp?排除根目录中名称为的一个字符扩展名的文件和目录 temp。例如,/tempa和/tempb被排除。
3、Dockerfile指令介绍
3.1、FROM
- FROM指令用于为镜像文件构建过程中指定基准镜像,后续的指令运行基于此镜像所提供的运行环境。
- 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会从docker主机上查找镜像文件,如不存在,则会从docker hub仓库上拉取
# Description: test image
FROM busybox:latest
3.2、MAINTANIER、LABEL
-
用于让Dockerfile制作者提供本人的详细信息
-
MAINTAIER指令已经被放弃,可使用LABEL
-
LABEL语法
- syntax:LABEL
= - 可以把MAINTAIER作为LABEL的一个键值
# Description: test image FROM busybox:latest MAINTAINER "yull <liangliang.yu@onebank.com.cn>" LABEL maintainer="yull <liangliang.yu@onebank.com.cn>" - syntax:LABEL
3.3、COPY
- 用于从Docker主机复制文件至创建的新镜像文件
- 语法:
- COPY
... - COPY ["
",..." "] : 要复制的源文件或者目录,支持通配符 :目标路径,既正在创建的image的文件系统路径,建议为绝对路径,否者COPY指令以WORKDIR为起始路径 - 在路径中有空白字符时,通常使用第二种格式。
- COPY
- 文件复制准则
必须是build上下文中的路径,不能是其父目录中的文件 - 如果
是目录,则其内部文件或子目录会被递归复制,但 目录自身不会被复制。 - 如果指定了多个
,或在 中使用了通配符,则 必须是一个目录,且必须以/结尾 - 如果
不存在,则会被自动创建,包括其父目录路径
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
COPY ./sendEmail.py /data/app/
-
基于Dockerfile创建镜像
[root@localhost ~]# docker build ./ -t busyhttpd:v0.1 # 基于创建的镜像启动容器,验证 [root@localhost ~]# docker run --name busyweb01 --rm busyhttpd:v0.1 ls /data/app/ sendEmail.py可以看到文件已经copy至容器中。
3.4、ADD
- ADD指令类似于COPY指令,ADD支持使用tar文件和url路径
- 语法
- ADD
... - ADD ["
",..." "]
- ADD
- 操作准则
- 同COPY指令
- 如果
为URL且 不以/结尾,则 指定的文件将被下载并直接创建为 ,如果 以/结尾,则文件名URL指定的文件将被直接下载并保存为 / - 如果
是一个本地系统上的压缩格式的tar文件,将被直接展开为一个目录,类似于tar -xf命令,但如果通过URL上获取的tar文件则不会自动展开 - 如果
有多个,间接或直接使用了通配符,则 必须是一个以/结尾的目录路径
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
COPY ./sendEmail.py /data/app/
# 会在build时下载并复制到容器中,但不会解压。
ADD http://nginx.org/download/nginx-1.16.1.tar.gz /data/app/nginx/
# 如果src在本地存在,则复制后会直接解压
ADD ./nginx-1.16.1.tar.gz /data/app/nginx/
3.5、WORKDIR
-
用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD设定工作目录
-
语法:
- WORKDIR
- 在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,为相对此前的一个WORKDIR指令指定的路径
- 也可以调用由ENV定义的变量
# Description: test image FROM busybox:latest MAINTAINER "yull <liangliang.yu@onebank.com.cn>" LABEL maintainer="yull <liangliang.yu@onebank.com.cn>" WORKDIR /data/app/ # 指定工作目录 ADD nginx-1.16.1.tar.gz ./ # dest只需使用./即可 - WORKDIR
3.6、VOLUME
- 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷
- 语法:
- VOLUME
或 - VOLUME ["
"]
- VOLUME
- 注意
- 如果挂载点目录路径下此前有文件存在,docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。
- Dockerfile中只能使用Docker-managed volume类型,不可直接指定宿主机上的目录。
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
WORKDIR /data/app/
ADD nginx-1.16.1.tar.gz ./
VOLUME /data/mysql/ # 指定容器挂载路径,但不可指定宿主机的目录
3.7、EXPOSE
- 用于为容器打开指定要监听的端口以实现与外部通信。
- 语法:
- EXPOSE
[/ ] [ [/ ]...] 用于指定传输层协议,可为tcp或者udp二者之一,默认为tcp协议
- EXPOSE指令可一次指定多个端口,例如:
- EXPOSE 11211/udp 11211/tcp
- EXPOSE
- 注意
- EXPOSE并不会直接暴露端口让容器端口访问到主机,要使其可以访问,需要在docker run运行容器时通过-p发布这些端口,或者通过-P端口发布EXPOSE到处的所有端口。
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
WORKDIR /data/app/
COPY ./index.html /data/app/www/
ADD nginx-1.16.1.tar.gz ./
VOLUME /data/mysql/
EXPOSE 80/tcp # 暴露80端口
上面的Dockerfile默认创建容器后并不会直接暴露端口到宿主机
[root@localhost images]# docker build ./ -t busyhttpd:v0.8
[root@localhost ~]# docker run --name busyweb01 --rm busyhttpd:v0.8 /bin/httpd -f -h /data/app/www
[root@localhost images]# docker port busyweb01 # 可以看到端口为空
[root@localhost images]#
可以使用-P选项来发布端口
[root@localhost ~]# docker run -P --name busyweb01 --rm busyhttpd:v0.8 /bin/httpd -f -h /data/app/www
[root@localhost images]# docker port busyweb01
80/tcp -> 0.0.0.0:32768
同时也可以在run的时候-p暴露其他端口
3.8、ENV
- 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其他指令(如ENV、ADD、COPY等)所调用
- 调用格式为$variable_name或$
- 语法:
- ENV
或 - ENV
= ...
- ENV
- 注意:
- 第一种格式,
之后的所有内容均会被视作其 的组成部分,因此,一次只能设置一个变量。 - 第二种格式可用一次设置多个变量
- 第一种格式,
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
ENV DOCKER_ROOT /data/app/www/ # 指定ENV变量
ENV DOCKER_ROOT=/data/app/www/ \
WEB_PACKAGE="nginx-1.16.1"
WORKDIR /data/app/
COPY ./index.html ${DOCKER_ROOT:-/data/web/html/} # 引用
ADD ${WEB_PACKAGE}.tar.gz ./
VOLUME /data/mysql/
EXPOSE 80/tcp
同时也支持在docker run时传参。
[root@localhost ~]# docker run -P --name busyweb01 -e WEB_PACKAGE='nginx-1.15.1' --rm busyhttpd:v0.9 printenv
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=ad48e338ff35
WEB_PACKAGE=nginx-1.15.1 # 传入的变量,但此变量只在docker run中改变,镜像中的变量还是使用dockerfile中的。
DOCKER_ROOT=/data/app/www/
HOME=/root
3.9、RUN
- 用于在构建镜像容器中执行命令
- 语法
- RUN
或 - RUN ["
"," ", " "] - 第一种格式中,
通常是一个shell命令,且会以"/bin/sh -c"来运行,这意味着此进程在容器中的PID不为1,不能接收Unix信号,当容器停止时,此进程也会被shutdown。 - 第二种语法格式中的参数是一个Json格式的数组,其中
为要运行的命令,后面的 为传递给命令的选项或者参数,然而,此格式指定的命令不会以"/bin/sh -c"来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行,不过,如果要运行的命令依赖此shell的话可以使用: - RUN ["/bin/sh", "-c", "
", " "]
- RUN ["/bin/sh", "-c", "
- RUN
- 注意:
- RUN运行的命令都是基于基础镜像的,所以基础镜像中没有的命令无法运行。
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
ENV DOCKER_ROOT /data/app/www/
ENV DOCKER_ROOT=/data/app/www/ \
WEB_PACKAGE="nginx-1.16.1"
ADD http://nginx.org/download/nginx-1.16.1.tar.gz ${DOCKER_ROOT}
WORKDIR /data/app/
COPY ./index.html ${DOCKER_ROOT:-/data/web/html/}
VOLUME /data/mysql/
EXPOSE 80/tcp
# 运行RUN指令,解压修改包名
RUN cd ${DOCKER_ROOT} && \
tar -xf ${WEB_PACKAGE}.tar.gz && \
mv ${WEB_PACKAGE} webserver
3.10、CMD
- 类似于RUN指令,用于设置容器启动后默认执行的命令及参数,CMD指令也可用于运行任何指令或者应用程序,不过,二者的运行时间点不同
- RUN指令运行于构建镜像文件过程中,而CMD指令运行于基于Dockerfile构建出来的新文件启动一个容器时。
- CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且运行结束后,容器也将终止。不过CMD指令的命令其可以被docker run的命令行选项所覆盖。
- 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效。
- 语法:
- CMD
或 - CMD ["executable", "param1", "param2"]或
- CMD ["<param1", "param2"]
- 前两种语法格式的意义同RUN
- 第三种则用于为ENTRYPOINT指令提供默认参数,需要结合ENTRYPOINT指令来使用。
- CMD
- 示例
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
ENV DOCKER_ROOT=/data/app/www/ \
WEB_PACKAGE="nginx-1.16.1"
WORKDIR /data/app/
COPY ./index.html ${DOCKER_ROOT:-/data/web/html/}
EXPOSE 80/tcp
RUN cd ${DOCKER_ROOT} && \
mv ${WEB_PACKAGE} webserver
CMD /bin/httpd -f -h /data/app/www/ # 这里的CMD会调用/bin/sh来运行。
CMD ["/bin/sh", "-c","/bin/httpd", "-f", "-h ${DOCKER_ROOT}"] # 同时也支持这种方式。
3.11、ENTRYPOINT
- 用于配置容器启动时的执行命令(不会被忽略,一定会执行,即时运行docker run时制定了其他命令)
- 不过,可以使用--entrypoint选项来覆盖Dockerfile
- ENTRYPOINT的exec格式用于设置容器启动时要执行的命令机器参数,同时可通过CMD命令或者命令行参数提供额外的参数。
- 如果Dockerfile中同时提供了ENTRYPOINT和CMD。那么CMD会作为参数传给ENTRYPOINT
# Description: test image
FROM busybox:latest
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
# ENV DOCKER_ROOT /data/app/www/
ENV DOCKER_ROOT=/data/app/www/
COPY ./index.html ${DOCKER_ROOT:-/data/web/html/}
EXPOSE 80/tcp
RUN cd ${DOCKER_ROOT} && \
mv ${WEB_PACKAGE} webserver
# CMD ["/bin/sh", "-c","/bin/httpd", "-f", "-h ${DOCKER_ROOT}"]
ENTRYPOINT /bin/httpd -f -h /data/app/www/
# 或者可同时指定CMD和ENTRYPOINT
CMD ["/bin/httpd", "-f", "-h /data/app/www/"]
ENTRYPOINT ["/bin/sh", "-c"]
3.12、USER
- 用于指定运行image时或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
- 默认情况下,container的运行身份为root用户
- 语法:
- USER
| - 需要注意的是
可以是任意数字,但必须为/etc/passwd中某用户有效UID,否者,docker run会运行失败
- USER
3.13、HEALTHCHECK
-
用于容器启动后的健康状况检查
-
当在一个镜像指定了
HEALTHCHECK指令后,用其启动容器,初始状态会为starting,在HEALTHCHECK指令检查成功后变为healthy,如果连续一定次数失败,则会变为unhealthy。 -
与CMD和ENTRYPOINT一样,只可以出现一次,如果写了多个,只有最后一个生效
-
语法
- HEALTHCHECK <参数> <命令>
-
支持的选项
--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;--retries=<次数>:当连续失败指定次数后,则将容器状态视为unhealthy,默认 3 次。- --start-period=<时长>:当容器启动指定时长后,才开始健康检查,默认为0s,启动后就检查
-
返回状态
- 0:成功
- 1:失败
- 2:保留
# Description: test image
FROM nginx:stable-alpine
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer="yull <liangliang.yu@onebank.com.cn>"
ENV NGINX_ROOT="/data/app/nginx/"
ADD entrypoint.sh /bin/
COPY ./index.html ${NGINX_ROOT}
# 指定启动后自动检测容器状态
HEALTHCHECK --interval=5s --timeout=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ || exit 1
CMD ["/usr/sbin/nginx", "-g", "daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
启动成功后可以使用docker ps查看状态
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fc19f4d7ced7 nginxweb02:v0.2.6 "/bin/entrypoint.sh …" 7 seconds ago Up 6 seconds (healthy) 0.0.0.0:32776->80/tcp nginxweb02
3.14、ARG
- 构建参数和ENV的效果类似,都是设置环境变量,不同的是ARG所设置构建的环境变量,在将来容器运行时是不会存在这些环境变量的。
- 可以在build时使用--build-arg <参数名>=<值>来向Dockerfile中传递参数。
# Description: test image
FROM nginx:stable-alpine
MAINTAINER "yull <liangliang.yu@onebank.com.cn>"
ARG author="yull <liangliang.yu@onebank.com.cn>"
LABEL maintainer=${author}

浙公网安备 33010602011771号