You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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.ymlvolumes部分:

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复制到挂载目录:

  1. project目录下创建entrypoint.sh脚本:
#!/bin/bash
# 先把镜像里的code目录复制到挂载的html目录
cp -r /var/www/html-template/code /var/www/html/code
# 执行WordPress原本的entrypoint脚本,保证容器正常启动
exec docker-entrypoint.sh "$@"
  1. 修改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

火山引擎 最新活动