Dockerfile参考

Docker可以通过阅读Dockerfile来自动构建镜像,Dockerfile是一个文本文档,其中包含用户可以在命令行上调用的所有命令,使用docker build可以自动创建镜像。

Dockerfile的基本结构

Dockerfile一般分为4个部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时指令

Dockerfile格式

  1. # Comment
  2. 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被排除。

Dockerfile指令介绍

  • FROM

    • FROM指令用于为镜像文件构建过程中指定基准镜像,后续的指令运行基于此镜像所提供的运行环境。
    • 实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build会从docker主机上查找镜像文件,如不存在,则会从docker hub仓库上拉取
      # Description: test image
      FROM busybox:latest
      
  • 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>"
        
  • COPY

    • 用于从Docker主机复制文件至创建的新镜像文件
    • 语法:

      • COPY …
      • COPY [“”,…””]

        • : 要复制的源文件或者目录,支持通配符
        • :目标路径,既正在创建的image的文件系统路径,建议为绝对路径,否者COPY指令以WORKDIR为起始路径
        • 在路径中有空白字符时,通常使用第二种格式。
    • 文件辅助准则

      • 必须是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至容器中。

  • ADD

    • ADD指令类似于COPY指令,ADD支持使用tar文件和url路径
    • 语法

      • 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/
        
  • 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只需使用./即可
          
  • VOLUME

    • 用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其他容器上的卷
    • 语法:

      • 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/  # 指定容器挂载路径,但不可指定宿主机的目录
        
  • EXPOSE

    • 用于为容器打开指定要监听的端口以实现与外部通信。
    • 语法:

      • EXPOSE [/] [ [/]…]

        • 用于指定传输层协议,可为tcp或者udp二者之一,默认为tcp协议
      • EXPOSE指令可一次指定多个端口,例如:

        • EXPOSE 11211/udp 11211/tcp
    • 注意

      • EXPOSE并不会直接暴露端口让容器端口访问到主机,要使其可以访问,需要在docker run运行容器时通过-p发布这些端口,或者通过-P端口发布EXPOSE到处的所有端口。 ```dockerfile

        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端口


```bash
[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]#
[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
  • ENV

    • 用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其他指令(如ENV、ADD、COPY等)所调用
    • 调用格式为6-Dockerfile详解 - 图1{variable_name}
    • 语法:

      • ENV 或
      • ENV = …
    • 注意:

      • 第一种格式,之后的所有内容均会被视作其的组成部分,因此,一次只能设置一个变量。
      • 第二种格式可用一次设置多个变量 ```dockerfile

        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


```bash
[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
  • RUN

    • 用于在构建镜像容器中执行命令
    • 语法

      • RUN 或
      • RUN [“”,” “, “”]
      • 第一种格式中,通常是一个shell命令,且会以”/bin/sh -c”来运行,这意味着此进程在容器中的PID不为1,不能接收Unix信号,当容器停止时,此进程也会被shutdown。
      • 第二种语法格式中的参数是一个Json格式的数组,其中为要运行的命令,后面的为传递给命令的选项或者参数,然而,此格式指定的命令不会以”/bin/sh -c”来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行,不过,如果要运行的命令依赖此shell的话可以使用:

        • RUN [“/bin/sh”, “-c”, “”, “”]
    • 注意:

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


- 
CMD

   - 类似于RUN指令,用于设置容器启动后默认执行的命令及参数,CMD指令也可用于运行任何指令或者应用程序,不过,二者的运行时间点不同

      - RUN指令运行于构建镜像文件过程中,而CMD指令运行于基于Dockerfile构建出来的新景祥文件启动一个 容器时
      - CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且运行结束后,容器也将终止。不过CMD指令的命令其可以被docker run的命令行选项所覆盖。
      - 在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效。
   - 语法:

      - CMD  或
      - CMD ["executable", "param1", "param2"]或
      - CMD ["<param1", "param2"]
      - 前两种语法格式的意义同RUN
      - 第三种则用于为ENTRYPOINT指令提供默认参数,需要结合ENTRYPOINT指令来使用。
   - 示例
```dockerfile
# 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}"] # 同时也支持这种方式。
  • ENTRYPOINT

    • 用于配置容器启动时的执行命令(不会被忽略,一定会执行,即时运行docker run时制定了其他命令)
    • 不过,可以使用—entrypoint选项来覆盖Dockerfile
    • ENTRYPOINT的exec格式用于设置容器启动时要执行的命令机器参数,同时可通过CMD命令或者命令行参数提供额外的参数。
    • 如果Dockerfile中同时提供了ENTRYPOINT和CMD。那么CMD会作为参数传给ENTRYPOINT ```dockerfile

      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”]


- 
USER

   - 用于指定运行image时或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
   - 默认情况下,container的运行身份为root用户
   - 语法:

      - USER  | 
      - 需要注意的是可以是任意数字,但必须为/etc/passwd中某用户有效UID,否者,docker run会运行失败
- 
HEALTHCHECK

   - 
用于容器启动后的健康状况检查

   - 
当在一个镜像指定了 `HEALTHCHECK` 指令后,用其启动容器,初始状态会为 `starting`,在 `HEALTHCHECK` 指令检查成功后变为 `healthy`,如果连续一定次数失败,则会变为 `unhealthy`。

   - 
与CMD和ENTRYPOINT一样,只可以出现一次,如果写了多个,只有最后一个生效

   - 
语法

      - HEALTHCHECK <参数> <命令>
   - 
支持的选项

      - `--interval=<间隔>`:两次健康检查的间隔,默认为 30 秒;
      - `--timeout=<时长>`:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
      - `--retries=<次数>`:当连续失败指定次数后,则将容器状态视为 `unhealthy`,默认 3 次。
      - --start-period=<时长>:当容器启动指定时长后,才开始健康检查,默认为0s,启动后就检查
   - 
返回状态

      - 0:成功
      - 1:失败
      - 2:保留
```dockerfile
# 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"]
[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
  • ARG

    • 构建参数和ENV的效果类似,都是设置环境变量,不同的是ARG所设置构建的环境变量,在将来容器运行时是不会存在这些环境变量的。
    • 可以在build时使用—build-arg <参数名>=<值>来向Dockerfile中传递参数。 ```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} ```