Skip to content

绑定挂载

绑定挂载(Bind Mount)将宿主机的文件或目录直接挂载到容器中,是开发环境中最常用的数据共享方式。

绑定挂载与数据卷的区别

特性绑定挂载数据卷
存储位置宿主机任意目录Docker 管理目录
管理方式由宿主机操作系统管理由 Docker 管理
可见性双向可见(宿主机和容器)主要在容器中
适用场景开发调试、配置文件生产数据持久化
跨平台性能macOS/Windows 较慢性能更好

基本用法

-v 语法

bash
# 挂载目录
docker run -d \
  -v /host/path:/container/path \
  nginx

# 挂载单个文件
docker run -d \
  -v /host/nginx.conf:/etc/nginx/nginx.conf \
  nginx

# 只读挂载(:ro)
docker run -d \
  -v /host/config:/app/config:ro \
  myapp

--mount 语法(推荐,更清晰)

bash
# 挂载目录
docker run -d \
  --mount type=bind,source=/host/path,target=/container/path \
  nginx

# 只读挂载
docker run -d \
  --mount type=bind,source=/host/config,target=/app/config,readonly \
  myapp

# 挂载文件
docker run -d \
  --mount type=bind,source=/host/nginx.conf,target=/etc/nginx/nginx.conf,readonly \
  nginx

开发环境应用

Node.js 开发热更新

bash
# 挂载源码,配合 nodemon 实现热更新
docker run -d \
  --name node-dev \
  -v $(pwd):/app \
  -w /app \
  -p 3000:3000 \
  node:20-alpine \
  sh -c "npm install && npx nodemon app.js"

package.json 中的 dev 脚本:

json
{
  "scripts": {
    "dev": "nodemon --watch src src/app.js"
  }
}

Python Django 开发

bash
docker run -d \
  --name django-dev \
  -v $(pwd):/app \
  -w /app \
  -p 8000:8000 \
  python:3.12-slim \
  sh -c "pip install -r requirements.txt && python manage.py runserver 0.0.0.0:8000"

Vue/React 前端开发

bash
docker run -d \
  --name frontend-dev \
  -v $(pwd):/app \
  -v /app/node_modules \          # 排除 node_modules(使用容器内的)
  -w /app \
  -p 5173:5173 \
  node:20-alpine \
  sh -c "npm install && npm run dev -- --host"

技巧:使用 -v /app/node_modules 创建匿名卷,覆盖宿主机的 node_modules,避免宿主机和容器的依赖冲突(尤其是 macOS 和 Linux 的原生模块差异)。

挂载配置文件

Nginx 配置挂载

bash
# 挂载自定义 Nginx 配置
docker run -d \
  --name nginx \
  -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro \
  -v $(pwd)/conf.d:/etc/nginx/conf.d:ro \
  -v $(pwd)/html:/usr/share/nginx/html:ro \
  -p 80:80 \
  nginx:alpine

MySQL 配置挂载

bash
docker run -d \
  --name mysql \
  -v $(pwd)/my.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  -v mysql-data:/var/lib/mysql \
  -e MYSQL_ROOT_PASSWORD=secret \
  mysql:8.0

my.cnf 示例:

ini
[mysqld]
max_connections=200
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
slow_query_log=1
slow_query_log_file=/var/log/mysql/slow.log
long_query_time=2

路径注意事项

Linux/macOS

bash
# 使用绝对路径
docker run -v /home/user/data:/data nginx

# 使用 $PWD 当前目录
docker run -v $(pwd)/data:/data nginx

# 使用 ~ 家目录
docker run -v ~/data:/data nginx

Windows

powershell
# PowerShell
docker run -v C:\Users\user\data:/data nginx

# 使用 $PWD
docker run -v ${PWD}\data:/data nginx

# 或者用正斜杠
docker run -v //c/Users/user/data:/data nginx

权限问题

容器内文件权限

bash
# 查看文件权限
docker exec mycontainer ls -la /app

# 挂载时设置权限
docker run -d \
  --mount type=bind,source=$(pwd),target=/app \
  --user $(id -u):$(id -g) \  # 使用当前用户的 UID:GID
  node:20-alpine \
  node app.js

SELinux 标签(CentOS/RHEL)

bash
# :z 自动重新标记(共享)
docker run -v $(pwd):/app:z myapp

# :Z 专用标签(不共享)
docker run -v $(pwd):/app:Z myapp

绑定挂载的性能优化

在 macOS 上,Docker 通过虚拟机访问宿主机文件系统,性能较慢。优化方式:

使用 :cached 或 :delegated(旧版优化,已被 virtiofs 替代)

bash
# macOS Docker Desktop 使用 virtiofs(更快的文件共享)
# 在 Settings → General 中开启 "Use VirtioFS"

将频繁访问的目录放在容器卷中

bash
# node_modules 放在容器内(避免跨系统同步)
docker run -d \
  -v $(pwd):/app \
  -v /app/node_modules \   # 匿名卷,覆盖宿主机的 node_modules
  node:20-alpine \
  npm start

常见问题

挂载目录为空

原因:挂载的宿主机目录覆盖了容器内的目录内容。

bash
# 如果需要容器内的初始文件,先复制出来
docker run --rm -v $(pwd)/config:/tmp/config nginx:alpine \
  cp -r /etc/nginx/conf.d/. /tmp/config/

# 查看复制的内容
ls -la ./config/

权限被拒绝(Permission denied)

bash
# 方法一:以 root 用户运行(不推荐生产)
docker run -u root myapp

# 方法二:在容器内修改权限
docker run -d myapp
docker exec -u root myapp chown -R appuser:appuser /app

# 方法三:使用正确的 UID 运行
docker run --user $(id -u):$(id -g) myapp

总结

绑定挂载的核心使用场景:

  1. 开发环境:挂载代码目录,修改即生效,无需重建镜像
  2. 配置文件:挂载外部配置,灵活修改不重建镜像
  3. 日志输出:将容器日志输出到宿主机,便于收集
  4. 静态资源:Nginx 静态文件服务

原则:开发用绑定挂载(灵活),生产用命名卷(稳定可靠)。