Dockerfile

发布于:2025-04-15 ⋅ 阅读:(81) ⋅ 点赞:(0)

Dockerfile

Dockerfile 是一个文本文件,其内包含了一条条指令,每一条指令构建镜像的一层,因此每一条指令的内容,就是描述该层应当如何构建。 定制镜像,可以将镜像制作的每一层的修改、安装、构建、操作的命令,都写入 Dockerfile 中,使用 Dockerfile 来构建、定制镜像。Dockerfile 相比于快照方法制作镜像,具有方便自动化构建、维护修改,二次开发方便、更加标准化的优点。

快照方法(docker commit)制作的镜像,需要手动一个命令一个命令执行,其制作过程不可考,因此生成的镜像又称为黑箱镜像,制作步骤比较繁琐,维护起来较麻烦,也难以进行二次开发。

在制作 Dockerfile 时,要尽量将不变的因素放在前面,易变化的因素放在后面。如为了减镜像的实际大小,我们往往会在镜像里安装 gcc,当 gcc 编译完代码文件后就删除 gcc,来释放空间。代码文件是易变化的文件,如果将 COPY 代码的指令放在 ADD gcc 指令的前面,由于 Dockerfile 是逐条构建,每次更改代码文件都需要重新安装和删除 gcc,造成镜像构建时间变长。但如果我们将 COPY 代码的指令放在 ADD gcc 指令的前面,由于镜像构建时会查找可用的缓存,即不需要重新安装 gcc 就可以重新编译代码,使得镜像构建时间大大缩短。

1. docker build

docker build 命令用于使用 Dockerfile 创建镜像。有三种语法:上下文构建(path),使用某个 Docerfile 构建;网络构建(URL),连接某个主机使用其 Dockerfile 构建;通过标准输入构建(-),可以指定 Docerfile 或 tar 文件。

语法:

docker build [options] [path]

docker build [options] [URL]

docker build [options] [-]

选项:

  • –build-arg=[]: 设置镜像创建时的变量。
  • -f: 设定要使用的 Dockerfile 路径。
  • –label=[]: 设置镜像使用的元数据。
  • –no-cache: 创建镜像的过程中不使用缓存(即不使用引用的方法,重新构建每一层)。
  • –pull: 尝试更新镜像的新版本。
  • -q,–quiet: 安静模式,成功后只输出镜像 ID。
  • -t,–tag: 镜像的名字及标签。
  • –network: 默认使用,在构建期间设置 RUN 指令的网络模式。

示例:

docker build -t myimage:1.0.0 .

docker build -t myimage:1.0.0 https://127.0.0.1/Dockerfile

docker build -t myimage:1.0.0 - < Dockerfile

2. .dockerignore文件

.dockerignore 文件可以标记在执行 docker build 时忽略的路径和文件,避免发送不必要的数据内容,从而加快整个镜像创建的过程。使用方法简单,只需要在其中添加需要忽略的文件的路径和名字即可,支持通配符。

*.txt

表示忽略所有后缀名为 .txt 的文件。

3. Dockerfile指令

Dockerfile 的指令不区分大小写,但是为了将其于一般的命令和参数区分开来,约定俗成使用大写,Dockerfile 的注释符号为 # 且必须在行首使用才会被识别为注释,行中其他地方出现 # 都会被视为参数。

FROM

FROM 用于指定镜像文件构建过程中的基础镜像,后续的指令运行于此基础镜像所提供的运行环境。因此,FROM 必须是 Dockerfile 中非注释行或者 ARG 之后的第一个指令FROM 可以在一个 Dokerfile 里多次出现,即可以使用一个 Dockerfile 创建多个镜像,或者将一个构建阶段作为另一个的依赖。如果 FROM 语句没有指定镜像标签,则默认使用 latest 标签。

默认情况下,docker build 会在 docker 主机上查找指定的镜像文件,如果本地不存在该镜像,则会自动从 Docker 的公共库 pull 镜像下来,如果还是找不到指定的镜像文件,docker build 会返回一个错误信息。

语法:

FROM [--platform=<platform>] <image> [AS <name>]

FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]

FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]

参数:

  • <platform>: 构建的 cpu 架构,如 linux/amd64linux/arm64
  • <image>: 指定作为 base image 的名称。
  • <tag>: base image 的标签,省略时默认 latest。
  • <digest>: 镜像的哈希码。
  • AS <name>: 指定构建步骤的名称,配合 COPY --from=<name> 可以完成多级构建。

示例:

FROM nginx:latest

LABEL

用于为镜像添加元数据,元数据是键值对的形式。使用 docker inspect 可以查看信息。

语法:

LABEL <key>=<value> <key>=<value>...

示例:

LABEL author="laimaxgg"

COPY

用于从 docker 主机复制新文件或者目录到创建的新镜像指定路径中。

语法:

COPY [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src>",..."<dest>"]

参数:

  • –chown: 修改用户和组。
  • <src>: 要复制的源文件或目录,支持使用通配符 *
  • <dest>: 目标路径,即正在创建的 iamge 的文件系统路径。建议使用绝对路径,否则 COPY 将指定以 WORKDIR 为当前路径。
  • –from <name>: 可选项,可以从之前构建的步骤中拷贝内容,往往用于多级构建中。

注意:

<src> 必须是 build 上下文中的路径,不能是其父目录中的文件。

如果 <src> 是目录,则其内部文件或子目录会被递归复制,但 <src> 目录自身不会被复制。

如果指定了多个 <src> ,或在 <src> 使用了通配符,则 <dest> 必须是一个目录,且必须以 / 结尾。

如果 <dest> 事先不存在,它将会被自动创建,包括它的父目录路径。

示例:

COPY index,html /data/web/html

ENV

用于为镜像定义所需的环境变量,并可被 Dockerfile 文件中位于其后的其他指令(如 ENVADDCOPY)调用。调用时使用 $env_name${env_name} 调用。

语法:

ENV <key>=<value> ...

示例:

ENV env_val1="1"

WORKDIR

用于为 Dockerfile 中所有 RUNCMDENTRYPOINTCOPYADD 指定设定工作目录。

语法:

WORKDIR /a/b/c

注意:

WORKDIR 的默认路径是 / ,且支持多次定义,定义时,如果没有重新从 / 开始指定,则会将前一条 WORKDIR 指令的路径视为父目录,如:

WORKDIR /a
WORKDIR b
WORKDIR c

最终的 WORKDIR/a/b/c

ADD

类似于 COPY 指令,但是 ADD 支持使用 tar 文件和 URL 路径,会自动完成解压和下载。

语法:

ADD [--chown=<user>:<group>] <src>... <dest>

ADD [--chown=<user>:<group>] ["<src>",..."<dest>"]

路径中包含空格字符时,一般使用第二种格式。

RUN

用于 docker build 过程中运行的程序,其可以是任何命令。RUN 指令有两种格式。

语法:

#shell格式
RUN [command]

#exec格式
RUN ["executable","param1","param2"]
  • shell 格式中, [command] 通常是一个 shell 命令,且以 /bin/sh -c 来运行,如果一个脚本 test.sh 不能自己运行,就必须要使用 /bin/sh -c test.sh 的方式来执行,如果使用 shell 格式,最后的指令相当于:

    /bin/sh -c "/bin/sh -c 'test.sh'"
    
  • exec 格式中的参数是一个 JSON 格式的数组,其中 executable 为要运行的命令,后面的 paramN 为要传递给命令的选项或参数。但是这种格式指定的命令不会以 /bin/sh -c 来发起,因此常见的 shell 操作如变量替换以及通配符(?,* 等)都将不会进行。不过,如果要运行的命令依赖于此 shell 特性的话,可以使用以下格式:

    RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
    

示例:

ENV WEB_SERVER_PACKAGE nginx-1.21.1.tar.gz
RUN cd ./src && tar -xf ${WEB_SERVER_PACKAGE}

CMD

类似于 RUNCMD 指令用于运行任何命令或应用程序,但两者运行的时间点不同。RUN 指令运行于镜像文件构建过程中,而 CMD 指令运行于基于 Dockerfile 构建出的新镜像文件启动一个容器时。 因此,CMD 指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止

CMD 指定的命令可以被 docker run 命令的选项所覆盖,在 Dockerfile 中也可以存在多个 CMD 指令,但最终只会生效最后一个。

语法:

#exec格式
CMD ["executable","param1","param2"]

#ENTRYPOINT指令默认参数
CMD ["param1","param2"]

#shell格式
CMD command param1 param2

注意:

  • 第二种格式用于为 ENTRYPOINT 指令提供默认参数。

  • json 数组中,要使用 "" 双引号,单引号会出错。

示例:

CMD ["/user/bin/wc","--help"]

EXPOSE

用于为容器声明打开指定要监听的端口以实现于外部通信。但 EXPOSE 并不会发布端口,它只是充当构建图像的人和运行容器的人之间的一种文档,即如果要让容器暴露端口,还是需要使用 -p 参数。

语法:

EXPOSE <port>
EXPOSE <port>/<protocol>

参数:

<port>: 端口。

<protocol>: tcp/udp 协议。

示例:

EXPOSE 80/tcp

ENTRYPOINT

用于指定容器的启动入口。如果是 CMD 是可以被覆盖的,如果是 ENTRYPOINT 则不能被覆盖。定义了 ENTRYPOINT 会将命令作为参数传给程序。

语法:

#exec格式
ENTRYPOINT ["executable","param1","param2"]

#shell格式
ENTRYPOINT command param1 param2

注意,json 数组中要使用 "" 双引号,单引号会出错。

示例:

ENTRYPOINT ["nginx","-g","daeom off;"]

ARG

类似于 ENVARG 用于在 Dockerfile 里定义一个变量,但不同是 ENV 的是,用户可以在构建时使用 docker build --build-arg <varname>=<val> 对变量进行修改,而 ENV 不能。

语法:

ARG <name>[=<default value>]

注意:

  • Dockerfile 可以包含一个或多个 ARG 指令。
  • ARG 支持指定默认值。
  • ARGdocker build 后就会失效,一般用于控制镜像的版本,如通过 --build-arg 更改 Dockerfile 默认的 ARG 控制的 Ubuntu 版本号,实现在外部切换镜像制作出来的版本。

示例:

ARG CONT_IMG_VER=v1.0.0

在外部更改值:

docker build --build-arg CONT_IMG_VER=v2.0.0

VOLUME

用于在镜像中创建一个挂载点目录。通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的名字,属于匿名卷。

语法:

VOLUME <moutpoint>
VOLUME ["<moutpoint>"]

注意:

  • 如果挂载点目录路径下此前有文件存在,docker run 命令会在卷挂载完成后将此前的所有文件复制到新挂载的卷中。
  • VOLUME 指令只是声明了容器中的目录作为匿名卷,但是并没有将匿名卷绑定到宿主机指定目录的功能。 VOLUME 只是指定了一个目录,用于在用户启动时忘记指定 -v 选项也可以保证容器正常运行,即使用户没有指定 -v ,容器被删除后也不会导致数据文件被删除。VOLUME-v 一样,容器被删除以后映射在主机上的文件不会被删除。
  • 如果 -vVOLUME 指定了同一个位置,会以 -v 设定的目录为准。

示例:

VOLUME ["/data1","/data2"]

SHELL

SHELL 指令允许覆盖用于 shell 命令形式的默认 shell。Linux 上的默认 shell 是 ["/bin/sh","-c"] ,在 Windows 上是 ["cmd","/S","/C"]SHELL 指令必须以 JSON 格式写入 Dockerfile 中。

语法:

SHEL ["executable","parameters"]

注意:

  • SHELL 指令在 Linux 上使用较少,但在 Windows 上特别有用,因为 Windows 有两种不同的 shell(cmd 和 powershell)。

USER

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

语法:

USER <user>:<group>
USER <UID>:<GID>

参数:

  • <user>: 用户
  • <group>: 用户组
  • <UID>: 组 id
  • <GID>: 组 id

示例:

USER docker:docker

HEALTHCHECK

用于告诉 Docker 如何测试容器以检查它是否仍在工作。即使服务器进程仍在运行,也可以检测出陷入无限循环且无法处理新连接的 Web 服务器等情况。

语法:

HEALTHCHECK [options] CMD command
HEALTHCHECK NONE

参数:

  • [options] 有:
    • –interval=DURATION(default:30s): 每隔多长时间探测一次,默认 30 秒。
    • –timeout=DURATION(default:30s): 服务响应超时时长,默认 30 秒。
    • –start-period=DURATION(default:0s): 服务启动多久后开始探测,默认 0 秒。
    • –retres=N(default:3): 认为检测失败几次为宕机,默认 3 次。
  • 返回值:
    • 0 :容器是健康的,随时可以使用。
    • 1:容器不健康,无法正常工作。
    • 2:保留不使用此退出码。

示例:

HEALTHCHECK --interval=5m --timeout=3s CMD curl -f https://localhost/ || exit 1

ONBUILD

用于在 Dockerfile 中定义一个触发器。以该 Dockerfile 中的作为基础镜像由 FROM 指令在 build 过程中被执行时,将会触发创建其 base iamge 的 Dockerfile 文件中的 ONBULD 指令定义的触发器。

语法:

ONBUILD <instruction>

参数:

  • <instruction>: Dockefile 的一条指令。

示例:

ONBUILD ADD ./app/src

STOPSIGHAL

用于设置将发送到容器的系统调用信号,即设置 docker stop 时触发的信号。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数。

语法:

STOPSIGNAL signal

示例:

STOPSIGNAL 9

4. CMD和ENTRYPOINT的组合使用

CMDENTRYPOINT 在 Dockerfile 里是两个功能十分相近的指令,但 Docker 官方实际更希望我们组合使用这两个指令。

4.1 CMD和ENTRYPOINT的异同

相同点:

  • Dockerfile 里含有多条CMDENTRYPOINT 命令时,后面的 CMDENTRYPOINT 会覆盖前一条指令,最终只生效一条。

    CMD echo "123"
    CMD echo "456"
    

    最终 echo "456" 有效,ENTRYPOINT 同理。

  • CMDENTRYPOINT 都支持 shell 和 exec 格式。当使用 shell 格式时,命令行程序作为 sh 程序的子程序运行,docker 用 /bin/sh -c 的语法调用,如果用 docker ps 命令查看运行的 docker,就可以看出我们启动的程序的 PID 不是 1,由于 /bin/sh 命令不会转发消息给实际运行的命令,所以从外部发送任何 POSIX 信号到 docker 容器中都不能安全的关闭 docker 容器;exec 格式直接运行提供的命令,命令进程的 PID 是 1。所以实践中,都强烈推荐使用 exec 格式。

不同点:

  • 使用 docker run 传递参数时会覆盖 CMD 的内容,但 ENTRYPOINT 无法被覆盖,除非使用 --entryopint 选项。
  • 如果 ENTRYOPINT 使用的是 exec 格式,那么 docker run 传递的参数会作为 ENTRYOPINT 的参数(实际是触发了 CMDENTRYPOINT 的组合模式)

特点:

  • ENTRYPOINT 使用 exec 格式时,CMDENTRYPOINT 可触发组合模式

4.2 组合模式

ENTRYPOINT 使用 exec 格式时,CMDENTRYPOINT 可触发组合模式。在组合模式下,当使用 docker run 运行容器时,docker 会将和 ENTRYPOINTCMD 拼接在一起,如:

ENTRYPOINT ["echo"]
CMD ["Hello, Docker!"]

将会拼接成 echo "Hello, Docker!" 。再加上,CMD 可以被 docker run 的参数覆盖,所以实际组合模式是 Docker 官方更推荐的写法。


网站公告

今日签到

点亮在社区的每一天
去签到