Docker 容器读不到宿主机文件?匿名 Volume 覆盖 Bind Mount
· 阅读需 3 分钟
在为客户部署 WordPress 站点时遇到此问题,记录根因与解法。
TL;DR
镜像 Dockerfile 中的 VOLUME 声明会创建匿名卷,挂载优先级高于 docker-compose.yml 的 bind mount。解决方案:停止容器 → 删除匿名卷 → 重启。
问题现象
CI 部署后,新增的静态文件或 PHP 代码在容器内不存在:
assets/images/logo.png宿主机存在,容器内无 → Logo 不显示inc/setup.php新增 filter 代码,容器内是旧版本 → Filter 不生效git pull后文件已更新,容器内仍是旧内容
根因
WordPress 官方镜像的 Dockerfile 包含:
VOLUME /var/www/html
即使你的 docker-compose.yml 配置了 bind mount:
volumes:
- ./wordpress/wp-content:/var/www/html/wp-content
Docker 仍会为 VOLUME 声明的路径创建匿名卷,匿名卷的挂载优先级高于 bind mount,导致:
/var/www/html被匿名卷接管- 你的 bind mount 只挂载到
/var/www/html/wp-content - 但匿名卷已经"占领"了父目录,bind mount 实际上被覆盖
用 docker inspect 验证:
docker inspect prod_wordpress --format '{{range .Mounts}}{{.Type}}: {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
输出类似:
volume: /var/lib/docker/volumes/wp-prod_wp_html/_data -> /var/www/html# 匿名卷!
bind:/var/www/wp-prod/wordpress/wp-content -> /var/www/html/wp-content
解决方案
# 1. 停止容器
cd /var/www/wp-prod && docker compose down
# 2. 删除匿名卷
docker volume rm wp-prod_wp_html
# 3. 重启
docker compose up -d
验证
docker inspect prod_wordpress --format '{{range .Mounts}}{{.Type}}: {{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
应只显示 bind mount,无匿名 volume:
bind: /var/www/wp-prod/wordpress/wp-content -> /var/www/html/wp-content
预防
使用 bind mount 部署时,检查镜像是否声明了 VOLUME。如果声明了:
- 首次启动前,确认没有残留的匿名卷
- 或者修改 docker-compose.yml,让 bind mount 路径与 VOLUME 路径一致(挂载到同一层级)
修复后,git pull 更新代码时容器自动读取新文件,无需 docker cp 或重启容器。
注意事项
- 删除匿名卷前确保数据已备份或可通过git pull 恢复
- 生产环境操作前先在测试环境验证
- 如果容器内有关键数据,先用
docker cp备份