Dockerfile
概述
1、Docker 可以通过读取 Dockerfile 中的指令自动构建镜像
2、Dockerfile 是一个文本文件,它包含了用户可以在命令行上调用的所有命令,以组装一个镜像
3、构建步骤
(1)编写 Dockerfile 文件
(2)docker build 构建镜像
(3)docker run 根据镜像运行容器
4、Dockerfile 内容
(1)每条保留字指令都必须为大写字母,且至少跟随一个参数
(2)指令按从上到下顺序执行
(3)# 表示注释
(4)每条指令都会创建一个新镜像,并提交镜像
5、Docker 执行 Dockerfile 流程
(1)docker 根据基础镜像,运行一个容器
(2)执行一条指令,并修改容器
(3)执行类似 docker commit 操作,提交一个新镜像层
(4)docker 基于(3)的新镜像层,运行一个容器
(5)执行 Dockerfile 下一条指令,直到所有指令执行完成
.dockerignore 文件
规则 | 行为 |
# comment | 注释 |
*/temp* |
排除根目录下任何直接子目录中名称以 temp 开头的文件和目录。例如:普通文件 /somedir/temporary.txt 被排除在外,目录 /somedir/temp 也是如此
|
*/*/temp* |
将以 temp 开头的文件和目录排除在根目录下两层的任何子目录之外。例如,/somedir/subdir/temporary.txt 被排除
|
temp? |
排除根目录中名称为 temp 一个字符扩展名的文件和目录。例如:/tempa 和 /tempb 被排除在外
|
FROM
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
1、FROM 指令初始化一个新的构建阶段,并为后续指令设置基础镜像。因此,一个有效的 Dockerfile 必须以 FROM 指令开始。镜像可以是任何有效的镜像,从公共资源库中抽取一个镜像开始是特别容易的
(1)ARG 是 Dockerfile 中唯一可以在 FROM 之前的指令
(2)FROM 可以在一个 Dockerfile 中多次出现,以创建多个镜像,或将一个构建阶段作为另一个的依赖。在每条新的 FROM 指令之前,只需记下提交所输出的最后一个镜像 ID。每条 FROM 指令都会清除之前指令创建的任何状态
(3)可以通过在 FROM 指令中添加 AS name 来给新的构建阶段起一个名字。这个名字可以在随后的 FROM 和 COPY --from=<name> 指令中使用,以指代在这个阶段建立的镜像
(4)tag 或 digest 的值是可选的。如果省略了其中任何一个,构建器默认会假定一个最新的标签。如果构建器找不到 tag 值,就会返回一个错误
2、可选的 --platform 标志可以用来指定镜像的平台,以防 FROM 引用一个多平台的镜像。例如,linux/amd64,linux/arm64,或 windows/amd64。默认情况下,会使用构建请求的目标平台。全局构建参数可以用在这个标志的值中,例如 automatic platform ARG 允许强制一个阶段为本地构建平台(--platform=$BUILDPLATFORM),并使用它来交叉编译到阶段内的目标平台
3、ARG 和 FROM 交互
(1)FROM 指令支持在第一个 FROM 指令之前出现的任何 ARG 指令所声明的变量
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD /code/run-app
FROM extras:${CODE_VERSION}
CMD /code/run-extras
(2)在 FROM 之前声明的 ARG 是在构建阶段之外的,所以它不能在 FROM 之后的任何指令中使用。要使用在第一个 FROM 之前声明的 ARG 的缺省值,请在构建阶段内使用没有值的 ARG 指令
ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version
RUN
1、shell 格式
(1)该命令在 shell 中运行,在 Linux 中默认为 /bin/sh -c,在 Windows 中默认为 cmd /S /C
RUN <command>
(2)shell 格式的默认 shell 可以用 SHELL 命令来改变
(3)在 shell 形式中,可以使用 \(反斜杠)将一条 RUN 指令延续到下一行
RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'
#等价于
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
2、exec 格式
RUN ["executable", "param1", "param2"]
(1)exec 格式使得避免 shell 字符串混淆成为可能,并且可以使用不包含指定 shell 可执行文件的基础镜像来 RUN 指令
(2)要使用一个不同的 shell,而不是 /bin/sh,请使用 exec 格式,输入想要的 shell
RUN ["/bin/bash", "-c", "echo hello"]
(3)exec 格式被解析为 JSON 数组,这意味着必须在单词周围使用双引号("),而不是单引号(')
(4)与 shell 格式不同,exec 格式不调用命令 shell,这意味着正常的 shell 处理不会发生。例如:RUN [ "echo", "
(5)在 JSON 中,有必要转义反斜线。这在Windows上尤其重要,因为反斜杠是路径分隔符。否则,下面这一行会因为不是有效的 JSON 而被视为 shell 形式,并以一种意外的方式失败
#错误格式
RUN ["c:\windows\system32\tasklist.exe"]
#正确格式
RUN ["c:\\windows\\system32\\tasklist.exe"]
3、RUN 指令将在当前镜像之上的新层中,执行任何命令并提交结果,提交后的镜像将被用于 Dockerfile 的下一个步骤
4、分层的 RUN 指令和生成的提交符合 Docker 的核心概念,即提交很便宜,容器可以从镜像历史上的任何一点创建,很像源代码控制
5、RUN 指令的缓存在下次构建时不会自动失效
(1)像 RUN apt-get dist-upgrade -y 这样的指令的缓存会在下次构建时被重新使用
(2)RUN 指令的缓存可以通过使用 --no-cache 标志来失效,例如:docker build --no-cache
6、RUN 指令的缓存可以通过 ADD 和 COPY 指令失效
CMD
1、格式
(1)exec 格式,这是首选格式
CMD ["executable","param1","param2"]
(2)作为 ENTRYPOINT 的默认参数
CMD ["param1","param2"]
(3)shell 格式
CMD command param1 param2
2、一个 Dockerfile 中只能有一条 CMD 指令,如果列出一个以上的 CMD,那么只有最后一个 CMD 会生效
3、CMD 的主要目的是为执行中的容器提供默认值
(1)这些默认值可以包括一个可执行文件,也可以省略可执行文件,在这种情况下,必须同时指定一个 ENTRYPOINT 指令
(2)如果 CMD 被用来为 ENTRYPOINT 指令提供默认参数,那么 CMD 和 ENTRYPOINT 指令都应该用 JSON 数组格式指定
(3)如果希望容器每次都运行相同的可执行文件,那么应该考虑将 ENTRYPOINT 与 CMD 结合使用
4、如果用户为 docker run 指定参数,那么它们将覆盖 CMD 中指定的默认值
5、注意
(1)RUN 在 docker build 时运行,实际上是 run 一个命令并 commit 结果
(2)CMD 在 docker run 时运行,在 build 时不执行任何东西,而是为镜像指定预期的命令
LABEL
LABEL <key>=<value> <key>=<value> <key>=<value> ...
1、LABEL 指令将元数据添加到一个镜像上
2、一个 LABEL 是一个键值对
3、要在 LABEL 值中包含空格,请使用双引号和反斜线
4、一个镜像可以有一个以上的标签
LABEL multi.label1="value1" multi.label2="value2" other="value3"
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
MAINTAINER(已废弃)
1、MAINTAINER 指令设置生成的镜像的作者字段
2、LABEL 指令是一个更灵活的版本,因为它可以设置任何你需要的元数据,并且可以很容易地被查看,例如:docker inspect
EXPOSE
EXPOSE <port> [<port>/<protocol>...]
1、EXPOSE 指令通知 Docker,容器在运行时监听指定的网络端口
(1)可以指定端口监听的是 TCP 还是 UDP
(2)如果没有指定协议,默认是 TCP
2、EXPOSE 指令实际上并没有发布端口
(1)作用:作为构建镜像的人和运行容器的人之间的一种文件,说明哪些端口打算被发布
(2)要在运行容器时实际发布端口,可以使用 docker run 上的 -p 来发布和映射一个或多个端口,或者使用 -P 来发布所有暴露的端口并将它们映射到随机端口
(3)不管 EXPOSE 设置如何,可以在运行时通过使用 -p 来覆盖它们
ENV
ENV <key>=<value> ...
1、ENV 指令将环境变量 <key> 设置为 <value> 的值
(1)这个值将在构建阶段的所有后续指令的环境中出现,也可以在许多指令中被内联替换
(2)该值将被解释为其他环境变量,所以引号字符如果没有被转义,将被删除
(3)像命令行解析一样,引号和反斜线可以用来在值中包含空格
2、ENV 指令允许一次设置多个 <key>=<value>... 变量
ADD
ADD [--chown=<user>:<group>] [--checksum=<checksum>] <src>... <dest>
#此格式对于含有空白的路径是必须的
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
1、--chown 功能只支持用于构建 Linux 容器的 Dockerfiles,在 Windows 容器上无法工作
2、ADD 指令从 <src> 复制新的文件、目录或远程文件 URL,并将其添加到路径 <dest> 的镜像文件系统中
(1)可以指定多个 <src> 资源,但如果它们是文件或目录,它们的路径将被解释为相对于构建上下文的源
(2)每个 <src> 都可以包含通配符
(3)<dest> 是一个绝对路径,或者一个相对于 WORKDIR 的路径,源文件将被复制到目标容器内
3、ADD 遵守以下规则
(1)<src> 路径必须在构建的上下文中;不能 ADD .../something /something,因为 docker 构建的第一步是将上下文目录(和子目录)发送给 docker 守护程序
(2)如果 <src> 是一个 URL,而 <dest> 不是以尾部斜线结尾,那么就会从 URL 下载一个文件并复制到 <dest>
(3)如果 <src> 是一个 URL,而 <dest> 确实以尾部斜线结尾,那么文件名将从 URL 推断出来,文件将被下载到 <dest>/<filename>
#URL必须有一个非简单的路径,以便在这种情况下可以发现一个适当的文件名(http://example.com 将不工作)
#将创建文件 /foobar
ADD http://example.com/foobar /
(4)如果 <src> 是一个目录,该目录的全部内容被复制,包括文件系统元数据,目录本身不被复制,只是其内容被复制
(5)如果 <src> 是一个公认的压缩格式(identity、gzip、bzip2 或 xz)的本地 tar 档案,那么它将被解压为一个目录。来自远程 URL 的资源不会被解压。当一个目录被复制或解压时,它的行为与 tar -x 相同
(6)一个文件是否被识别为公认的压缩格式,完全基于文件的内容,而不是文件的名字
(7)如果 <src> 是任何其他类型的文件,它和它的元数据一起被单独复制。在这种情况下,如果 <dest> 以尾部斜线 / 结尾,它将被视为一个目录,<src> 的内容将被写在 <dest>/base(<src>)
(8)如果直接指定了多个 <src> 资源,或者由于使用了通配符,那么 <dest> 必须是一个目录,而且必须以斜线 / 结尾
(9)如果 <dest> 没有以斜线结尾,它将被视为一个普通文件,<src> 的内容将被写入 <dest>
(10)如果 <dest> 不存在,它将和其路径中所有丢失的目录一起被创建
COPY
COPY [--chown=<user>:<group>] <src>... <dest>
#此格式对于含有空白的路径是必须的
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
1、--chown 功能只支持用于构建 Linux 容器的 Dockerfiles,在 Windows 容器上无法工作
2、COPY 指令从 <src> 复制新的文件或目录,并将它们添加到容器的文件系统中,路径为 <dest>
(1)可以指定多个 <src> 资源,但是文件和目录的路径将被解释为与构建的上下文的源头相对
(2)每个 <src> 可以包含通配符
(3)<dest> 是一个绝对路径,或者一个相对于 WORKDIR 的路径,源文件将被复制到目标容器内
3、COPY 遵守以下规则
(1)<src> 路径必须在构建的上下文中,不能 COPY .../something /something,因为 docker 构建的第一步是将上下文目录(和子目录)发送到 docker 守护进程
(2)如果 <src> 是一个目录,该目录的全部内容都会被复制,包括文件系统元数据,目录本身不被复制,只是其内容
(3)如果 <src> 是任何其他类型的文件,它和它的元数据一起被单独复制,在这种情况下,如果 <dest> 以尾部斜线 / 结尾,它将被视为一个目录,<src> 的内容将被写在 <dest>/base(<src>)
(4)如果直接指定了多个 <src> 资源,或者由于使用了通配符,那么 <dest> 必须是一个目录,而且必须以斜线 / 结尾
(5)如果 <dest> 没有以斜线结尾,它将被视为一个普通文件,<src> 的内容将被写入 <dest>
(6)如果 <dest> 不存在,它将和其路径中所有丢失的目录一起被创建
ENTRYPOINT
1、格式
(1)exec 格式(建议)
ENTRYPOINT ["executable", "param1", "param2"]
(2)shell 格式
ENTRYPOINT command param1 param2
2、一个 ENTRYPOINT 允许配置一个将作为可执行文件运行的容器
3、只有 Docker 文件中的最后一条 ENTRYPOINT 指令才会有效果
4、类似 CMD,但 ENTRYPOINT 不会被 docker run 后面的命令覆盖,且作为 ENTRYPOINT 指定程序的参数
5、在执行 docker run 时可以指定 ENTRYPOINT 运行所需参数
6、ENTRYPOINT 可与 CMD 一起使用
(1)一般是变参才会使用 CMD,CMD 相当于在给 ENTRYPOINT 传参
(2)当指定 ENTRYPOINT 后,CMD 不再是直接运行其命令,而是将 CMD 内容作为参数,传递给 ENTRYPOINT 指令,组合为 <ENTRYPOINT> "<CMD>"
VOLUME
VOLUME ["/data"]
1、VOLUME 指令以指定的名称创建一个挂载点,并将其标记为持有来自本地主机或其他容器的外部挂载卷
(1)该值可以是一个 JSON 数组,VOLUME ["/var/log/"]
(2)或者是一个有多个参数的普通字符串,比如VOLUME /var/log 或 VOLUME /var/log /var/db
2、docker run 命令用基本镜像中指定位置存在的任何数据来初始化新创建的卷
#这个Dockerfile会产生一个镜像,使docker run在/myvol创建一个新的挂载点,并将问候文件复制到新创建的卷中
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
USER
USER <user>[:<group>]
USER <UID>[:<GID>]
1、USER 指令设置用户名(或 UID)和可选的用户组(或 GID),作为当前阶段剩余时间的默认用户和组
(1)指定的用户用于 RUN 指令
(2)在运行时,运行相关的 ENTRYPOINT 和 CMD 指令
(3)注意,当为用户指定一个组时,用户将只拥有指定的组成员资格
2、当用户没有主组时,那么该镜像(或下一个指令)将以 root 组运行
WORKDIR
WORKDIR /path/to/workdir
1、WORKDIR 指令为 Dockerfile 中的任何 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令设置工作目录
2、如果 WORKDIR 不存在,它将被创建,即使它没有在任何后续的 Dockerfile 指令中使用
3、WORKDIR 指令可以在一个 Dockerfile 中多次使用
4、如果提供了一个相对路径,它将是相对于前一个 WORKDIR 指令的路径
#这个Dockerfile中最后一条pwd命令的输出是/a/b/c
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
5、WORKDIR 指令可以解决之前用 ENV 设置的环境变量,只能使用在 Dockerfile 中明确设置的环境变量
#这个Dockerfiel中最后一条pwd命令的输出是/path/$DIRNAME
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
(1)如果没有指定,默认的工作目录是 /
(2)在开发中,如果不是从头开始构建一个 Dockerfile(FROM scratch),那么 WORKDIR 可能会被所使用的基础镜像所设置
(3)因此,为了避免在未知目录中进行非预期的操作,最好的做法是明确设置 WORKDIR
ARG
ARG <name>[=<default value>]
1、ARG 指令定义了一个变量,用户可以在构建时通过 docker build 命令使用 -build-arg <varname>=<value> 标记传递给构建器
2、如果用户指定的构建参数没有在 Dockerfile 中定义,构建时就会输出一个警告
3、一个 Dockerfile 可以包括一个或多个 ARG 指令
ONBUILD
ONBUILD <INSTRUCTION>
1、ONBUILD 指令为镜像添加了一条 trigger 指令,在以后的时间里,当该镜像被用作另一个构建的基础时,将被执行
2、trigger 将在下游构建的上下文中执行,就像它在下游 Dockerfile 中的 FROM 指令之后被立即插入一样
3、任何构建指令都可以被注册为一个 trigger
4、如果正在构建一个镜像,并将其作为构建其他镜像的基础,例如:一个应用程序的构建环境或一个可通过用户特定配置进行定制的守护程序,那么这就非常有用
STOPSIGNAL
STOPSIGNAL signal
1、STOPSIGNAL 指令设置将被发送到容器中退出的系统调用信号
(1)这个信号可以是格式为 SIG<NAME> 的信号名称,例如 SIGKILL
(2)也可以是一个无符号的数字,与内核的系统调用表中的一个位置相匹配,例如 9
(3)如果没有定义,默认是 SIGTERM
2、镜像的默认停止信号可以被每个容器覆盖,使用 docker run 和 docker create 的 -stop-signal 标志
HEALTHCHECK
#通过在容器内运行一个命令来检查容器的健康状况
HEALTHCHECK [OPTIONS] CMD command
#禁用从基本镜像继承的任何健康检查
HEALTHCHECK NONE
1、HEALTHCHECK 指令告诉 Docker 如何测试一个容器以检查它是否仍在工作。这可以检测到一些情况,比如:网络服务器陷入了无限循环,无法处理新的连接,尽管服务器进程仍在运行
2、当一个容器被指定了健康检查时,除了 normal 状态外,它还有一个 healthy 状态
(1)状态最初是 starting
(2)每当健康检查通过时,它就会变成 healthy 状态(不管它以前是什么状态)
(3)在连续失败一定次数后,它就会变成 unhealthy 状态
3、CMD 选项
(1)-interval=DURATION(默认:30s)
(2)--timeout=DURATION(默认:30s)
(3)--start-period=DURATION(默认: 0s)
(4)--retries=N(默认: 3)
4、健康检查将在容器启动后的 interval 秒内首次运行,然后在之前的每次检查完成后的 interval 秒内再次运行
5、如果一次检查的时间超过了 timeout 秒,那么检查将被视为失败
6、容器需要连续 retries 健康检查失败才会被认为是不健康的 unhealthy
7、start period 为需要时间来启动的容器提供了初始化时间。该期间的探测失败将不被计入最大重试次数。然而,如果在启动期间健康检查成功,则容器被视为已启动,所有连续的失败将被计入最大重试次数
8、一个 Docker 文件中只能有一条 HEALTHCHECK 指令,如果列出了多条,那么只有最后一条 HEALTHCHECK 才会生效
9、CMD 关键字后面的命令可以是一个 shell 命令(比如:HEALTHCHECK CMD /bin/check-running),也可以是一个 exec 数组
10、该命令的退出状态表示容器的健康状态
(1)0:成功,容器是健康的,可以使用
(2)1:不健康,容器不能正常工作
(3)2:保留,不要使用这个退出代码
SHELL
SHELL ["executable", "parameters"]
1、SHELL 指令允许覆盖用于命令的 shell 格式的默认 shell
(1)Linux 上的默认 shell 是 ["/bin/sh", "-c"]
(2)在 Windows 上是 ["cmd", "/S", "/C"]
(3)SHELL 指令必须以 JSON 形式写在 Dockerfile 中
2、SHELL 指令在 Windows 上特别有用,因为在 Windows 上有两个常用的、完全不同的本地 shell: cmd 和 powerhell,以及包括 sh 在内的其他 shell
3、SHELL 指令可以出现多次,每条 SHELL 指令都会覆盖所有之前的 SHELL指令,并影响所有后续指令
4、当 Dockerfile 中使用 SHELL 指令的形式时,以下指令会受到 SHELL 指令的影响:RUN、CMD 和 ENTRYPOINT
docker build
1、从 Dockerfile 建立一个镜像
docker build [OPTIONS] PATH | URL | -
2、描述
(1)docker build 命令从一个 Dockerfile 和一个 context 中构建 Docker 镜像
(2)构建的上下文是位于指定的 PATH 或 URL 中的一组文件
(3)构建过程可以引用上下文中的任何文件。例如:构建可以使用 COPY 指令来引用上下文中的一个文件
(4)URL 参数可以指代三种资源:Git 仓库、预先打包的 tarball 上下文、纯文本文件
虚悬镜像(dangling image)
1、仓库名、标签为 <none> 的镜像
2、查询显示虚悬镜像
docker images ls -f dangling=true
3、删除虚悬镜像
docker rmi $(docker images -q -f dangling=true)
docker image prune [OPTIONS]
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战