容器内文件系统的更改未反映在 docker 卷中的主机上

met*_*ord 0 docker docker-compose

我正在使用 TypeScript 编写的 Express 服务器。项目的流程是我有一个 npm 构建脚本,它在 src 文件夹中获取项目文件并将它们编译到 dist 文件夹。这两个文件夹都位于根目录下。该项目有效,但是在尝试将所有内容移动到 docker 时,虽然我正在安装卷并且构建的文件(dist 目录)在容器中,但更改并未反映在主机上。(我正在为 Docker 使用 Windows + VirtualBox)

我已经提到了这个这个问题。我看到他们的场景是一样的,但他们的解决方案似乎对我不起作用。我确保我使用了这些答案中提到的类似技术,它们似乎不起作用。

项目目录结构:

??? Backend
?   ??? src/
?   ?   ??? controllers/
?   ?   ??? models/
?   ?   ??? routes/
?   ?   ??? services/
?   ?   ??? index.ts
?   ?   ??? server.ts
?   ??? dist/ (Created upon compilation)
?   ?   ??? controllers/
?   ?   ??? data/ (Created upon starting the server)
?   ?   ??? models/
?   ?   ??? routes/
?   ?   ??? services/
?   ?   ??? index.js
?   ?   ??? server.js
?   ??? Dockerfile
?   ??? package.json
?   ??? tsconfig.json
?   ??? tslint.json
?   ??? .env
??? Frontend/ (This part is an independent application)
??? docker-compose.yml
??? README.md

Run Code Online (Sandbox Code Playgroud)

当服务器启动时,它会在%proj_root%/Backend/distnamed 中创建一个目录,data用于通过 txt 文件向应用程序提供输入。从我在 Dockerfile 中放入的 ls 命令可以看出,编译工作正常,但是在容器内部所做的更改(创建 dist 目录)并未反映在主机上。在主机上,dist 目录为空,导致服务器崩溃,因为没有 server.js 文件。

这是我的 docker-compose.yml:

version: "3"
services:
  backend:
    build:
      context: ./Backend/
    volumes:
      - ./Backend/dist:/app/dist
      - /app/node_modules
      - ./Backend:/app
  frontend:
    build:
      context: ./Frontend
    ports:
      - "3001:8080"
    volumes:
      - /app/node_modules
      - ./Frontend:/app
Run Code Online (Sandbox Code Playgroud)

这是后端服务的 Dockerfile:

FROM node:8
WORKDIR /app
COPY ./package.json .
RUN npm install
COPY . . # Copying everything to enable standalone usage
RUN ls # Logging before tsc build
RUN npm run build
RUN ls /app/dist # Logging after tsc build. All the built files are visible.
CMD ["npm", "run", "start"]
Run Code Online (Sandbox Code Playgroud)

运行时docker-compose up,应在容器 ( /app/dist) 中创建一个 dist 文件夹,并应在主机上反映为%proj_root%/Backend/dist

我知道我可以创建一个脚本来编译 TS 然后运行 ​​docker-compose,但这对我来说似乎是一种hacky 方法。有更好的解决方案吗?

Dav*_*aze 7

docker-compose.yml您展示的设置做了两个独立的事情。首先,它构建一个 Docker 镜像,使用Dockerfile你单独提供的。其次,它获取该映像,安装卷并应用其他设置,并基于这些设置运行容器。Docker 镜像构建序列会忽略所有这些其他设置;您在 Dockerfile 中所做的任何事情都无法更改主机系统上的文件。

当您运行容器时,volumes:您传入的设置中的任何内容都会完全替换该图像中的内容。这始终是一种单向“推入容器”:在容器中Backend替换主机目录/app的内容;匿名卷的内容替换其node_modules,主机list目录的内容替换/app/dist

对此有一种特殊情况。启动容器时,如果卷挂载为空,则映像中的内容将复制到卷中。仅当卷树中完全没有任何内容时才会发生这种情况。如果dist主机目录或node_modules匿名卷中已经有内容,这将替换映像中的任何内容,即使它在映像中发生了变化(或者在卷中发生了变化,Docker 无法判断)。

作为一次性的解决方法,如果您

rm -rf dist
Run Code Online (Sandbox Code Playgroud)

那么下次启动容器时,Docker 会注意到该dist目录为空并从映像中重新填充它。

我建议完全删除这些volumes:设置。如果您正在积极开发软件,请在主机上进行:使用典型的操作系统包管理器安装 Node 非常容易,您的 IDE 不会被隐藏在容器内的 Node 解释器混淆,并且您不会点击这种问题。当您进行部署时,您可以直接使用 Docker 镜像,而无需单独分发镜像内的代码。