Dockerfile全解析:指令、构建、多阶段构建等
笔记哥 /
04-13 /
41点赞 /
0评论 /
418阅读
## Dockerfile官网
https://docs.docker.com/reference/dockerfile/
## 什么是Dockerfile?
Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
当我们从docker镜像仓库中下载的镜像不能满足我们的需求时,我们可以通过以下两种方式对镜像进行更改:
1. 从已经创建的容器中更新镜像,并且提交这个镜像
2. 使用 Dockerfile 指令来创建一个新的镜像
镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
**那Dockerfile有什么作用呢?**
- 对于开发人员,可以为开发团队提供一个完全一致的开发环境
- 对于测试人员,可以直接拿开发时所构建的镜像测试。
- 对于运维人员,在部署时,可以实现快速部署、移值。
## Dockerfile指令
### FROM
FROM指令初始化一个新的构建阶段,并为后续指令设置 基础镜像。因此,有效的 Dockerfile 必须以FROM指令开头。镜像可以是任何有效的镜像。FROM指定一个基本镜像,类似`docker pull`下载镜像。
FROM可以在单个 Dockerfile 中多次出现,以创建多个镜像,或将一个构建阶段用作另一个构建阶段的依赖项。
示例:
```csharp
FROM [--platform=] [:] [AS ]
FROM java:8
```
### LABEL
指定镜像的元数据,例如作者、联系方式、邮箱等信息
语法:
```csharp
LABEL = [=...]
LABEL author=huangSir
```
### RUN
RUN指令制作镜像过程中需要执行的命令,通常系统配置,服务配置,下载软件,部署等等,不能出现阻塞当前终端的命令.
RUN它有两种形式:
```csharp
#shell脚本的形式:
RUN [OPTIONS] ...
#Exec的形式:
RUN [OPTIONS] [ "", ... ]
```
通常RUN指令种,shell脚本是最常用的:
```csharp
#第一种heredocs形式
RUN <=` 标志的命令将该变量传递给构建器。
Dockerfile 可以包含一条或多ARG条指令。例如,以下是一个有效的 Dockerfile:
```csharp
FROM busybox
ARG user1
ARG buildno
```
也可以给ARG设置默认值:
```csharp
FROM busybox
ARG user1=someuser
ARG buildno=1
```
### USER
USER 指令用于指定后续指令执行时所使用的用户。这在需要以非 root 用户运行容器时非常有用,可以提高容器的安全性,避免以 root 用户运行可能导致的安全风险。
示例:
```csharp
FROM busybox
RUN useradd www-www
USER www-www
RUN apt install curl
```
### HEALTHCHECK
HEALTHCHECK指令告诉 Docker 如何测试容器是否仍在运行。这可以检测出诸如 Web 服务器陷入无限循环、无法处理新连接等情况,即使服务器进程仍在运行。
当容器指定了健康检查后,除了正常状态外,它还会拥有一个健康状态。此状态最初为starting。每当健康检查通过时,它都会变为healthy(无论它之前的状态如何)。在连续失败一定次数后,它将变为unhealthy。
示例:
```csharp
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl http://127.0.0.1:8080
#--interval 间隔多少秒执行CMD的内容
#--timeout 指定超时时间是多少
#--retries 允许重试几次
#CMD 执行的命令
```
### 总结
上述指令在生产过程中均已包含,当然还有几个指令没有说明,例如SHELL(可以使用RUN指令替换)、MAINTAINER(该指令已弃用,可以使用LABEL标签替换)ONBUILD、STOPSIGNAL这四个指令,感兴趣的同学可以自行查阅相关资料
## Dockerfile相关命令说明
### 语法:
```csharp
docker build [选项] <上下文路径>
```
常用选项说明:
- -t:指定镜像的名称和标签(tag)。格式为 `:`,其中 `` 是可选的
- -f:指定 Dockerfile 的路径。默认情况下,Docker 会在当前目录下查找名为 Dockerfile 的文件。
- --build-arg:设置构建时的变量,用于传递给 ARG 指令。
- --no-cache:禁用缓存,强制重新构建。
- --rm:构建完成后删除中间容器,默认值为 true
- --debug:debug测试Dockerfile
### 示例:
假设你的 Dockerfile 位于当前目录下,你可以使用以下命令构建镜像:
```csharp
docker build -t my-image .
```
如果 Dockerfile 不在当前目录下,可以使用 -f 指定路径:
```csharp
docker build -f /path/to/Dockerfile -t my-image /path/to/context
-f /path/to/Dockerfile:指定 Dockerfile 的路径。
/path/to/context:指定构建上下文的路径。
```
如果 Dockerfile 中使用了 ARG 指令,可以通过 --build-arg 参数在构建时传递值。
示例 Dockerfile
```csharp
FROM alpine
ARG MY_VAR=default_value
RUN echo "The value is $MY_VAR"
```
构建命令
```csharp
docker build --build-arg MY_VAR=custom_value -t my-image .
```
### 总结
一般来说,Dockerfile文件和文件中指定的其它文件,都会指定在同一个目录下,所以我们只需要记住下面这个命令即可
```csharp
#最后有个点,代表当前目录下的所有文件内容
docker build -t 镜像名:版本号 .
```
## 使用tomcat构建Java项目
这里使用zrlog的war包来代表生产环境中的实际项目,在这里感谢zrlog的提供方:https://gitee.com/94fzb/zrlog
下载war包:
```csharp
[root@master /data/docker/zrlog]# wget wget https://dl.zrlog.com/release/zrlog.war
--2025-04-13 14:59:30-- http://wget/
Resolving wget (wget)... failed: Temporary failure in name resolution.
wget: unable to resolve host address ‘wget’
--2025-04-13 14:59:30-- https://dl.zrlog.com/release/zrlog.war
Resolving dl.zrlog.com (dl.zrlog.com)... 154.17.16.140
Connecting to dl.zrlog.com (dl.zrlog.com)|154.17.16.140|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10794045 (10M) [application/java-archive]
Saving to: ‘zrlog.war’
zrlog.war 100%[==================================================================================================================>] 10.29M 4.63MB/s in 2.2s
2025-04-13 14:59:33 (4.63 MB/s) - ‘zrlog.war’ saved [10794045/10794045]
FINISHED --2025-04-13 14:59:33--
Total wall clock time: 3.3s
Downloaded: 1 files, 10M in 2.2s (4.63 MB/s)
[root@master /data/docker/zrlog]# ll
total 10552
drwxr-xr-x 2 root root 4096 Apr 13 14:59 ./
drwxr-xr-x 5 root root 4096 Apr 13 14:59 ../
-rw-r--r-- 1 root root 10794045 Jul 10 2024 zrlog.war
```
编写Dockerfile:
```csharp
[root@master /data/docker/zrlog]# cat Dockerfile
FROM tomcat:9.0.87-jdk8-corretto
LABEL author=huangSir
LABEL version=1.0
ENV CODE_FILE="zrlog.war"
ENV SRC_PATH="/usr/local/tomcat/webapps/ROOT.war"
ENV WORK_DIR="/usr/local/tomcat"
COPY ${CODE_FILE} ${SRC_PATH}
WORKDIR ${WORK_DIR}
EXPOSE 8080
CMD ["catalina.sh","run"]
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl http://127.0.0.1:8080
```
构建镜像并查看
```csharp
#构建镜像
[root@master /data/docker/zrlog]# docker build -t zrlog_tomcat:8.0 .
[+] Building 0.2s (8/8) FINISHED docker:default
...
=> => naming to docker.io/library/zrlog_tomcat:8.0
#查看构建的镜像
[root@master /data/docker/zrlog]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zrlog_tomcat 8.0 be4206f2e7bf About a minute ago 467MB
```
运行容器
```csharp
[root@master /data/docker/zrlog]# docker run -d -p 8080:8080 --name zrlog --restart always zrlog_tomcat:8.0
8cb866a61b46bb04bcf1a04a064388d6a8c985d84ea9a3a11478086ad89cf28c
[root@master /data/docker/zrlog]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8cb866a61b46 zrlog_tomcat:8.0 "catalina.sh run" 4 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp, [::]:8080->8080/tcp, 8443/tcp zrlog
```
测试访问:
http://10.0.0.10:8080/

## Dockerfile书写要求
合理编写Dockerfile可以减少构建出来的镜像的大小,避免构建Docker镜像时产生过多的层级。
Dockerfile生产环境书写要求:
1、尽量保证每个镜像功能单一,尽量避免多个服务运行在同一个镜像中
2、选择合适的基础镜像,不一定都要从头做
3、注释与说明,添加一定的注释和镜像属性信息
4、指定版本号
5、减少镜像的层数/步骤,尽可能合并RUN,ADD,COPY
6、记得减少镜像的大小,清理垃圾,记得清理缓存,临时文件,压缩包等等...
7、合理使用.dockeringnore,Dockerfile同一个目录,隐藏文件,构建的忽略的文件
## .dockerignore使用
`.dockerignore`是一个隐藏文件,在Dockerfile文件同级目录中
示例:
```csharp
[root@master /data/docker/zrlog]# ll
total 10556
drwxr-xr-x 2 root root 4096 Apr 13 15:33 ./
drwxr-xr-x 5 root root 4096 Apr 13 14:59 ../
-rw-r--r-- 1 root root 0 Apr 13 15:33 .dockerignore
-rw-r--r-- 1 root root 370 Apr 13 15:25 Dockerfile
-rw-r--r-- 1 root root 10794045 Jul 10 2024 zrlog.war
```
`.dockerignore` 文件是 Docker 构建过程中使用的一个配置文件,类似于 Git 中的 `.gitignore` 文件。它的作用是告诉 Docker 在构建镜像时,应该忽略哪些文件和目录,从而避免将不必要的文件复制到镜像中,减少镜像大小并提高构建效率。
示例:
```csharp
# 忽略所有以 . 开头的文件
.*
# 但不忽略 .dockerignore 文件本身
!.dockerignore
# 忽略临时文件
*.tmp
*.swp
# 忽略日志文件
*.log
# 忽略测试目录
tests/
# 忽略数据目录下的敏感文件
data/sensitive_data.txt
# 忽略虚拟环境
venv/
# 忽略构建文件
build/
dist/
# 忽略特定文件
requirements.txt
# 准许Dockerfile文件
!Dockerfile
# 准许entrypoint.sh脚本
!entrypoint.sh
```
说明:
\*:表示排除所有
!:准许指定的文件传输到docker镜像中
## Dockerfile多阶段构建
Docker 的多阶段构建(Multi-Stage Builds)是一种强大的功能,允许你在同一个 Dockerfile 中定义多个构建阶段,每个阶段可以基于不同的基础镜像。最终,你可以从这些阶段中选择需要的文件和目录,构建出一个更小、更安全的最终镜像。多阶段构建特别适用于需要编译源代码或安装大量依赖的应用程序。
### 多阶段构建的优势
- 减小镜像大小:只将必要的文件和依赖复制到最终镜像中,避免包含编译工具和中间文件。
- 提高安全性:避免将编译工具和源代码暴露在最终镜像中。
- 简化构建过程:在一个 Dockerfile 中完成所有构建步骤,无需多个 Dockerfile 或复杂的构建脚本。
### 多阶段构建的基本结构
多阶段构建的 Dockerfile 通常包含多个 FROM 指令,每个 FROM 指令定义一个新的阶段。你可以为每个阶段指定一个名称(通过 AS 关键字),并在后续阶段中引用这些名称。
示例:
```csharp
# 第一阶段:构建阶段
FROM maven:3.8.1-jdk-11 AS builder
WORKDIR /app
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
# 第二阶段:运行阶段
FROM openjdk:11-jre-slim
COPY --from=builder /app/target/my-java-app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
```
说明:
上述第一阶段构建时,使用maven打包成一个jar包,然后在第二阶段构建时,会将第一阶段打包的jar包copy到第二阶段中进行运行
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2204
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利