设想一下,你兴致冲冲地停止了一个 Docker 容器,准备调整些配置,结果重启后发现所有数据都不见了。我个人就经历过这样的情况,那感觉可真不妙。
这其实是因为 Docker 容器默认是“短暂的”(ephemeral)——一旦容器被移除,其可写层中的所有数据就跟着烟消云散了。但实际应用显然不能这样玩。你需要数据库能持久化数据,配置文件能经受重启考验,日志也得能随时查阅。
Docker 的挂载(mount)机制正是为解决这个问题而生的,它将容器存储与外部存储位置连接起来。我们有三种主要的挂载类型:Volumes 适用于生产环境的数据持久化,Bind Mounts 专为开发工作流设计,而 tmpfs 则用于存储内存中的临时文件。
在这篇文章里,我将带你深入了解这三种挂载类型,帮助你根据实际需求,选择并正确实现最合适的存储方案。要理解本文内容,你最好对 Docker 和容器化有一些基本认识。
Docker 如何处理存储
Docker 容器采用分层文件系统,默认情况下,所有内容都被视为临时数据。
当我们构建 Docker 镜像时,Dockerfile 中的每条指令都会生成一个新的只读层。这些层像扑克牌一样堆叠在一起。比如,你拉取一个安装了 Python 的 Ubuntu 镜像,那么会有一个基础 OS 层,上面再叠一个 Python 层。
关键在于,所有这些层都是只读的,你无法直接修改它们。
容器文件系统与可写层
当你启动一个容器时,Docker 会在顶部再加一层——可写容器层。
所有的数据修改、文件创建、配置变更以及数据库记录添加,都发生在这个可写层。
听起来很棒,但问题是这一层与容器的生命周期紧密绑定。
当你使用 docker rm 命令停止并移除容器时,这个可写层也会随之消失。你之前所有的工作都会消失不见。Docker 通常不会要求你确认,它就是默默地把一切都删掉了。
这种设计对于那些无状态、不需要记住任何运行间信息的应用来说是合理的。但实际应用往往并非无状态。
为什么需要挂载
对于生产环境来说,可写层存在两个主要问题。
首先,容器停止后,数据就会丢失。一个数据库容器重启后所有数据都丢了,除了做些集成测试,我想不出还有什么用。
其次,你无法在容器之间共享数据。假设你的 Web 应用和一个后台工作进程都需要访问同一批文件。如果这些文件都存在于某个容器的可写层中,那另一个容器就完全看不到它们。
Docker 挂载解决了这两个问题,它把容器连接到独立于容器生命周期的外部存储。你可以将宿主机的目录或 Docker 管理的卷挂载到容器中。这样,即使容器被移除了,你的数据依然会保留下来。多个容器也可以挂载到同一个位置,实现文件的实时共享。
这就是为什么你需要使用挂载。接下来,我们聊聊挂载的类型,然后我会演示它们具体怎么工作。
Docker 挂载类型概览
Docker 提供了三种处理持久化数据的方式,每种都解决了不同的问题。下面我们看看每种挂载类型的作用以及适用场景。
Volumes(卷)
Volumes 是 Docker 处理持久化存储的默认方式。
Docker 会在宿主机上一个专门的目录里创建并管理这些卷。你通常不需要关心这个目录具体在哪里,Docker 会全权负责。这使得 Volumes 在不同系统间具备可移植性,并且在生产环境中可以安全使用。
当你移除一个容器时,Volume 会保持不变。如果你启动一个新容器并挂载相同的 Volume,所有数据都会原封不动地在它应在的地方。
Volumes 最适合存放生产数据库、应用程序状态以及任何你不能丢失的数据。
Bind Mounts(绑定挂载)
Bind Mounts 直接将宿主机上的某个特定目录连接到容器中。
你可以指定宿主机上精确的路径——比如 /home/user/project——Docker 会把它映射到容器内部的某个路径。当你修改了宿主机上的文件,容器会立即看到这些变化。反过来,在容器内修改文件,宿主机上也会同步更新。
这种实时同步的特性使得 Bind Mounts 成为开发环境的理想选择。
但 Bind Mounts 也有其风险。它们会将宿主机的路径暴露给容器,并且依赖于特定的目录结构,这在其他机器上可能不存在。
tmpfs Mounts(tmpfs 挂载)
tmpfs Mounts 将数据存储在宿主机的内存中,而不是磁盘上。
数据不会写入文件系统。当容器停止时,数据会彻底消失。这使得 tmpfs Mounts 对于那些你不想持久化的临时数据非常有用——比如身份验证令牌、会话数据,或者那些反正会重新生成的缓存文件。
不过,tmpfs Mounts 受限于可用的 RAM,并且只在 Linux 宿主机上工作。
Docker Volumes:持久化数据的首选
Volumes 是 Docker 生产就绪的存储解决方案,除非你有特别的理由,否则我建议你优先使用它。
它们完全由 Docker 管理,在不同平台间表现一致,并且天生设计就是为了在容器移除后依然能存活。如果你在运行数据库、存储应用状态,或者处理任何需要比单个容器生命周期更长的数据,Volumes 就是答案。
Docker Volumes 的工作原理
Docker 在宿主机的一个专用目录中存储 Volumes:
- Linux:
/var/lib/docker/volumes/ - macOS:
~/Library/Containers/com.docker.docker/Data/vms/0/data/ - Windows:
\\wsl$\docker-desktop-data\data\docker\volumes\(假设使用 WSL2 后端)
你不需要直接管理这个目录。Docker 通过其自身的 API 处理卷的创建、权限和清理。这种分离意味着无论你在 Linux、Mac 还是 Windows 上,Volumes 的工作方式都一样,这反过来又让你的容器设置在开发和生产环境之间具备可移植性。
这里要记住的是,Volumes 独立于任何容器而存在。当你创建一个 Volume,把它挂载到一个容器,运行你的应用,然后停止并删除那个容器时,Volume 依然原封不动地在那里,所有数据完好无损。
如果你启动一个新的容器并挂载相同的 Volume,你的数据仍然在那里。
创建和复用 Volumes
你可以在启动任何容器之前创建一个具名 Volume:
docker volume create mydata

然后,在运行容器时使用 --mount 标记将其挂载:
docker run -d \
--name postgres-db \
--mount source=mydata,target=/var/lib/postgresql/data \
postgres:18

这条命令将 mydata 卷挂载到容器内部的 /var/lib/postgresql/data,Postgres 数据库文件就存储在这个位置。
现在,你可以停止并移除这个容器,然后用同一个 Volume 启动一个新的容器:
docker rm -f postgres-db
docker run -d \
--name postgres-db-new \
--mount source=mydata,target=/var/lib/postgresql/data \
postgres:18
你的数据库会带着所有表和数据完好无损地回来。
这就是 Volumes 的核心目的——跨容器生命周期的数据持久化。
管理和维护 Volume 数据
你可以运行这个命令来查看系统上存在哪些 Volume:
docker volume ls

然后,你可以使用这个命令来检查某个特定的 Volume,查看它存储在哪里以及哪些容器在使用它:
docker volume inspect mydata

这会显示它在宿主机上的挂载点和一些有用的元数据。不过,你很少需要直接访问这个目录——那是 Docker 的活。
如果你不再需要某个 Volume,想把它移除,直接运行:
docker volume rm mydata
Docker 不会让你删除一个正在运行的容器所挂载的 Volume。你得先停止容器,才能移除 Volume。

最后,如果你想清理资源并回收一些磁盘空间,可以运行这个命令一次性移除所有未使用的 Volume:
docker volume prune

对于生产环境,Docker 支持 Volume 驱动程序,这些驱动可以将 Volume 连接到外部存储系统,比如 NFS、AWS EFS 或云块存储。你在创建 Volume 时指定驱动,Docker 会处理剩下的事情。这使得你可以将数据完全存储在宿主机之外,这对于容器在不同服务器之间移动的高可用性设置至关重要。
接下来,我们讨论 Bind Mounts。
Bind Mounts:本地开发的利器
Bind Mounts 让你能直接从容器内部访问宿主机文件系统,这正是开发者们钟爱它的原因。
它们非常适合本地开发,但其固有的权衡使得它们在生产环境中存在风险。你能获得实时文件同步和零构建步骤,但会牺牲可移植性,并可能引入安全漏洞。
Bind Mounts 的工作原理
Bind Mount 将宿主机上的一个特定目录直接映射到容器内部。
你指定确切的路径——比如 /home/user/myapp——Docker 会使其在容器内部的某个路径可用。这里没有文件复制、没有 Docker 管理的存储、也没有抽象层。容器看到的就是你宿主机上的真实文件。
如果你在宿主机上修改了一个文件,容器会立即看到这个变化。同样地,如果你在容器内部修改了一个文件,它也会在宿主机上更新。双方都是在实时地操作同一份文件。
这是一个实际的 Bind Mount 例子:
docker run -d \
--name dev-app \
--mount type=bind,source=/Users/dradecic/Desktop/app,target=/app \
python:3.14

这条命令将我宿主机上的 /Users/dradecic/Desktop/app 挂载到容器内部的 /app。当我用文本编辑器编辑 /Users/dradecic/Desktop/app 里的一个 Python 文件时,容器化的应用会立即感知到变化。
你也可以使用更简洁的语法:
docker run -d \
--name dev-app \
-v /Users/dradecic/Desktop/app:/app \
python:3.14
常见的开发工作流
最常见的用途是在开发期间挂载你的源代码。
比如你正在开发一个 FastAPI 应用。你可以将你的项目目录挂载到容器中,启用热重载,然后你就拥有了一个完整的开发环境:
docker run -d \
--name fastapi-dev \
--mount type=bind,source=/Users/dradecic/Desktop/app,target=/app \
-w /app \
-p 8000:8000 \
python:3.14 \
sh -c "pip install fastapi uvicorn && uvicorn main:app --reload --host 0.0.0.0"

仅供参考,这是我的 main.py 文件:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI(
title="FastAPI Docker Demo",
description="A minimal FastAPI app running inside Docker",
version="1.0.0",
)
class Item(BaseModel):
name: str
price: float
in_stock: bool = True
@app.get("/")
def read_root():
return {
"message": "FastAPI is running",
"docs": "/docs",
"redoc": "/redoc",
}
@app.get("/health")
def health_check():
return {"status": "ok"}
@app.post("/items")
def create_item(item: Item):
return {
"message": "Item received",
"item": item,
}
运行 Docker 命令后,应用就可以通过宿主机的 8000 端口访问了:

如果你在编辑器中修改 main.py 文件并保存,FastAPI 会自动重新加载。无需重新构建镜像,也无需重启容器。你像本地开发一样编写代码,但应用运行在一个一致的容器环境中。
风险与局限性
Bind Mounts 会将你的宿主机文件系统暴露给容器,这可能带来安全问题。
一个带有 Bind Mount 的容器可以读取和写入你宿主机上的文件。如果你以 root 身份运行容器(这是默认设置),那么它对这些挂载的文件就拥有了 root 权限。恶意代码或被攻破的容器可以修改或删除你整个家目录中的任何文件。
可移植性是另一个问题。
Bind Mounts 依赖于宿主机上特定路径的存在。比如 /Users/dradecic/Desktop/app 这个路径,在你的机器上或许有,但在生产服务器上肯定就没有了。这违背了容器“处处运行”的承诺。
平台差异也得考虑。Windows 和 Mac 通过虚拟机来运行 Docker,所以 Bind Mounts 经过了一个额外的翻译层。这使得文件操作变慢,并且可能导致文件监听和符号链接方面出现一些不易察觉的错误。
生产环境绝不应该使用 Bind Mounts。
它们过于依赖宿主机特定的路径,从安全角度看风险太高,而且几乎无法进行版本控制。Volumes 解决了所有这些问题,这就是为什么它们是生产环境的标准。
将 Bind Mounts 视为开发工具——快速、方便、强大,但绝不是你希望出现在生产环境中的东西。
tmpfs Mounts:处理临时数据的选择
tmpfs Mounts 将数据存储在宿主机的 RAM 中,而不是磁盘上。这使得它们非常适合那些你不想持久化的数据。
内存存储行为
一个 tmpfs 挂载完全存在于内存中。
Docker 在你的宿主机上分配 RAM,并将其作为文件系统在容器内部可用。写入 tmpfs 挂载的文件永远不会接触你的磁盘。数据会一直存在于内存中,直到容器停止。
当你停止容器时,tmpfs 挂载中的所有数据都会被删除。无需清理,不会留下任何文件,也不会有任何痕迹。每次你重新启动容器,你都会得到一个全新的、空的 tmpfs 挂载。
简而言之,tmpfs 挂载适用于你明确不想保留的数据——临时计算结果、会话令牌或不应在使用后持久化的敏感信息。
典型用例
最常见的用例是存储密钥或敏感数据。
假设你正在运行一个需要 API 密钥或数据库密码的容器。将其存储在 tmpfs 挂载中,秘密将永远不会存储在磁盘上。当容器停止时,秘密从内存中消失。这样就不会意外地将文件提交到版本控制中,或将其暴露在文件系统上。
缓存是另一个不错的选择。构建产物、编译代码或下载的依赖项,如果你反正会重新生成它们,就不需要持久化。将它们放在 tmpfs 中,以便在容器生命周期内更快地访问,然后在你完成后让它们消失。
临时文件在这里也很好用——比如会话数据、锁文件或只在容器运行时才重要的中间处理结果。
基本配置
运行此命令以使用 --tmpfs 标志创建 tmpfs 挂载:
docker run -d \
--name temp-app \
--tmpfs /tmp:rw,size=100m \
python:3.14
这会在容器内部的 /tmp 创建一个 100MB 的 tmpfs 挂载。size 选项限制了挂载可以使用的 RAM 量。
你也可以使用 --mount 语法:
docker run -d \
--name temp-app \
--mount type=tmpfs,destination=/tmp,tmpfs-size=104857600 \
python:3.14
tmpfs-size 的值以字节为单位——104857600 字节等于 100MB。
如果你不指定大小限制,tmpfs 会使用高达系统一半的 RAM。这很危险——原因很明显。请务必设置明确的大小限制。
唯一的大缺点是 tmpfs 挂载只在 Linux 上工作。
Mac 和 Windows 上的 Docker Desktop 不支持它们,因为它们在 Linux VM 中运行 Docker,而 tmpfs 需要直接的内核支持。
Docker 挂载语法与配置
Docker 提供了两种定义挂载的方式,选择正确的语法能让你的命令更易读、更便于调试。
两种方法都有效,但当你需要高级选项或在单个容器中进行多次挂载时,其中一种的可扩展性会更好。
--mount vs --volume
--mount 标志使用显式的键值对,而 -v 或 --volume 使用冒号分隔的字符串。
这是使用两种语法表示的相同 Volume 挂载:
# 使用 --mount
docker run -d \
--mount type=volume,source=mydata,target=/app/data \
python:3.14
# 使用 -v
docker run -d \
-v mydata:/app/data \
python:3.14
两者都创建一个名为 mydata 的 Volume,并将其挂载到容器中的 /app/data。
对于除了基本设置之外的任何情况,都请使用 --mount。它更冗长,但显式的键值对能清楚地表明每个部分的作用。当你添加诸如只读访问或自定义 Volume 驱动等选项时,它仍然保持可读性,而 -v 可能会变得像一串难以理解的乱码。
-v 语法对于你手动输入命令的简单开发工作流来说是没问题的。
常见的挂载选项
readonly 选项可以防止容器修改挂载的数据:
docker run -d \
--mount type=volume,source=mydata,target=/app/data,readonly \
python:3.14
这对于容器需要读取但绝不能更改的配置文件或参考数据非常有用。试图写入只读挂载的容器会收到权限错误。
对于 Volumes,volume-nocopy 选项会跳过将现有数据从容器镜像复制到 Volume 中:
docker run -d \
--mount type=volume,source=mydata,target=/app/data,volume-nocopy \
python:3.14
默认情况下,Docker 会将镜像中挂载点处的所有内容复制到一个新的 Volume。当你设置 volume-nocopy 时,无论镜像中有什么,你都会得到一个空的 Volume。
对于 tmpfs 挂载,tmpfs-size 选项设置内存限制:
docker run -d \
--mount type=tmpfs,target=/tmp,tmpfs-size=104857600 \
python:3.14
这将 tmpfs 挂载限制在 100MB。没有它,tmpfs 挂载可能会耗尽所有可用 RAM。
挂载覆盖现有数据
当你挂载到一个容器镜像中已存在的目录时,挂载的内容会完全隐藏原有的一切。
比如你的镜像里有一个 /app/data 目录,里面内置了配置文件。当你把一个 Volume 挂载到 /app/data 时,那些内置的配置文件就会“消失”。容器只能看到 Volume 里的内容。
这种情况适用于所有挂载类型——Volumes、Bind Mounts 和 tmpfs。被挂载的内容拥有优先权,原始目录在挂载激活期间变得不可访问。
在 Docker Compose 中使用挂载
Docker Compose 可以轻松地在你的应用程序堆栈中定义和共享多个容器的挂载。
你不需要手动输入冗长的 docker run 命令和挂载标志,只需在 docker-compose.yml 文件中声明一切。我来给你展示一下。
在 Compose 中定义 Volumes 和 Bind Mounts
这是一个包含 Volume 和 Bind Mount 示例的 Compose 文件:
services:
service-1:
image: ubuntu:latest
command: sleep infinity
volumes:
- ./code:/app # 用于开发的绑定挂载
- shared:/data # 与 worker 共享的具名卷
service-2:
image: ubuntu:latest
command: sleep infinity
volumes:
- shared:/data # 与 service-1 相同的卷
volumes:
shared:
每个服务下的 volumes 键定义了要挂载的内容。像 ./code 这样的相对路径创建 Bind Mounts,而像 shared 这样的名称则引用具名 Volume。
顶层的 volumes 部分声明了 Compose 将创建和管理的具名 Volume。service-1 和 service-2 都挂载了相同的 shared Volume,所以它们能看到相同的文件。在一个容器中写入文件,另一个容器可以立即读取它。
sleep infinity 命令是为了演示目的,让容器保持运行,以便你可以进入其中进行操作。
持久化与数据验证
使用 docker compose up -d 启动你的堆栈,然后检查挂载是否正常工作:
# 从 app 容器向共享卷写入数据
docker compose exec service-1 sh -c "echo 'test' > /data/file.txt"
# 从 worker 容器读取数据
docker compose exec service-2 cat /data/file.txt
如果两个命令都成功执行,说明你的 Volume 配置正确。

现在你可以运行此命令来停止并移除所有内容:
docker compose down
你的具名 Volume 仍然会存在。如果你再次使用 docker compose up -d 启动堆栈,你之前写入的数据仍然在那里。这就是数据库在多次部署中持久化的方式——Volume 的生命周期比容器长。
要在停止堆栈时删除 Volume,请添加 -v 标志:
docker compose down -v
这会移除 Compose 文件中定义的所有 Volume。当你想要一个干净的开始时,可以使用它。
使用初始数据填充 Volume
最常见的模式是使用一个单独的初始化容器来为共享 Volume 注入初始数据:
services:
init:
image: ubuntu:latest
command: sh -c "mkdir -p /source && echo 'initial data' > /source/seed.txt && cp /source/* /dest/"
volumes:
- shared:/dest
service-1:
image: ubuntu:latest
command: sleep infinity
depends_on:
- init
volumes:
- shared:/data
service-2:
image: ubuntu:latest
command: sleep infinity
depends_on:
- init
volumes:
- shared:/data
volumes:
shared:
init 容器创建种子数据并将其复制到 shared Volume 中,然后退出。service-1 和 service-2 在其后启动,然后就能使用这些已填充的数据了。

Compose 完美地处理了在单个版本控制文件中协调多个容器及其共享存储的复杂性。
Docker 挂载的性能与安全考量
选择错误的挂载类型可能会拖慢你的容器,甚至会产生你从未察觉到的安全漏洞。如果你不想遇到这些麻烦,那就认真阅读这一节。
不同挂载类型间的性能权衡
Volumes 在 Linux 上表现出最佳性能,因为它们直接存储在宿主机文件系统上,没有额外的转换层。
在 Mac 和 Windows 上,Docker 运行在一个 Linux 虚拟机内部。Volumes 仍然表现良好,因为它们始终留在虚拟机内部。另一方面,Bind Mounts 必须在宿主操作系统和 Linux 虚拟机之间同步文件,这会增加开销。在 Mac 和 Windows 上,Bind Mounts 的文件操作明显比原生 Linux 慢。
tmpfs 是读写操作最快的选项,因为所有操作都在 RAM 中进行。没有磁盘 I/O,也没有文件系统开销。但你受限于可用内存,并且数据会在容器停止时消失。
如果你在 Linux 上,需要最高性能,请使用 Volumes。如果你在 Mac 或 Windows 上,并且在开发过程中发现文件操作缓慢,那很可能是因为 Bind Mount 的开销。对于生产工作负载,请切换到 Volumes。
挂载的安全隐患
每一次挂载都让容器能够访问其隔离文件系统之外的东西,这会带来风险。
Bind Mounts 是最大的隐患。如果你将 /home/user 挂载到容器中,一个被攻破的容器就能读取你的 SSH 密钥,修改你的 shell 配置,或者删除你整个家目录中的文件。如果以 root 身份运行该容器(这是默认设置),它就拥有对这些文件的 root 级别访问权限。
Volumes 降低了这种风险,因为它们被隔离在 Docker 的存储目录中。容器无法通过 Volumes 挂载任意宿主路径。但如果你不小心共享 Volumes,它们仍然可能在容器之间泄露数据。
tmpfs 挂载将持久化风险降到最低——存储在内存中的秘密会在容器停止时消失。但它们无法防止运行时攻击,例如被攻破的容器从内存中读取秘密。
一般的经验法则是,挂载会打破容器的隔离性,所以请谨慎使用。
安全挂载的最佳实践
只挂载容器需要的东西,不多不少。
与其挂载整个项目目录,不如只挂载容器使用的子目录。与其以写入权限挂载 /var/log,如果容器只需要读取日志,就将其设置为只读。
尽可能使用 readonly 选项:
docker run -d \
--mount type=bind,source=/app/config,target=/config,readonly \
ubuntu:latest
这可以防止容器修改挂载的数据,从而在容器被攻破时限制损害。
以非 root 用户身份运行容器,以减少 Bind Mount 漏洞的影响。在你的 Dockerfile 中创建一个用户,并在容器启动前切换到该用户:
RUN useradd -m appuser
USER appuser
定期使用 docker volume prune 清理未使用的 Volume。旧的 Volume 会随着时间的推移而堆积,它们会占用磁盘空间,并可能包含已删除容器的敏感数据。
除非你有特定的理由并了解风险,否则永远不要挂载敏感的宿主目录,如 /、/etc 或 /var。每个挂载都应该有明确的目的和最小的范围。
Docker 挂载问题排查
挂载问题通常表现为权限错误、文件丢失或容器无法启动——而这些问题几乎总是由相同的原因引起的。
下面我来告诉你如何诊断并修复你最常遇到的问题。
权限和所有权错误
当容器内部的用户没有权限访问挂载的文件时,就会发生权限错误。
Docker 容器默认以 root 身份运行。当 root 用户在 Bind Mount 中创建一个文件时,该文件在你的宿主机上就归 root 所有。如果你试图用你的普通用户账户编辑它,就会收到权限拒绝错误。
反之亦然。如果你将一个你拥有的目录挂载到一个以非 root 用户运行的容器中,容器可能无法写入该目录。
你可以用 ls -la 命令检查挂载目录的文件所有权:
ls -la /path/to/mounted/directory
如果文件归 root 所有,但你的容器以不同的用户运行,那么就出现了不匹配。通过以拥有这些文件的相同用户身份运行容器来解决它:
docker run -d \
--user $(id -u):$(id -g) \
-v ./data:/app/data \
ubuntu:latest
这会以你当前的用户而不是 root 身份运行容器,从而与 Bind Mount 中文件的所有权匹配。
对于 Volumes,Docker 在容器创建文件时会自动处理权限。但如果你遇到错误,请检查容器化应用程序以哪个用户运行,以及它是否具有对挂载点的写入权限。
路径和配置错误
最常见的错误是挂载了宿主机上不存在的路径。
如果你试图挂载 /home/user/project,但该目录不存在,Docker 会创建一个由 root 拥有的空目录。你的容器会启动,但它挂载的是错误的东西——一个空目录而不是你实际的项目。
在挂载路径之前,务必验证路径是否存在:
ls /home/user/project
如果目录不存在,请先创建它,或者在挂载命令中修正路径。
在 Docker Compose 中,相对路径是相对于包含 docker-compose.yml 文件的目录解析的。如果你的文件在 /home/user/app/ 中,并且你使用 ./data,Docker 会寻找 /home/user/app/data。
移动 Compose 文件,挂载就会失效。
另一个常见错误是挂载到容器内部的错误目标路径。如果你挂载到 /app/data,但你的应用程序期望数据在 /data,那么应用程序将无法找到其文件。请检查你的应用程序文档或 Dockerfile,确认它期望数据位于何处。
平台特定的怪癖
在 Linux 上,Bind Mounts 直接与宿主机文件系统交互。
在 Mac 和 Windows 上,Docker 运行在 Linux 虚拟机内部。Bind Mounts 在你的宿主操作系统和该虚拟机之间同步文件,这会产生时间问题。文件观察器——当文件更改时重新加载你应用程序的工具——有时会因为同步延迟而错过更新。
Mac 和 Windows 对文件权限的处理方式也不同。虚拟机在宿主操作系统和 Linux 之间转换权限,这可能导致文件在容器内部显示不正确的权限。
符号链接在 Mac 和 Windows 上的 Bind Mounts 中不可靠。虚拟机并非总是能够解析指向挂载目录之外的符号链接,因此文件在容器内部可能会显示为丢失或损坏。
tmpfs 挂载在 Mac 和 Windows 上根本不起作用,因为虚拟机不会将 tmpfs 暴露给宿主机。如果你尝试使用 tmpfs 挂载,Docker 会根据版本默默忽略它或抛出错误。
如果你在 Mac 或 Windows 上开发,并且遇到奇怪的文件同步问题,请切换到具名 Volumes 以获得更好的性能和可靠性。将 Bind Mounts 保留给那些实时同步比完美一致性更重要的开发工作流。
总结
总的来说,对于那些需要持久化保存的生产数据,比如数据库、上传文件、应用状态——任何你不能丢失的东西,都请使用 Volumes。它们由 Docker 管理,跨平台可移植,是保护重要数据的最安全选择。
Bind Mounts 适用于那些需要宿主机和容器之间实时文件同步的开发工作流。当你用编辑器编辑代码时,你的容器化应用会立即看到变化。但请把它们留在生产环境之外,因为它们过于依赖宿主机特定的路径,并且会带来不必要的安全风险。
关于容器化和虚拟化,如果你准备深入学习,可以查阅我们相关的课程。
关于
关注我获取更多资讯