如何把宿主机目录挂载进 Docker 容器?
docker run -v /宿主机/路径:/容器/路径 即绑定挂载,实时双向同步;加 :ro 只读。Dockerfile 里不能做主机挂载(不可移植),ADD/COPY 是构建期拷贝不是挂载。本文讲清区别与坑。
做法:docker run -v /host/dir:/container/dir 镜像——绑定挂载(bind mount),宿主机目录与容器目录实时同步,容器删了宿主机文件还在。注意 Dockerfile 里无法做主机挂载(镜像要可移植,宿主路径因机而异),挂载只能在运行时指定;Dockerfile 的 ADD/COPY 是构建期拷贝副本,后续改动不同步。
基本用法
# 挂载配置目录
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) | |
|---|---|---|
| 时机 | 运行时 | 构建时 |
| 宿主机后续改动 | 容器实时可见 | 不可见(拷的是当时的副本) |
| 容器删除后 | 数据保留在宿主机 | 镜像层不动,容器层丢失 |
| 可移植性 | 依赖宿主路径 | 镜像自给自足 |
常见坑
- 宿主机目录不存在:Docker 会自动创建为 root 属主的空目录——多半不是你要的,挂载前先确认路径
- 权限不匹配:容器内进程 UID 与宿主机文件属主不一致导致读写失败,按需 chown 或用
--user对齐 - SELinux(RHEL/CentOS):挂载加
:z或:Z重新打标签,否则容器内 permission denied - 挂载单文件后被编辑器覆盖:vim 等编辑器"另存替换"会换 inode,挂载的单文件句柄失效——改挂载其所在目录
挂载 vs 命名卷
配置、代码、要直接查看的日志 → 绑定挂载;数据库数据等应用自管理的数据 → 命名卷更省心(权限初始化 Docker 会帮忙做)。
观测云对照
日志目录挂载后采集更直接。 应用日志目录绑定挂载到宿主机规范路径(如 /var/log/apps/),DataKit 按主机路径采集,容器重建、多副本扩缩都不影响日志链路。
常见问题(FAQ)
Q:容器内写入的文件在宿主机看不到?
A:确认挂载方向没写反(左边是宿主机);容器内写到了挂载点之外的路径也会"看不到"。
Q:Mac/Windows 上挂载很慢?
A:Desktop 的虚拟化文件共享开销大,大目录用命名卷或 delegated 挂载选项改善。
Q:能挂载不存在的容器路径吗?
A:会照挂——容器内该路径被遮蔽成挂载内容,镜像里原有的同路径文件被盖住。