当前位置: 首页 > news >正文

【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)

Langchain系列文章目录

01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
08-【万字长文】MCP深度解析:打通AI与世界的“USB-C”,模型上下文协议原理、实践与未来

Python系列文章目录

PyTorch系列文章目录

机器学习系列文章目录

深度学习系列文章目录

Java系列文章目录

JavaScript系列文章目录

Python系列文章目录

Go语言系列文章目录

Docker系列文章目录

01-【Docker-Day 1】告别部署噩梦:为什么说 Docker 是每个开发者的必备技能?
02-【Docker-Day 2】从零开始:手把手教你在 Windows、macOS 和 Linux 上安装 Docker
03-【Docker-Day 3】深入浅出:彻底搞懂 Docker 的三大核心基石——镜像、容器与仓库
04-【Docker-Day 4】从创建到删除:一文精通 Docker 容器核心操作命令
05-【Docker-Day 5】玩转 Docker 镜像:search, pull, tag, rmi 四大金刚命令详解
06-【Docker-Day 6】从零到一:精通 Dockerfile 核心指令 (FROM, WORKDIR, COPY, RUN)


文章目录

  • Langchain系列文章目录
  • Python系列文章目录
  • PyTorch系列文章目录
  • 机器学习系列文章目录
  • 深度学习系列文章目录
  • Java系列文章目录
  • JavaScript系列文章目录
  • Python系列文章目录
  • Go语言系列文章目录
  • Docker系列文章目录
  • 摘要
  • 一、为什么需要 Dockerfile?
  • 二、Dockerfile 的基本结构与执行机制
    • 2.1 文件结构与基本语法
    • 2.2 构建上下文 (Build Context)
    • 2.3 分层构建 (Layered Build)
  • 三、核心指令详解(上)
    • 3.1 `FROM`:指定基础镜像
        • (1) 语法
        • (2) 示例
    • 3.2 `WORKDIR`:设定工作目录
        • (1) 语法
        • (2) 作用与特性
        • (3) 示例
    • 3.3 `COPY`:复制文件或目录
        • (1) 语法
        • (2) 关键点
        • (3) 示例
    • 3.4 `RUN`:执行命令
        • (1) 两种形式
        • (2) 最佳实践:合并 `RUN` 指令
  • 四、实战:构建一个自定义 Nginx 镜像
    • 4.1 准备工作
        • (1) 创建项目目录
        • (2) 创建自定义网页
        • (3) 编写 Dockerfile
    • 4.2 构建镜像
    • 4.3 运行并验证
        • (1) 查看新镜像
        • (2) 运行容器
        • (3) 验证结果
  • 五、总结


摘要

在前面的学习中,我们已经掌握了如何从 Docker Hub 拉取并运行现成的镜像。然而,在真实的项目中,我们往往需要根据自己的应用需求,创建专属的镜像。本文将深入探讨 Docker 中实现镜像构建自动化的核心工具——Dockerfile。我们将从其基本概念与结构入手,详细解析 FROM, WORKDIR, COPY, RUN 这四个最基础也最重要的指令,并通过一个完整的实战案例,手把手教你如何编写第一个 Dockerfile,并使用 docker build 命令构建出一个自定义的 Web 服务器镜像。

一、为什么需要 Dockerfile?

在我们深入指令之前,首先要理解 Dockerfile 扮演的角色。

想象一下,你新加入一个项目组,需要配置开发环境。通常,你会拿到一份长长的环境搭建文档,上面写着:“第一步,安装 Ubuntu 20.04;第二步,安装 Python 3.8;第三步,安装 Nginx;第四步,修改 Nginx 配置文件…”。这个过程繁琐、耗时且容易出错。

Dockerfile 就是这份“环境搭建文档”的代码化、自动化版本。它是一个包含了一系列指令的文本文件,这些指令按顺序描述了如何从一个基础镜像开始,一步步地安装依赖、复制文件、配置环境,最终构建出一个全新的、符合我们需求的 Docker 镜像。

使用 Dockerfile 的核心优势:

  • 透明化与可追溯: Dockerfile 本身就是镜像构建过程的完整记录,任何人都可以通过阅读它来理解镜像的构成。
  • 自动化与一致性: 只需一条 docker build 命令,即可在任何安装了 Docker 的机器上重现一模一样的环境,彻底告别“在我机器上是好的”这一魔咒。
  • 版本控制: 我们可以像管理项目代码一样,将 Dockerfile 纳入 Git 等版本控制系统,轻松追踪环境的每一次变更。

二、Dockerfile 的基本结构与执行机制

2.1 文件结构与基本语法

一个 Dockerfile 通常由一系列的“指令+参数”组成,其基本语法非常直观:

# 这是一个注释 (Comment)
INSTRUCTION arguments
  • #: 行首的 # 表示注释。
  • INSTRUCTION: 指令不区分大小写,但官方推荐使用大写,以便与参数区分。
  • arguments: 指令的参数。

Docker 引擎会从上到下,逐行解析并执行 Dockerfile 中的指令。

2.2 构建上下文 (Build Context)

执行 docker build 命令时,我们所在的目录被称为构建上下文 (Build Context)。Docker 客户端会将这个目录下的所有文件(可以被 .dockerignore 排除)打包发送给 Docker 守护进程(Docker Daemon)。这样,在 Dockerfile 中使用 COPYADD 指令时,Docker 才能找到我们想要复制到镜像中的本地文件。

2.3 分层构建 (Layered Build)

Docker 镜像最核心的概念之一就是分层。Dockerfile 中的每一条可执行指令(如 RUN, COPY, ADD)都会创建一个新的镜像层 (Image Layer)

第一层
第二层
第三层
最终镜像
基础镜像: nginx:alpine
RUN apt-get update
COPY ./myapp /app
RUN chmod +x /app/run.sh
my-app:1.0

分层构建的好处:

  1. 缓存复用 (Cache Reuse): 这是 Docker 构建如此高效的关键。如果 Dockerfile 的某一行指令没有发生变化,并且它所依赖的上一层也没有变化,那么 Docker 会直接使用之前构建时生成的缓存层,而不是重新执行该指令。这极大地加快了镜像的重复构建速度。
  2. 资源共享: 多个镜像可以共享相同的底层。例如,你有十个基于 ubuntu:20.04 构建的应用镜像,它们在物理机上只会存储一份 ubuntu:20.04 的基础层。

三、核心指令详解(上)

下面我们来正式学习构建镜像的四大基础指令。

3.1 FROM:指定基础镜像

FROM 指令是 Dockerfile 的基石,它必须是 Dockerfile 中的第一条非注释指令。它告诉 Docker 我们要构建的新镜像是基于哪个镜像开始的。

(1) 语法
FROM <image>
FROM <image>:<tag>
FROM <image>@<digest>
  • <image>: 基础镜像的名称,例如 ubuntu
  • <tag>: 镜像的标签(版本),例如 20.04。如果省略,默认为 latest
  • <digest>: 镜像的唯一内容摘要哈希值。使用摘要可以保证你使用的镜像是绝对确定的,不会因标签被覆盖而改变。
(2) 示例

如果我们想构建一个基于轻量级 Alpine Linux 的 Nginx 服务器,Dockerfile 的开头将是:

# 从 Docker Hub 拉取 alpine 标签的 nginx 镜像作为基础
FROM nginx:alpine

选择一个合适的基础镜像是优化的第一步。例如,nginx:alpine(约 23MB)就比 nginx:latest(基于 Debian,约 142MB)小得多。

3.2 WORKDIR:设定工作目录

WORKDIR 指令用于为 Dockerfile 中在其之后执行的任何 RUN, CMD, ENTRYPOINT, COPY, ADD 指令设置工作目录。

(1) 语法
WORKDIR /path/to/workdir
(2) 作用与特性
  • 简化路径:避免在后续指令中不断重复书写长路径。
  • 自动创建:如果指定的目录不存在,Docker 会自动创建它。
  • 可多次使用:可以多次使用 WORKDIR 来切换当前目录。路径可以是相对路径,它会相对于前一个 WORKDIR 指令的路径。
(3) 示例
# 不推荐的写法
RUN mkdir /app
COPY config.json /app/config.json
RUN /app/my-script.sh# 推荐的写法
WORKDIR /app
COPY config.json .
RUN ./my-script.sh

在推荐的写法中,COPY . .RUN ./my-script.sh 中的 ../ 都是相对于 /app 目录的,代码更清晰简洁。

3.3 COPY:复制文件或目录

COPY 指令用于将构建上下文中的文件或目录复制到镜像内的文件系统中。

(1) 语法
COPY [--chown=<user>:<group>] <src>... <dest>
  • <src>: 源文件或目录,路径是相对于构建上下文的。支持通配符,例如 *.html
  • <dest>: 目标路径,在镜像内的绝对路径,或者是相对于 WORKDIR 的相对路径。
  • --chown: (可选) 改变复制到镜像中文件的用户和用户组。
(2) 关键点
  • 路径规则:源路径必须在构建上下文中。你不能 COPY ../somefile /app
  • 目录复制:如果源是目录,它会复制目录中的所有内容(包括元数据)。
  • 目标路径:如果目标路径以 / 结尾,则源会被复制到该目录下。如果目标路径不存在,Docker 会自动创建它以及所有必需的父目录。
(3) 示例

假设我们的项目目录结构如下:

.
├── Dockerfile
├── html
│   └── index.html
└── conf└── default.conf

Dockerfile 内容:

# ...
WORKDIR /usr/share/nginx/html
# 将构建上下文中的 html/index.html 复制到镜像的 /usr/share/nginx/html/index.html
COPY html/index.html .WORKDIR /etc/nginx/conf.d
# 将构建上下文中的 conf/default.conf 复制到镜像的 /etc/nginx/conf.d/default.conf
COPY conf/default.conf .

3.4 RUN:执行命令

RUN 指令用于在镜像构建过程中执行命令。这通常用于安装软件包、创建目录、编译代码等。

(1) 两种形式
  1. Shell 形式: RUN <command>

    • 命令在 shell 中执行,在 Linux 上默认是 /bin/sh -c <command>
    • 可以直接使用 shell 语法,如环境变量替换 ($HOME)。
    • 示例: RUN apt-get update && apt-get install -y vim
  2. Exec 形式: RUN ["executable", "param1", "param2"]

    • 命令直接由内核执行,不经过 shell 解析。
    • 更适合不希望被 shell 字符串插值影响的命令。
    • 参数必须是 JSON 数组格式。
    • 示例: RUN ["/bin/bash", "-c", "echo hello"]
(2) 最佳实践:合并 RUN 指令

由于每一条 RUN 指令都会创建新的一层,为了减少镜像层数、缩小镜像体积,应将多个相关的命令用 && 连接起来,合并成一条 RUN 指令。

# 不推荐:创建了两个镜像层
RUN apt-get update
RUN apt-get install -y curl# 推荐:只创建一个镜像层
RUN apt-get update && apt-get install -y curl

四、实战:构建一个自定义 Nginx 镜像

现在,我们将运用所学知识,创建一个替换了默认欢迎页面的 Nginx 镜像。

4.1 准备工作

(1) 创建项目目录

在你的电脑上创建一个名为 my-nginx-app 的文件夹。

mkdir my-nginx-app
cd my-nginx-app
(2) 创建自定义网页

my-nginx-app 目录下,创建一个 index.html 文件,并写入以下内容:

<!DOCTYPE html>
<html>
<head><title>Welcome to My Custom Nginx!</title>
</head>
<body><h1>Hello from My First Dockerfile!</h1><p>This page is served by a custom Nginx image built by me.</p>
</body>
</html>
(3) 编写 Dockerfile

my-nginx-app 目录下,创建一个名为 Dockerfile 的文件(注意没有文件后缀),并写入以下内容:

# 步骤 1: 指定基础镜像
# 我们选择 Alpine Linux 版本的 Nginx,因为它非常小巧
FROM nginx:1.21-alpine# 步骤 2: 设置工作目录 (可选,但推荐)
# 这里我们将工作目录设置为 Nginx 默认存放网页文件的目录
WORKDIR /usr/share/nginx/html# 步骤 3: 复制文件
# 将构建上下文(当前目录)中的 index.html 文件
# 复制到镜像的当前工作目录(/usr/share/nginx/html)下
# 注意:会覆盖掉基础镜像中原有的 index.html
COPY index.html .# RUN 指令在这里不是必需的,因为我们只是替换静态文件
# 如果需要安装软件,才会用到 RUN,例如:
# RUN apk add --no-cache curl

此时,你的目录结构应该是:

my-nginx-app/
├── Dockerfile
└── index.html

4.2 构建镜像

打开终端,确保当前路径在 my-nginx-app 目录下,然后执行 docker build 命令:

# -t 参数用于给镜像打上标签,格式为 <name>:<tag>
# . 表示将当前目录作为构建上下文
docker build -t my-custom-nginx:1.0 .

你会看到类似以下的输出:

Sending build context to Docker daemon  3.072kB
Step 1/3 : FROM nginx:1.21-alpine---> a355830213b3
Step 2/3 : WORKDIR /usr/share/nginx/html---> Running in c8e2b1e3d4a5
Removing intermediate container c8e2b1e3d4a5---> 7d2f9a65b8f1
Step 3/3 : COPY index.html .---> 1a9b8f7c6e5d
Successfully built 1a9b8f7c6e5d
Successfully tagged my-custom-nginx:1.0

4.3 运行并验证

(1) 查看新镜像

使用 docker images 命令,你应该能看到我们刚刚创建的镜像:

REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
my-custom-nginx     1.0       1a9b8f7c6e5d   5 seconds ago   22.8MB
(2) 运行容器

使用 docker run 命令来运行这个新镜像:

# -d: 后台运行容器
# -p 8080:80: 将主机的 8080 端口映射到容器的 80 端口
# --name: 给容器取一个名字,方便管理
docker run -d -p 8080:80 --name my-nginx-server my-custom-nginx:1.0
(3) 验证结果

打开你的浏览器,访问 http://localhost:8080。如果一切顺利,你将看到我们自定义的 index.html 页面内容!

五、总结

本文作为 Dockerfile 的入门篇,详细介绍了其作为镜像构建蓝图的核心地位,并深入剖析了分层构建机制及其带来的缓存优势。通过本章学习,我们应掌握以下核心知识点:

  1. Dockerfile 的作用:它是实现环境配置代码化、构建过程自动化的关键,确保了环境的一致性与可移植性。
  2. 构建上下文与分层:理解了 docker build 时发送给守护进程的内容,以及每一条指令如何创建新镜像层的概念,这是理解 Docker 镜像构建效率和大小的关键。
  3. 四大核心指令
    • FROM:必须是第一条指令,用于定义所有构建步骤的基础。
    • WORKDIR:用于设定后续指令的工作目录,能让 Dockerfile 更清晰、易于维护。
    • COPY:将本地文件复制到镜像中的标准方式,是向镜像中添加应用代码和配置的主要手段。
    • RUN:在镜像构建时执行命令,主要用于安装系统依赖和软件包。
  4. docker build 命令:掌握了使用 -t 参数为镜像打标签和指定构建上下文的基本用法,并成功构建了第一个自定义镜像。

在下一篇文章中,我们将继续深入 Dockerfile 的学习,探讨如何通过 CMDENTRYPOINT 指令让镜像真正“跑起来”,以及如何使用 ENVARG 等指令来传递变量和参数,敬请期待。


http://www.dtcms.com/a/282449.html

相关文章:

  • 壹脉销客AI电子名片源码核心架构
  • C++11 std::uninitialized_copy_n 原理与实现
  • 计算机网络:(九)网络层(下)超详细讲解互联网的路由选择协议、IPV6与IP多播
  • EVA series系列(上)
  • UltraISO编辑ISO文件
  • XPath注入攻击详解:原理、危害与防御
  • PLC-BMS电力载波通信技术深度解析:智能电网与储能系统的融合创新
  • (nice!!!)(LeetCode 每日一题) 3201. 找出有效子序列的最大长度 I (动态规划dp)
  • js数组简介
  • Linux 探秘进程与 fork:从内核源码到容器化演进
  • NLP:LSTM和GRU分享
  • 加速度传感器的用途与应用
  • Opencv---cv::minMaxLoc函数
  • Go与Python在数据管道与分析项目中的抉择:性能与灵活性的较量
  • React 中 props 的最常用用法精选+useContext
  • 单列集合顶层接口Collection
  • QT——事件系统详解
  • YOLOv13_SSOD:基于超图关联增强的半监督目标检测框架(原创创新算法)
  • GaussDB 数据库架构师修炼(五) 存储容量评估
  • 动态规划题解_打家劫舍【LeetCode】
  • MySQL 8.0 OCP 1Z0-908 题目解析(27)
  • 钱包核心标准 BIP32、BIP39、BIP44:从助记词到多链钱包的底层逻辑
  • RocketMQ源码级实现原理-消息过滤与重试
  • 【Deepseek-R1+阿里千问大模型】四步完成本地调用本地部署大模型和线上大模型,实现可视化使用
  • 拥抱主权AI:OpenCSG驱动智能体运营,共筑新加坡智能高地
  • 【技术追踪】基于检测器引导的对抗性扩散攻击器实现定向假阳性合成——提升息肉检测的鲁棒性(MICCAI-2025)
  • 辅助驾驶GNSS高精度模块UM680A外形尺寸及上电与下电
  • 剑指offer64_圆圈中最后剩下的数字
  • 为什么要用erc165识别erc721或erc1155
  • 系统性学习C语言-第十八讲-C语言内存函数