如何把宿主机目录挂载进 Docker 容器?
docker run -v /宿主机/路径:/容器/路径 即绑定挂载,共享文件系统视图;加 :ro 只读。Dockerfile 不能声明部署时的宿主机绑定挂载,ADD/COPY 是构建期拷贝不是挂载。本文讲清区别与坑。
做法:docker run -v /host/dir:/container/dir 镜像——绑定挂载(bind mount),容器访问的是宿主机目录的文件系统视图,不是两个目录的同步副本;删除容器不删除该目录,但容器内删除挂载文件也会影响宿主机。部署时的绑定挂载在运行配置中指定;Dockerfile 的 RUN --mount=type=bind 则是构建步骤内的临时挂载,不会固化运行时挂载;Dockerfile 的 ADD/COPY 是构建期拷贝副本,后续改动不同步。
这里的宿主机指 Docker daemon 所在主机;远程 Docker 客户端不能直接把本机目录作为远端 daemon 的绑定源。
基本用法
# 挂载配置目录
docker run -d -v /opt/app/conf:/etc/app/conf myimage
# 只读挂载(配置防改)
docker run -d -v /opt/app/conf:/etc/app/conf:ro myimage
# 挂载单个文件
docker run -d -v /opt/app/app.yml:/etc/app/app.yml myimage
compose 写法:
services:
app:
volumes:
- /opt/app/conf:/etc/app/conf:ro
- ./logs:/var/log/app
与 ADD/COPY 的本质区别
| 绑定挂载(-v) | ADD/COPY(Dockerfile) | |
|---|---|---|
| 时机 | 运行时 | 构建时 |
| 宿主机后续改动 | 访问同一文件系统视图,仍受应用缓存等影响 | 不可见(拷的是当时的副本) |
| 容器删除后 | 数据保留在宿主机 | 镜像层不动,容器层丢失 |
| 可移植性 | 依赖宿主路径 | 镜像自给自足 |
常见坑
- 宿主机目录不存在:
-v会创建缺失路径为目录;--mount type=bind默认会报错。属主还取决于 daemon 与用户映射,挂载前先确认路径 - 权限不匹配:容器内进程 UID 与宿主机文件属主不一致导致读写失败,按需 chown 或用
--user对齐 - SELinux(RHEL/CentOS):挂载加
:z或:Z重新打标签,否则容器内 permission denied - 挂载单文件后被编辑器覆盖:vim 等编辑器"另存替换"会换 inode,挂载仍可能指向旧 inode,读不到替换后的文件——可改挂载其所在目录
挂载 vs 命名卷
配置、代码、要直接查看的日志 → 绑定挂载;数据库数据等应用自管理的数据 → 命名卷便于管理,但应用需要的 UID/GID、权限及初始化仍要核对。
日志目录使用绑定挂载时,先核对宿主机路径和文件属主。观测云 DataKit 可按文件采集配置读取该路径;容器重建后再写一条测试日志,检查是否仍能采集,避免多个副本写入同名文件后无法区分来源。
常见问题(FAQ)
Q:容器内写入的文件在宿主机看不到?
A:确认挂载方向没写反(左边是宿主机);容器内写到了挂载点之外的路径也会"看不到"。
Q:Mac/Windows 上挂载很慢?
A:性能取决于 Desktop 版本与文件共享后端;可测试命名卷或当前版本的同步文件共享功能,不能保证 delegated 在所有后端都有效。
Q:能挂载不存在的容器路径吗?
A:会照挂——容器内该路径被遮蔽成挂载内容,镜像里原有的同路径文件被盖住。