Docker中将含文件目录作为卷:容器文件无法同步至主机目录
Docker的bind mount(你通过local卷配置的bind模式)核心行为是主机目录会覆盖容器内对应目录的内容,而非同步镜像里的文件到主机。你构建镜像时已把代码放到容器的/srv/var/www/p_parser目录,但启动容器时用bind mount将主机./data/p_parser挂载到该路径,此时容器内的这个目录会被主机空目录替换。你看到的“容器内目录存在文件”大概率是镜像里的目录内容,而非运行中容器的实际目录(运行中容器的该目录实际是挂载的空主机目录)。
另外,你配置的device: ./data/p_parser存在路径解析问题:Docker daemon处理bind mount相对路径时,默认以daemon工作目录(通常为/)为基准,而非你的docker-compose.yml所在目录,导致实际挂载的是主机根目录下的/data/p_parser,而非你预期的当前项目目录下的子目录。
方案1:修复路径解析问题
将bind mount的设备路径改为绝对路径,利用docker-compose的${PWD}变量自动获取当前compose文件所在目录的绝对路径:
volumes: p_parser_volume: driver: local driver_opts: device: ${PWD}/data/p_parser o: bind type: none
也可以直接写死绝对路径,比如/home/your-user/project/data/p_parser。
方案2:同步镜像内初始文件到挂载目录
如果需要把镜像里的初始代码同步到主机挂载目录,可添加初始化脚本,在容器启动时仅当挂载目录为空时复制文件:
步骤1:创建初始化脚本
在./build/parser/目录下创建init.sh文件:
#!/bin/sh # 检查挂载目录是否为空 if [ -z "$(ls -A /srv/var/www/p_parser)" ]; then # 复制镜像内的初始文件到挂载目录 cp -r /var/www/parser/. /srv/var/www/p_parser/ fi # 执行容器原本的启动命令 exec "$@"
步骤2:修改Dockerfile
在Dockerfile中添加以下内容,将脚本设为ENTRYPOINT:
# 复制初始化脚本 COPY init.sh /usr/local/bin/ # 赋予执行权限 RUN chmod +x /usr/local/bin/init.sh # 设置ENTRYPOINT ENTRYPOINT ["init.sh"] # 保留原本的CMD命令(如果有) # CMD ["your-original-start-command"]
步骤3:重启容器
重新构建镜像并启动容器:
docker-compose down && docker-compose build && docker-compose up -d
方案3:调整目录结构(推荐)
避免直接挂载镜像内已有内容的目录,将代码与动态数据目录分离:
- 构建镜像时将代码放在
/var/www/parser(你已设置为working_dir) - 将挂载目录改为
/srv/var/www/p_parser/data,仅用于存储动态生成的数据 - 在应用配置中指定动态数据存储到该挂载目录
这样既保留了镜像内的代码,又能通过挂载目录持久化动态数据。
内容的提问来源于stack exchange,提问作者Newbie

