dockerfile
Dockerfile 是一个用来构建 Docker 镜像的脚本文件,里面按一定语法规则写好了一系列的指令(instructions),每个指令会执行一个操作,从而逐步构建出一个镜像。
dockerfile的作用
自动化构建镜像:不需要手动安装、配置环境,执行一次 docker build
就能复现相同镜像。
可移植性强:换服务器、换电脑,Dockerfile 还能构建出同样的镜像。
版本可控:和代码一起放在 Git 里,方便回滚和更新。
dokcerfile相关命令
指令(Instruction) | 描述 |
---|---|
ADD |
添加本地或远程文件和目录。 |
ARG |
使用构建时变量。 |
CMD |
指定默认命令。 |
COPY |
复制文件和目录。 |
ENTRYPOINT |
指定默认可执行文件。 |
ENV |
设置环境变量。 |
EXPOSE |
描述应用程序正在侦听哪些端口。 |
FROM |
从基础映像创建新的生成阶段。 |
HEALTHCHECK |
在启动时检查容器的运行状况。 |
LABEL |
将元数据添加到镜像。 |
MAINTAINER |
指定镜像的作者。 |
ONBUILD |
指定在生成中使用映像的说明。 |
RUN |
执行构建命令。 |
SHELL |
设置镜像的默认外壳。 |
STOPSIGNAL |
指定退出容器的系统调用信号。 |
USER |
设置用户和组 ID。 |
VOLUME |
创建卷挂载。 |
WORKDIR |
更改工作目录。 |
ARG
ARG
是 Dockerfile 中唯一可以开在FROM前的指令,ARG可以在构建镜像提供一个dockerfile内部可使用的变量。当ARG在FROM前时,FROM的基础镜像指令可以使用ARG的变量值,若后续没有再次声明该变量,则无法使用FROM前定义的ARG变量,举例如下:
全局变量
1 | ARG VERSION=latest #定义一个版本变量 |
变量传入赋值
1 | FROM ubuntu |
多阶段构建使用变量
1 | ARG CODE_VERSION=latest #定义版本为最新 |
FROM
FROM时构建镜像需要的基础镜像,有效的 Dockerfile 必须以FROM指令开头,该镜像可以是任何有效的镜像,例如docker官方源的,第三方源的,个人的。
多阶段构建:FROM
可以在单个 Dockerfile 中多次出现,以 创建多个映像或使用一个生成阶段作为另一个构建阶段的依赖项。
1 | FROM [--platform=<platform>] <image> [AS <name>] |
使用AS定义镜像作为下一个阶段的可用依赖,在所有阶段完成时,没有使用的镜像将会消失,不会为最终生成镜像产生额外的资源消耗和增大体积,常用于精简和优化镜像体积的方法。例如:
1 | ========== 阶段 1:构建阶段 ========== |
ENV
ENV设置环境变量,这些变量会在 镜像构建阶段 和 容器运行阶段 都生效。
1 | ENV MY_NAME="John Doe" #引号赋值 |
env声明与使用(可配合ARG变量)
1 | FROM ubuntu:22.04 |
ADD
ADD可以从构建上下文(本地目录)复制文件,从远程 URL下载并添加文件,自动解压 tar 压缩包(.tar
, .tar.gz
等),从Git 仓库(实验性功能,需要 BuildKit)拉取文件。
当使用本地 tar 存档作为 的源时,并且存档位于可识别的压缩格式( 或 uncompressed),则存档被解压缩并提取到指定的目标中。只 提取本地 tar 档案。如果tar存档是远程URL,则存档不会被解压,而是下载并放置在目标位置。(支持格式.tar,.tar.gz,.tgz ,.tar,.bz2, .tar.xz)
使用语法:
1 | ADD [OPTIONS] <src> ... <dest> |
ADD使用举例:
1 | ADD file1.txt file2.txt /usr/src/things/ #将两个文件推送到目标路径,最后的参数必须要目标路径 |
COPY
该命令与ADD相似,有些许不同,具体下面讲解。COPY 有两种形式。 对于包含空格的路径,需要后一种形式。
- 如果目标路径不是以前导斜杠开头,则将其解释为相对于构建容器的工作目录(即当前shell路径的相对路径)。
- 如果目标不存在,则会创建它以及所有缺少的目录 在它的路径上。
- 如果源是一个文件,并且目标没有以尾随斜杠结尾,源文件将作为文件写入目标路径。
1 | COPY [OPTIONS] <src> ... <dest> |
多阶段构建容器间引用
1 | COPY file1.txt file2.txt /usr/src/things/ #将两个文件推到指定路径 |
MAINTAINER
MAINTAINER 用于指定镜像的维护作者信息,已被官方弃用,推荐使用下面的LABEL维护镜像作者信息。
1 | MAINTAINER <name> |
LABEL
该指令将元数据以键值对形式添加到镜像中,要在值中包含空格,需要使用引号和反斜杠,使用语法:
MAINTAINER 已被官方弃用,目前使用LABEL标签替换,更加灵活且便洁。
1 | LABEL <key>=<value> [<key>=<value>...] |
举例:
1 | 逐行添加 |
EXPOSE
该指令通知 Docker 容器监听运行时指定的网络端口。您可以指定端口是否侦听 TCP 或 UDP,如果未指定协议,则默认值为 TCP。
1 | EXPOSE <port> [<port>/<protocol>...] |
下面列出了EXPOSE和docker run -p 80:80 的区别
场景 | 结果 |
---|---|
只写 EXPOSE 8080 ,运行不加 -p |
容器 8080 端口仅容器内部可访问 |
写了 EXPOSE 8080 ,运行 -p 80:8080 |
宿主机 80 → 容器 8080 |
不写 EXPOSE ,运行 -p 80:8080 |
一样可以映射,EXPOSE 不是必须的 |
多个 -p 映射同一容器端口 |
后运行的 -p 会报错端口占用 |
WORKDIR
该指令为 Dockerfile 中后面的任何指令设置工作目录,设置在镜像中的当前路径。
该指令可以在 Dockerfile 中多次使用。如果写的是相对路径,它将相对于上一条指令的路径。列如:
1 | WORKDIR /a |
如果未设置工作目录,那么当前的路径会由FROM的基础镜像设置。
USER
为当前构建的镜像设置用户名(或 UID)和可选的用户组(或 GID)用作默认用户和组,用于当前阶段。
1 | USER <user>[:<group>] |
若指定的用户不存在时,需要先创建。(容器里直接创建用户不需要密码交互即可直接使用该身份)
1 | FROM ubuntu:22.04 |
SHELL
该指令用于指定shell形式的解释器,默认使用的/bin/sh,可以切换为/bin/bash。用于解决可能出现不同解释器的命令问题。
1 | SHELL ["/bin/bash", "-c"] |
如果不换成 bash,{1..3}
这种写法 /bin/sh
不支持,会报错。
ENTRYPOINT
该指令允许你将容器配置成像一个可执行文件那样运行,多行ENTRYPOINT只有最后一行生效
1 | exec格式,推荐使用,可以避免shell转义错误的情况 |
ENTRYPOINT在运行容器时不会被显示的替换,如果需要替换需要docker run –entrypoint来指定的替换命令。
无入口点 | 入口点exec_entry p1_entry(shell格式) | 入口点 [“exec_entry”, “p1_entry”](exec格式) | |
---|---|---|---|
无CMD | 错误,不允许 | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”, “p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry exec_cmd p1_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
如上图,ENTRYPOINT与CMD存在一定的关联交互,当ENTRYPOINT与CMD同时存在时,ENTRYPOINT会作为命令,CMD作为命令的参数结合使用,如RNTRYPOINT [“top”],CMD[“-b”],两个命令在没有覆盖命令运行容器的情况会执行top -b。如果单独只有一个,则会将那一个当完整命令执行。
CMD
该命令指定容器运行时需要执行的命令,多行CMD命令只有最后一行生效。CMD命令不会在构建镜像时生成新的镜像层。
使用形式:
1 | CMD ["executable","param1","param2"] #exec形式 |
CMD运行容器时可以被显示覆盖,如docker run -it images command。这里的command命令就会替换CMD里的命令。
RUN
RUN命令在构建镜像时会生成新的镜像层,每一行RUN命令都会。
1 | Shell 形式 |
多阶段运行
使用--mount=type=bind from=阶段名称
来绑定多阶段的源,使用其构建的资源
1 | 第一阶段:生成一些文件 |
ENTRYPOINT
CMD
RUN
同样都是执行命令,他们之间有着区别,如下表:
指令 | 执行阶段 | 覆盖规则 | 是否生成镜像层 | 用途 |
---|---|---|---|---|
RUN | 构建阶段 | 无覆盖 | ✅ 每条 RUN 都生成镜像层 | 安装软件、生成文件、编译 |
CMD | 运行阶段 | 容器启动时可被命令覆盖 | ❌ 不生成镜像层 | 容器默认启动命令或默认参数 |
ENTRYPOINT | 运行阶段 | 可用 --entrypoint 覆盖 |
❌ 不生成镜像层 | 固定容器执行程序,让容器像可执行文件 |
HEALTHCHECK
健康检查,使用该命令指定的判断容器是否正常健康运行。该命令需要配合
HEALTHCHECK [OPTIONS] CMD command
(通过在容器内运行命令来检查容器运行状况)HEALTHCHECK NONE
(禁用从基础映像继承的任何运行状况检查)
该命令需要配合CMD命令使用,使用CMD前可以添加如下参数配合检查:
--interval=DURATION
(默认值:30s
) #间隔--timeout=DURATION
(默认值:30s
) #超时--start-period=DURATION
(默认值:0s
) #开始期--start-interval=DURATION
(默认值:5s
) #开始间隔--retries=N
(默认值:3
) #重试次数
–interval:运行状况检查将在容器 started,然后在每次前一次检查完成后再次间隔秒。
–timeout:如果单次运行检查所需的时间超过超时秒数,则检查被认为失败了。
–retries:它会重试容器的运行状况检查连续失败
–start-period:开始期为需要时间引导的容器提供初始化时间。 在此期间的探测失败将不计入最大重试次数。 但是,如果运行状况检查在开始期间成功,则会考虑容器已启动,所有连续失败都将计入最大重试次数。
–start-interval:开始间隔是开始期间健康检查之间的时间。 此选项需要 Docker 引擎版本 25.0 或更高版本。
命令的退出状态指示容器的运行状况。 可能的值为:
- 0:成功 - 容器运行正常并可供使用
- 1:不正常 - 容器无法正常工作
- 2:保留 - 不要使用此退出代码
1 | 每五分钟检查一次 Web 服务器是否能够 在三秒钟内投放网站主页: |
STOPSIGNAL
STOPSIGNAL
用来指定容器接收到 docker stop
时发送给主进程(PID 1)的 系统信号,默认发送SIGTERM
。有些第三方应用不适用该默认值,例如nginx使用SIGQUIT
来优雅退出。
1 | FROM ubuntu:22.04 |
VOLUME
该指令创建具有指定名称的挂载点 并将其标记为保存来自本机主机或其他主机的外部挂载卷,该命令使用任何数据初始化新创建的卷存在于基础映像中的指定位置,但是无法从在 Dockerfile 中挂载主机目录。该指令不支持指定参数。您必须在创建或运行容器时指定挂载点,如docker run
1 | FROM ubuntu |
如果docker run没有显示的指定卷名,则docker会自动创建随机名称的卷挂载/myvol。
运行容器时显示指定卷名mydata,docker run -v mydata:/data ubuntu
volume优点:
- 容器删除,数据还在
- 多个容器可以共享数据
- 可以备份、迁移
- 不依赖宿主机目录结构
- IO 性能通常比 bind mount 好
备份与迁移恢复
备份
创建一个新容器dbstore,挂载容器的/dbdata
1 | docker run -v /dbdata --name dbstore ubuntu /bin/bash |
- 启动新容器并从容器挂载卷
dbstore
- 将本地主机目录挂载为
/backup
- 将卷内容 tar 传递到目录内的文件的命令。
dbdata
backup/backup.tar
1 | docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata |
当命令完成且容器停止时,它会创建卷dbdata
的备份数据到/backup/backup.tar包
--rm
- 容器执行完命令后 自动删除,不会在
docker ps -a
留下记录。 - 适合临时任务,比如备份或一次性操作。
--volumes-from dbstore
- 挂载另一个容器
dbstore
的卷到当前容器。 - 如果
dbstore
里有/dbdata
卷,这里会把它挂载到本容器同路径/dbdata
。 - 常用于 数据备份 或 访问别的容器数据。
ubuntu
- 该临时运行的容器镜像
迁移与恢复
使用刚刚创建的备份,您可以将其恢复到同一个容器, 或您在其他地方创建的另一个容器。
例如,创建一个名为 dbstore2
的新容器
1 | docker run -v /dbdata --name dbstore2 ubuntu /bin/bash |
对新容器数据卷中的备份文件进行tar解压
1 | docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1" |