我正在使用TypeScript编写的Express服务器。项目的流程是我有一个npm构建脚本,它将项目文件放在src文件夹中并将它们编译到dist文件夹中。这两个文件夹都位于根目录下。该项目有效,但在尝试将所有内容移动到docker时,虽然我正在安装卷,并且容器中存在构建的文件(dist目录),但更改不会反映在主机上。 (我使用Windows + VirtualBox for Docker)
我提到了this和this问题。我看到他们的情况是一样的,但他们的解决方案似乎对我不起作用。我确信我使用的答案中提到的类似技术,它们似乎不起作用。
项目目录结构:
├── 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
当服务器启动时,它会在%proj_root%/Backend/dist
中创建一个名为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
这是后端服务的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"]
在运行docker-compose up
时,应该在容器(/app/dist
)中创建一个dist文件夹,并且应该在主机上反映为%proj_root%/Backend/dist
我知道我可以创建一个编译TS然后运行docker-compose的脚本,但这看起来像是一个hacky方法。有更好的解决方案吗?
你展示的docker-compose.yml
设置有两个独立的东西。首先,它使用你单独提供的Dockerfile
构建一个Docker镜像。其次,它采用该图像,安装卷并应用其他设置,并根据这些设置运行容器。 Docker镜像构建序列忽略所有这些其他设置;您在Dockerfile中所做的任何事情都无法更改主机系统上的文件。
当您运行容器时,传入的volumes:
设置中的任何内容都完全取代了该图像的内容。这总是单向“推入容器”:主机的Backend
目录中的内容替换容器中的/app
;匿名卷的内容替换其node_modules
,主机的list
目录的内容替换/app/dist
。
这有一个特殊情况例外。启动容器时,如果卷装入为空,则映像中的内容将复制到卷中。只有在卷树中根本没有任何内容时才会发生这种情况。如果dist
主机目录或node_modules
匿名卷中已有内容,则会替换图像中的任何内容,即使它在图像中发生了更改(或在卷中更改,Docker也无法分辨)。
作为一次性解决方案,如果你
rm -rf dist
然后在下次启动容器时,Docker会注意到dist
目录为空并从图像中重新填充它。
我建议完全删除这些volumes:
设置。如果您正在积极开发软件,请在主机上执行:使用典型的操作系统软件包管理器非常容易安装节点,您的IDE不会被您的节点解释器隐藏在容器中而感到困惑,并且您不会遇到这类问题。当您进行部署时,您可以按原样使用Docker镜像,而无需单独分发也在图像中的代码。