Dockerfile ADD命令失效:无法将目录添加至/var/www/html路径
你遇到的情况是Docker bind mount(绑定挂载) 的核心特性导致的:当你在docker-compose.yml里配置./bindmount:/var/www/html时,容器启动后,宿主机的bindmount目录会完全覆盖容器内原本的/var/www/html目录——包括你通过Dockerfile的ADD/COPY/mkdir命令在这个路径下创建的任何内容。
简单说就是:Dockerfile里的操作是在构建镜像时完成的,会把code目录放到镜像的/var/www/html下;但容器启动时,bind mount会用宿主机的空目录(或已有内容的目录)直接替换容器里的这个路径,所以你之前添加的code就被“盖”掉了。
根据你的需求,这里提供几种不同场景的解决方案:
1. 只挂载需要持久化的子目录(最常用)
WordPress的核心文件其实不需要持久化,真正需要保留的是wp-content目录(主题、插件、上传文件等)。你可以修改挂载路径,只挂载这个子目录,这样镜像里的/var/www/html/code就不会被覆盖:
修改docker-compose.yml的volumes部分:
volumes: - ./bindmount/wp-content:/var/www/html/wp-content
这样容器启动后,/var/www/html/code依然存在,宿主机的bindmount只管理需要持久化的内容,两全其美。
2. 把code目录放到挂载路径之外
如果你的code目录不需要和WordPress的核心文件在同一路径,可以修改Dockerfile,把它放到/var/www/html之外的位置:
修改project/Dockerfile:
FROM wordpress # 把code放到/var/www下,避开被挂载覆盖的路径 ADD ./code /var/www/code
之后你可以在WordPress代码里通过绝对路径/var/www/code引用这个目录,或者用符号链接把它链接到/var/www/html(注意设置好权限)。
3. 容器启动时自动复制code到挂载目录
如果你必须把code放在/var/www/html下,同时又要使用bind mount,可以通过自定义entrypoint脚本,在容器启动后自动把code复制到挂载目录:
- 在
project目录下创建entrypoint.sh脚本:
#!/bin/bash # 先把镜像里的code目录复制到挂载的html目录 cp -r /var/www/html-template/code /var/www/html/code # 执行WordPress原本的entrypoint脚本,保证容器正常启动 exec docker-entrypoint.sh "$@"
- 修改
project/Dockerfile,添加脚本并设置为新的entrypoint:
FROM wordpress # 先把code放到一个不会被覆盖的临时目录 ADD ./code /var/www/html-template/code # 添加自定义entrypoint脚本 ADD entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/entrypoint.sh # 设置新的entrypoint ENTRYPOINT ["entrypoint.sh"]
这样每次容器启动,都会自动把code复制到被挂载的/var/www/html目录里,既保留了bind mount的持久化能力,又能让code目录正常可用。
4. 使用Named Volume代替Bind Mount(推荐)
Docker的Named Volume(命名卷) 有一个非常实用的特性:当你第一次挂载命名卷到容器目录时,Docker会自动把容器目录里的所有内容(包括你Dockerfile添加的code)复制到卷里。之后启动容器时,卷里的内容会被挂载到容器,不会覆盖,而是继承初始内容。
修改docker-compose.yml:
version: '3.1' services: wordpress: build: ./project ports: - 80:80 volumes: - wp-wordpress-data:/var/www/html # 使用命名卷 environment: WORDPRESS_DB_PASSWORD: example mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: example # 定义命名卷 volumes: wp-wordpress-data:
第一次启动容器后,code目录会被自动复制到wp-wordpress-data卷里,之后即使重启容器,code也会存在,同时卷里的内容会持久化保存。
内容的提问来源于stack exchange,提问作者Anand Naik B




