mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 08:27:25 +00:00
更新Docker安装、镜像、Dockerfile和Compose等文档内容
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
## 7.1 RUN 执行命令
|
||||
|
||||
### 何时使用 RUN
|
||||
|
||||
`RUN` 是 Dockerfile 中最常用的指令,主要用于在镜像构建阶段执行命令来修改镜像。具体来说:
|
||||
|
||||
- **安装依赖**:`RUN apt-get install nginx`
|
||||
- **编译程序**:`RUN gcc -o app main.c`
|
||||
- **下载文件**:`RUN curl -O https://example.com/file.tar.gz`
|
||||
- **配置系统**:`RUN mkdir -p /app/data`
|
||||
|
||||
理解 RUN 的核心是理解**镜像分层**:每一个 RUN 都会在当前层之上创建新的一层,这会影响镜像大小。因此,合理使用 RUN(特别是合并多个 RUN)是构建轻量级镜像的关键。
|
||||
|
||||
### 7.1.1 基本语法
|
||||
|
||||
```docker
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
## 7.2 COPY 复制文件
|
||||
|
||||
### 何时使用 COPY
|
||||
|
||||
`COPY` 是在构建镜像时,将构建上下文(Dockerfile 所在目录及其子目录)中的文件或目录复制到容器内的指令。它是处理应用代码、配置文件最常用的方式。
|
||||
|
||||
典型场景:
|
||||
- 复制应用源码:`COPY . /app`
|
||||
- 复制配置文件:`COPY nginx.conf /etc/nginx/nginx.conf`
|
||||
- 复制静态资源:`COPY public /app/public`
|
||||
|
||||
**为什么 COPY 比 ADD 更值得推荐?** 笔者建议在 90% 的情况下使用 COPY。原因是 COPY 的语义更清晰——它就是简单地复制文件。而 ADD 有额外的功能(自动解压、支持 URL),这些功能往往会带来意外的行为。除非你明确需要 ADD 的自动解压功能,否则用 COPY。详见 [7.3 ADD 指令](7.3_add.md) 中的详细对比。
|
||||
|
||||
### 7.2.1 基本语法
|
||||
|
||||
```docker
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
## 7.3 ADD 更高级的复制文件
|
||||
|
||||
### 何时使用 ADD?何时用 COPY?
|
||||
|
||||
在开始前,让我们直言不讳:**在大多数情况下,你应该使用 COPY,而不是 ADD**。
|
||||
|
||||
`ADD` 在 `COPY` 基础上增加了两个额外功能,但这些功能往往引入复杂性而非便利:
|
||||
|
||||
1. 自动解压 tar 压缩包(有时你想复制一个 .tar.gz 本身,而 ADD 会意外地解压它)
|
||||
2. 支持从 URL 下载文件(这个功能由于网络不稳定已被广泛认为是反模式)
|
||||
|
||||
**实践中的建议**:除非你明确需要自动解压功能(比如官方基础镜像构建根文件系统),否则始终使用 COPY。原因很简单——显式优于隐式。你的 Dockerfile 在 6 个月后被接手维护时,清晰的意图会让团队少走很多弯路。
|
||||
|
||||
### 7.3.1 基本语法
|
||||
|
||||
```docker
|
||||
@@ -13,7 +24,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
|
||||
---
|
||||
|
||||
### 7.3.2 ADD vs COPY
|
||||
### 7.3.2 ADD vs COPY 详细对比
|
||||
|
||||
| 特性 | COPY | ADD |
|
||||
|------|------|-----|
|
||||
@@ -23,7 +34,7 @@ ADD [选项] ["<源路径>", ... "<目标路径>"]
|
||||
| 行为可预测性 | ✅ 高 | ⚠️ 低 |
|
||||
| 推荐程度 | ✅ **优先使用** | 仅解压场景 |
|
||||
|
||||
> 笔者建议:除非需要自动解压 tar 文件,否则始终使用 COPY。明确的行为比隐式的魔法更好。
|
||||
> **笔者建议**:除非需要自动解压 tar 文件,否则始终使用 COPY。明确的行为比隐式的魔法更好。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
## 7.4 CMD 容器启动命令
|
||||
|
||||
### 何时使用 CMD,何时使用 ENTRYPOINT?
|
||||
|
||||
在深入 CMD 的细节之前,我们需要理解一个关键问题:**CMD 和 ENTRYPOINT 应该在什么时候使用?**
|
||||
|
||||
这是 Dockerfile 使用中最常见的困惑之一。简单的答案是:
|
||||
- **CMD**:定义容器的”默认命令”。如果用户在 `docker run` 时提供命令,CMD 会被覆盖
|
||||
- **ENTRYPOINT**:定义容器的”入口脚本”。通常用于启动应用的某个特定部分
|
||||
|
||||
**决策树**:
|
||||
1. **你的容器是否有不可变的启动逻辑?** 比如需要先做一些初始化工作,然后才运行应用 → 使用 ENTRYPOINT
|
||||
2. **用户经常会在 `docker run` 时传入不同的命令吗?** → 使用 CMD(让用户灵活覆盖)
|
||||
3. **大多数情况下,你希望容器始终以相同的方式启动?** → 使用 ENTRYPOINT
|
||||
|
||||
更多细节见 [7.5 ENTRYPOINT 指令](7.5_entrypoint.md)。
|
||||
|
||||
### 7.4.1 什么是 CMD
|
||||
|
||||
`CMD` 指令用于指定容器启动时默认执行的命令。它定义了容器的 “主进程”。
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
## 7.5 ENTRYPOINT 入口点
|
||||
|
||||
### 何时使用 ENTRYPOINT:从"容器"到"命令"
|
||||
|
||||
如果说 CMD 是"容器中的默认程序",那么 ENTRYPOINT 就是"把容器变成一个命令"。这个思维转变决定了你何时使用 ENTRYPOINT。
|
||||
|
||||
**使用 ENTRYPOINT 的典型场景**:
|
||||
|
||||
1. **命令行工具**:你想让镜像像 `curl` 或 `wget` 一样使用
|
||||
```dockerfile
|
||||
ENTRYPOINT ["curl"]
|
||||
# docker run myimage http://example.com → curl http://example.com
|
||||
```
|
||||
|
||||
2. **应用启动脚本**:你有一个初始化脚本,需要接收命令行参数
|
||||
```dockerfile
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
# docker run myimage --debug → /app/entrypoint.sh --debug
|
||||
```
|
||||
|
||||
3. **与 CMD 结合**:ENTRYPOINT 定义入口,CMD 定义默认参数
|
||||
```dockerfile
|
||||
ENTRYPOINT ["python", "app.py"]
|
||||
CMD ["--port", "8000"]
|
||||
# docker run myimage → python app.py --port 8000
|
||||
# docker run myimage --port 9000 → python app.py --port 9000
|
||||
```
|
||||
|
||||
**对比 CMD**:如果没有这些"把容器当命令用"的需求,通常使用 CMD 就足够了。
|
||||
|
||||
### 7.5.1 什么是 ENTRYPOINT
|
||||
|
||||
`ENTRYPOINT` 指定容器启动时运行的入口程序。与 CMD 不同,ENTRYPOINT 定义的命令不会被 `docker run` 的参数覆盖,而是 **接收这些参数**。
|
||||
|
||||
@@ -13,6 +13,18 @@ Dockerfile 是一个文本文件,其内包含了一条条的 **指令 (Instruc
|
||||
* **版本控制**:Dockerfile 可以纳入版本控制系统 (如 Git),便于追踪变更。
|
||||
* **透明性**:任何人都可以通过阅读 Dockerfile 了解镜像的构建过程。
|
||||
|
||||
## Dockerfile 编写哲学
|
||||
|
||||
在深入每个指令的细节之前,笔者想强调一个至关重要的原则:**Dockerfile 不是脚本,而是镜像的"设计图"**。这个区别决定了你如何思考每条指令的作用。
|
||||
|
||||
相比编写 Bash 脚本的思维("按顺序执行这些命令"),Dockerfile 的思维应该是("这一层镜像应该如何构建,下一层如何分层")。这个思维转变会影响你的决策:
|
||||
|
||||
- **合并命令**:一个 `RUN apt-get update && apt-get install ...` 应该写在一起,而不是分开成多个 `RUN` 指令,因为它们是同一个"层"的逻辑
|
||||
- **选择合适的指令**:`COPY` vs `ADD`、`CMD` vs `ENTRYPOINT` 这些选择不是随意的,而是根据镜像分层的语义来决定的
|
||||
- **优化镜像大小**:最后才清理缓存、删除临时文件,让这些"瘦身"操作在同一层完成
|
||||
|
||||
这个章节将详细介绍各个指令。在学习指令语法时,请始终思考:"这个指令为什么要以这样的方式工作?如果我是 Docker,我应该如何设计它?"
|
||||
|
||||
## Dockerfile 基本结构
|
||||
|
||||
Dockerfile 一般分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
|
||||
|
||||
Reference in New Issue
Block a user