Dockerfile(转载)

Dockerfile

镜像的生产途径

1.基于容器
2.基于Dockerfile

Dockerfile

Dockerfile is nothing but the source code for building Docker images
    Docker can build images automatically by reading the instructions from
    A  Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image
    Using  docker build users can create an automated build that executes several command-line instructions in succession

Dockerfile Format 语法格式

## 语法
Format
    # Comment
    INSTRUCTION arguments

## Dockerfile 指令 大小写不敏感,但是预定俗称为大写
The instruction is not case-sensitive
    However, convention is for them to be UPPERCASE to distinguish them from arguments more easily

## 顺序执行指令,前后关系很重要
Docker runs instructions in a  Dockerfile in order

## 第一个非注释行必须为 FROM 指令,指定做当前镜像基于那个基础镜像
The first instruction must be `FROM` in order to specify the Base Image from which you are building

Environment replacement

Environment variables (declared with the ENV statement) can also be used in certain instructions as variables to be interpreted by the  Dockerfile

Environment variables are notated in the  Dockerfile either with  $variable_name or  ${variable_name}

The  ${variable_name} syntax also supports a few of the
standard  bash modifiers
    ${variable:-word} indicates that if variable is set then the result will be that value. If variable is not set then word will be the result.
    ${variable:+word} indicates that if variable is set then word will be the result, otherwise the result is the empty string.

使用变量的2种方式:
    ${variable:-word} :变量没值或为空,使用word值,有值使用原本值
    ${variable:+word} :变量有值,使用word值,没值就没值

.dockerignore file

Before the docker CLI sends the context to the docker daemon, it looks for a file named  .dockerignore in the root directory of the context

If this file exists, the CLI modifies the context to exclude files and directories that match patterns in it

The CLI interprets the  .dockerignore file as a newline-separated list of patterns similar to the file globs of Unix shells

## 忽略某些文件,当Dockerfile拷贝当前所有文件到容器中时,若 .dockerignore 中设置了某些文件,则这些文件不会被拷贝到容器中

Dockerfile Instructions

FROM

FROM 指令是最重的一个且必须为 Dockerfile文件开篇的第一个非注释行,用于为映像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境

实践中,基准镜像可以是任何可用镜像文件,默认情况下,docker build 会在 docker主主机上查找指定的镜像文件,在其不存在时,则会从 Docker Hub Registry 上拉取所需的镜像文件
    如果找不到指定的镜像文件, docker build 会返回一个错误信息

Syntax语法
    FROM <image>[:<tag>]  或
    FROM <image>@<digest>  ## digest 指定镜像hash码
        <image> :指定作为 base image 的名称;
        <tag> :base image 的标签,为可选项,省略时默认为latest

MAINTANIER (depreacted已废弃 --> LABEL v1.17版本)

用于让镜像制作者提供本人的详细信息
Dockerfile 并不限制 MAINTAINER指令可在出现的位置,但推荐将其放置于FROM 指令之后

Syntax
    MAINTAINER <authtor's detail>
        <author's detail> 可是任何文本信息,但约定俗成地使用作者名称及邮件地址

LABEL

该指令是为镜像添加标签。顶替 MAINTANIER 指令

  • 句法:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
  • 一个Dockerfile种可以有多个LABEL,如下:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
LABEL maintainer="evescn evescn@evescn.com"

COPY

用于从 Docker 主机复制文件至创建的新映像文件
Syntax
    COPY <src> ... <dest>  或
    COPY ["<src>",... "<dest>"]
        <src> :要复制的源文件或目录,支持使用通配符
        <dest> :目标路径,即正在创建的 image 的文件系统路径;建议为 <dest> 使用绝对路径,否则, COPY 指定则以 WORKDIR 为其起始路径;
    注意:在路径中有空白字符时,通常使用第二种格式

文件复制准则
    <src> 必须是 build 上下文中的路径,不能是其父目录中的文件
    如果 <src> 是目录,则其内部文件或子目录会被递归复制,但 <src>目录自身不会被复制
    如果指定了多个 <src> ,或在 <src> 中使用了通配符,则 <dest>必须是一个目录 / 结尾
    如果 <dest> 事先不存在,它将会被自动创建,这包括其父目录路径

ADD

ADD 指令类似于 COPY 指令, ADD 支持使用 TAR 文件和 URL 路径
Syntax
    ADD <src> ... <dest>  或
    ADD ["<src>",... "<dest>"]

操作准则
    同 COPY 指令

    如果 <src> 为 URL 且 <dest> 不以 / 结尾,则 <src>指定的文件将被下载并直接被创建为 <dest> ;如果 <dest> 以 / 结尾,则文件名 URL指定的文件将被直接下载并保存为 <dest>/<filename>

    如果 <src> 是一个本地系统上的压缩格式的 tar文件,它将被展开为一个目录,其行为类似于“ tar -x ”命令;然而,通过 URL 获取到的 tar文件将不会自动展开;

    如果 <src> 有多个,或其间接或直接使用了通配符,则 <dest> 必须是一个以 / 结尾的目录路径;如果 <dest> 不以 / 结尾,则其被视作一个普通文件, <src> 的内容将被直接写入到 <dest> ;

WORKDIR

用于为 Dockerfile 中所有的 RUN 、 CMD 、 ENTRYPOINT 、 COPY 和 ADD 指定设定工作目录

Syntax
    WORKDIR <dirpath>
        在 Dockerfile 文件中, WORKDIR指令可出现多次,其路径也可以为相对路径,其是相对此前一个 WORKDIR 指令指定的路径
        另外, WORKDIR 也可调用由 ENV 指定定义的变量
    例如
        WORKDIR /var/log
        WORKDIR $STATEPATH

VOLUME

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

Syntax
    VOLUME <mountpoint>  或
    VOLUME ["<mountpoint>"]

如果挂载点目录路径下此前在文件存在, docker run命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中

EXPOSE

用于为容器打开指定要监听的端口以实现与外部通信
Syntax
    EXPOSE <port>[/<protocol>] [<port>[/<protocol>] ...]
        <protocol> 用于指定传输层协议,可为 tcp 或 udp 二者之一,默认为 TCP 协议
EXPOSE 指令可一次指定多个端口,例如
    EXPOSE 11211/udp 11211/tcp

ENV

用于为镜像定义所需的环境变量,并可被 Dockerfile文件中位于其后的其它指令(如 ENV 、 ADD 、 COPY 等)所调用
调用格式为 $variable_name 或 ${variable_name}

Syntax
    ENV <key> <value>  或
    ENV <key>=<value> ...

第一种格式中, <key> 之后的所有内容均会被视作其 <value>的组成部分,因此,一次只能设置一个变量;

第二种格式可用一次设置多个变量,每个变量为一个 "<key>=<value>"的
键值对,如果 <value> 中包含空格,可以以反斜线 (\)进行转义,也可通过对 <value> 加引号进行标识;另外,反斜线也可用于续行;

定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

RUN

用于指定 docker build 过程中运行的程序,其可以是任何命令

Syntax
    RUN <command>  或
    RUN ["<executable>", "<param1>", "<param2>"]

第一种格式中, <command> 通常是一个 shell 命令,且以 "/bin/sh -c" 来运行它,这意味着此进程在容器中的 PID 不为 1 ,不能接收 Unix 信号,因此,当使用 docker stop <container> 命令停止容器时,此进程接收不到 SIGTERM 信号;

第二种语法格式中的参数是一个 JSON 格式的数组,其中 <executable>为要运行的命令,后面的 <paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“ /bin/sh -c” 来发起,因此常见的 shell 操作如变量替换以及通配符 (?,*等) 替换将不会进行;不过,如果要运行的命令依赖于此 shell特性的话,可以将其替换为类似下面的格式。
	RUN ["/bin/bash", "-c", "<executable>", "<param1>"]

注意:json数组中,要使用双引号

CMD

类似于 RUN 指令, CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同
    RUN 指令运行于映像文件构建过程中,而 CMD 指令运行于基于 Dockerfile构建出的新映像文件启动一个容器时
    CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过, CMD 指定的命令其可以被 docker run 的命令行选项所覆盖
	在 Dockerfile 中可以存在多个 CMD 指令,但仅最后一个会生效

Syntax
    CMD <command>  或
    CMD [ “ <executable> ”,  “ <param1> ”,  “ <param2> ”]  或
    CMD ["<param1>","<param2>"]

前两种语法格式的意义同 RUN
第三种则用于为 ENTRYPOINT 指令提供默认参数

注意:json数组中,要使用双引号

ENTRYPOINT

类似 CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序

与 CMD 不同的是,由 ENTRYPOINT 启动的程序不会被 docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给 ENTRYPOINT 指定指定的程序
    不过, docker run 命令的 --entrypoint 选项的参数可覆盖 ENTRYPOINT 指令指定的程序

Syntax
    ENTRYPOINT <command>
    ENTRYPOINT ["<executable>", "<param1>", "<param2>"]

docker run 命令传入的命令参数会覆盖 CMD 指令的内容并且附加到ENTRYPOINT 命令最后做为其参数使用

Dockerfile 文件中也可以存在多个 ENTRYPOINT 指令,但仅有最后一个会生效

注意:json数组中,要使用双引号

USER

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

Syntax
    USER <UID>|<UserName>
    需要注意的是, <UID> 可以为任意数字,但实践中其必须为 /etc/passwd 中某用户的有效 UID ,否则, docker run 命令将运行失败

HEALTHCHECK

  • 格式:
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。

在没有 HEALTHCHECK 指令前,Docker 引擎只可以通过容器内主进程是否退出来判断容器是否状态异常。很多情况下这没问题,但是如果程序进入死锁状态,或者死循环状态,应用进程并不退出,但是该容器已经无法提供服务了。在 1.12 以前,Docker 不会检测到容器的这种状态,从而不会重新调度,导致可能会有部分容器已经无法提供服务了却还在接受用户请求。

而自 1.12 之后,Docker 提供了 HEALTHCHECK 指令,通过该指令指定一行命令,用这行命令来判断容器主进程的服务状态是否还正常,从而比较真实的反应容器实际状态。

当在一个镜像指定了 HEALTHCHECK 指令后,用其启动容器,初始状态会为 starting,在 HEALTHCHECK 指令检查成功后变为 healthy,如果连续一定次数失败,则会变为 unhealthy。
  • HEALTHCHECK 支持下列选项:
--interval=<间隔>:两次健康检查的间隔,默认为 30 秒;
--timeout=<时长>:健康检查命令运行超时时间,如果超过这个时间,本次健康检查就被视为失败,默认 30 秒;
--start-period=<间隔>:第一次检查检查的间隔,默认为 0 秒;
--retries=<次数>:当连续失败指定次数后,则将容器状态视为 unhealthy,默认 3 次。

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

在 HEALTHCHECK [选项] CMD 后面的命令,格式和 ENTRYPOINT 一样,分为 shell 格式,和 exec 格式。

  • 命令的返回值决定了该次健康检查的成功与否:
0:成功;
1:失败;
2:保留,不要使用这个值。
  • 例如:
HEALTHCHECK --interval=5s --timeout=3s --start-period=3s \
	CMD curl -f http://localhost/ || exit 1

ARG

语法形式: ARG <name>[=<default value>]
ARG和ENV效果类似,都是用来设置观景变量的。唯一 不同的是dockerfile中的ARG编译好后是不会出现在打开的容器内的。

ARG在dockerfile中创建一个全局参数,参数可以给定一个默认值,在编译时可以传参对其进行覆盖。如果ARG指令有默认值并且在构建期间没有接收到参数、则使用默认值。一个dockerfile中可以包含多个ARG参数。
docker build --build-arg <varname>=<value>

可以使用ARG或ENV指令来指定RUN指令可用的变量,如果ARG和ENV同时指定了一个相同名称的变量、则ENV设置的变量会覆盖ARG设置的变量。如下:

FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER v1.0.0
RUN echo $CONT_IMG_VER


## 使用 docker build --build-arg CONT_IMG_VER=v2.0.1 . 最终输出v1.0.0 。

一个ARG指令的有效范围在其定义的构建阶段内、如果要在多个阶段中都有效、则必须在每个阶段都使用ARG指令;与ARG不同 ENV设置参数的有效期为整个构建期内。

ONBUILD

用于在 Dockerfile 中定义一个触发器

Dockerfile 用于 build 映像文件,此映像文件亦可作为 base image被另一个 Dockerfile 用作 FROM指令的参数,并以之构建新的映像文件

在后面的这个 Dockerfile 中的 FROM 指令在 build过程中被执行时,将会“ 触发” 创建其 base image 的 Dockerfile 文件中的 ONBUILD指令定义的触发器

Syntax
    ONBUILD <INSTRUCTION>

尽管任何指令都可注册成为触发器指令,但 ONBUILD不能自我嵌套,且不会触发 FROM 和 MAINTAINER 指令

使用包含 ONBUILD 指令的 Dockerfile 构建的镜像应该使用特殊的标签,例如 ruby:2.0-onbuild

在 ONBUILD 指令中使用 ADD 或 COPY指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败

实践

  • 变量生产nginx配置文件,并且启动时能修改此配置
Dockerfile

FROM nginx:1.14-alpine
LABEL maintainer="evescn"

ENV NGX_DOC_ROOT='/data/web/html'

ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/

EXPOSE 80/tcp

HEALTHCHECK --start-period=3s \
	CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/

CMD ["/usr/sbin/nginx","-g","deamon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
# vim entrypoint.sh

#!/bin/sh
#
cat > /etc/nginx/conf.d/www.conf << EOF
server {

	server_name ${HOSTNAME};
	listen ${IP:-0.0.0.0}:${PORT:-80};
	root ${NGX_DOC_ROOT:-/usr/share/nginx/html};
}
EOF

exec "$@"

# chmod a+x entrypoint.sh
# echo “test page” > ./index.html
# docker build -t evescn_nginx:v1 ./

# docker run --name myweb1 --rm -P -e "PORT=8080"  evescn_nginx:v1
posted @ 2020-04-28 17:46  evescn  阅读(177)  评论(0编辑  收藏  举报