mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-10 11:54:37 +00:00
Restruct
This commit is contained in:
293
07_dockerfile/7.8_volume.md
Normal file
293
07_dockerfile/7.8_volume.md
Normal file
@@ -0,0 +1,293 @@
|
||||
## 7.8 VOLUME 定义匿名卷
|
||||
|
||||
### 基本语法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
VOLUME ["/路径1", "/路径2"]
|
||||
VOLUME /路径
|
||||
```
|
||||
|
||||
`VOLUME` 指令创建挂载点,并标记为外部挂载的卷。
|
||||
|
||||
---
|
||||
|
||||
### 为什么使用 VOLUME
|
||||
|
||||
> **核心原则**:容器存储层应该保持无状态,任何运行时数据都应该存储在卷中。
|
||||
|
||||
```
|
||||
没有 VOLUME: 使用 VOLUME:
|
||||
┌─────────────────────┐ ┌─────────────────────┐
|
||||
│ 容器存储层 │ │ 容器存储层 │
|
||||
│ ┌─────────────┐ │ │ (只读/无状态) │
|
||||
│ │ 数据库文件 │←─问题 │ │
|
||||
│ │ 日志文件 │ │ └──────────┬──────────┘
|
||||
│ │ 上传文件 │ │ │
|
||||
│ └─────────────┘ │ ┌──────────▼──────────┐
|
||||
└─────────────────────┘ │ 数据卷 │
|
||||
容器删除 = 数据丢失 │ ┌─────────────┐ │
|
||||
│ │ 持久化数据 │←─安全
|
||||
│ └─────────────┘ │
|
||||
└─────────────────────┘
|
||||
容器删除,数据保留
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 基本用法
|
||||
|
||||
#### 定义单个卷
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM mysql:8.0
|
||||
VOLUME /var/lib/mysql
|
||||
```
|
||||
|
||||
#### 定义多个卷
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME ["/data", "/logs", "/config"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VOLUME 的行为
|
||||
|
||||
#### 1. 自动创建匿名卷
|
||||
|
||||
如果运行时未指定挂载,Docker 会自动创建匿名卷:
|
||||
|
||||
```bash
|
||||
$ docker run mysql:8.0
|
||||
$ docker volume ls
|
||||
DRIVER VOLUME NAME
|
||||
local a1b2c3d4e5f6... # 自动创建的匿名卷
|
||||
```
|
||||
|
||||
#### 2. 可被命名卷覆盖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用命名卷替代匿名卷
|
||||
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
#### 3. 可被 Bind Mount 覆盖
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用宿主机目录替代
|
||||
|
||||
$ docker run -v /my/data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VOLUME 在构建时的特殊行为
|
||||
|
||||
> ⚠️ **重要**:VOLUME 之后对该目录的修改会被丢弃!
|
||||
|
||||
```docker
|
||||
FROM ubuntu
|
||||
VOLUME /data
|
||||
|
||||
## ❌ 这个文件不会出现在镜像中!
|
||||
|
||||
RUN echo "hello" > /data/test.txt
|
||||
```
|
||||
|
||||
**原因**:VOLUME 指令之后,Docker 将该目录视为外部挂载点,不再记录对它的修改。
|
||||
|
||||
#### 正确做法
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM ubuntu
|
||||
|
||||
## ✅ 先写入文件
|
||||
|
||||
RUN mkdir -p /data && echo "hello" > /data/test.txt
|
||||
|
||||
## 再声明 VOLUME
|
||||
|
||||
VOLUME /data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 常见使用场景
|
||||
|
||||
#### 数据库持久化
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM postgres:15
|
||||
VOLUME /var/lib/postgresql/data
|
||||
```
|
||||
|
||||
#### 日志目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM nginx
|
||||
VOLUME /var/log/nginx
|
||||
```
|
||||
|
||||
#### 上传文件目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
FROM myapp
|
||||
VOLUME /app/uploads
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 查看 VOLUME 定义
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 查看镜像定义的 VOLUME
|
||||
|
||||
$ docker inspect mysql:8.0 --format '{{json .Config.Volumes}}' | jq
|
||||
{
|
||||
"/var/lib/mysql": {}
|
||||
}
|
||||
|
||||
## 查看容器挂载的卷
|
||||
|
||||
$ docker inspect mycontainer --format '{{json .Mounts}}' | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### VOLUME vs docker run -v
|
||||
|
||||
| 特性 | Dockerfile VOLUME | docker run -v |
|
||||
|------|-------------------|---------------|
|
||||
| **定义时机** | 镜像构建时 | 容器运行时 |
|
||||
| **默认行为** | 创建匿名卷 | 可指定命名卷或路径 |
|
||||
| **灵活性** | 低(固定路径) | 高(可任意指定) |
|
||||
| **适用场景** | 定义必须持久化的路径 | 灵活的数据管理 |
|
||||
|
||||
---
|
||||
|
||||
### 在 Compose 中
|
||||
|
||||
在 Compose 中 配置如下:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
db:
|
||||
image: postgres:15
|
||||
volumes:
|
||||
# 命名卷(推荐)
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
# Bind Mount
|
||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
|
||||
volumes:
|
||||
postgres_data: # 声明命名卷
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 安全注意事项
|
||||
|
||||
#### 匿名卷可能导致数据丢失
|
||||
|
||||
运行以下命令:
|
||||
|
||||
```bash
|
||||
## 使用 --rm 运行的容器,匿名卷会在容器删除时一起删除
|
||||
|
||||
$ docker run --rm mysql:8.0
|
||||
## 容器停止后,数据丢失!
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
|
||||
**解决**:始终使用命名卷
|
||||
|
||||
```bash
|
||||
$ docker run -v mysql_data:/var/lib/mysql mysql:8.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 最佳实践
|
||||
|
||||
#### 1. 定义必须持久化的路径
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 数据库必须使用卷
|
||||
|
||||
FROM postgres:15
|
||||
VOLUME /var/lib/postgresql/data
|
||||
```
|
||||
|
||||
#### 2. 不要在 VOLUME 后修改目录
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## ❌ 避免
|
||||
|
||||
VOLUME /app/data
|
||||
RUN cp init-data.json /app/data/
|
||||
|
||||
## ✅ 正确
|
||||
|
||||
RUN mkdir -p /app/data && cp init-data.json /app/data/
|
||||
VOLUME /app/data
|
||||
```
|
||||
|
||||
#### 3. 文档中说明 VOLUME 用途
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```docker
|
||||
## 持久化用户上传的文件
|
||||
|
||||
VOLUME /app/uploads
|
||||
|
||||
## 持久化数据库数据
|
||||
|
||||
VOLUME /var/lib/mysql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 本章小结
|
||||
|
||||
| 要点 | 说明 |
|
||||
|------|------|
|
||||
| **作用** | 创建挂载点,标记为外部卷 |
|
||||
| **语法** | `VOLUME /path` |
|
||||
| **默认行为** | 自动创建匿名卷 |
|
||||
| **覆盖方式** | `docker run -v name:/path` |
|
||||
| **注意** | VOLUME 之后的修改会丢失 |
|
||||
|
||||
### 延伸阅读
|
||||
|
||||
- [数据卷](../../08_data_network/data/volume.md):卷的管理和使用
|
||||
- [挂载主机目录](../../08_data_network/data/bind-mounts.md):Bind Mount
|
||||
- [Compose 数据管理](../../compose/10.5_compose_file.md):Compose 中的卷配置
|
||||
Reference in New Issue
Block a user