解析Docker构建时WORKDIR与主机挂载卷的交互机制
问题
我有一个单仓库(monorepo),对应的docker-compose.yml配置如下:
version: '3' services: alpha: build: context: . dockerfile: projects/alpha/Dockerfile target: alpha restart: always ports: - "8080:80" volumes: - ./projects/alpha:/projects/alpha
对应的Dockerfile内容为:
FROM python:3.11.3-slim as builder # Make / set a working directory WORKDIR /projects/alpha # Install Poetry and system dependencies RUN apt update && ... (install necessary apt packages) # Copy pyproject.toml / poetry.lock COPY projects/alpha/pyproject.toml projects/alpha/poetry.lock* ./ # Poetry install RUN poetry install --no-interaction --no-ansi # Copy source COPY projects/alpha ./ # Add a random file to the directory RUN touch ./RANDO.md FROM builder as alpha CMD gunicorn --reload -w 3 -b 0.0.0.0:80 -k uvicorn.workers.UvicornWorker alpha.asgi:application
当前场景下,gunicorn的--reload参数可在主机修改Python模块时重新加载工作进程,但未挂载主机目录则无法实现该效果。不过我发现:构建阶段通过RUN touch ./RANDO.md创建的RANDO.md文件在容器和主机目录中均不存在;而进入容器后手动执行touch RANDO.md创建的该文件可在容器和主机双向可见。请问Docker构建阶段执行WORKDIR /projects/alpha时,容器内和主机挂载目录实际发生了什么?
回答
- Docker的构建阶段和容器运行阶段是完全独立的两个流程:
- 执行构建时(
docker build或docker-compose build),根本不会涉及主机目录的挂载。此时WORKDIR /projects/alpha只是在构建的镜像层里创建这个目录(如果不存在),并把后续命令的工作目录切换到这里。你在构建阶段用RUN touch ./RANDO.md创建的文件,只保存在镜像的文件系统层中。
- 执行构建时(
- 当通过
docker-compose up启动容器时,你配置的volumes: - ./projects/alpha:/projects/alpha会用主机的./projects/alpha目录直接覆盖容器内的/projects/alpha目录。这就导致镜像层里原本存在的RANDO.md被主机目录的内容替换掉了——因为主机目录里没有这个文件,所以容器启动后自然看不到它。 - 你进入容器后手动创建
RANDO.md时,这个操作是直接在挂载的主机目录上进行的,所以主机和容器两边都能看到这个文件。
总结一下:构建阶段的操作只作用于镜像,启动容器时挂载的主机目录会覆盖镜像中对应路径的内容,所以构建出来的文件被覆盖消失;手动创建的文件是写在挂载的主机目录里,因此双向可见。
内容的提问来源于stack exchange,提问作者orokusaki
相关产品推荐
相关产品推荐

