英文:
Share volume across multiple containers
问题
我有一个情况,容器运行npm run dev
,这只是rollup -cw
,所以我们在等待前端文件的更改并创建一个捆绑包。现在的问题是,我有两个容器,一个是前端,另一个是后端。当我使用docker-compose将所有容器混合在一起时,这两个容器不共享同一个卷。所以后端不知道捆绑包何时被创建或更新。同时,我必须确保当任何更改发生(在前端)时,捆绑包也必须在主机文件中更新。如果我理解正确的话,如果我使用命名卷,那么主机文件将不会受到影响。还有其他选择吗?
这是我的根目录:
- frontend
- backend
- docker-compose.yml
捆绑包被创建到后端静态文件目录中。后端不知道捆绑包是否已更新等。所有容器都是隔离的,对吗?
frontend:
tty: true
restart: unless-stopped
stdin_open: true
build: ./frontend
container_name: frontend
volumes:
- ./frontend:/frontend # 确保npm run dev能捕捉到新的更改
django:
build: ./web
ports:
- 5050:5050
restart: always
container_name: django
command: [django, runserver, 0.0.0.0:5050]
tty: true
stdin_open: true
depends_on:
- frontend
volumes:
- .:/werent # 使用本地更改更新容器
这是rollup.config.js
:
input: "./main.ts",
output: {
format: "iife", // 立即调用的函数表达式
file: "../web/static/dist/bundle.js",
},
我应该如何使其工作?连接这两个容器并更新本地文件的最佳实践是什么?
英文:
I have a situation in which container runs a npm run dev
so this is just rollup -cw
, so we're waiting for frontend file changes and creating a bundle. Now the problem is that I have two containers, one is for frontend and the other is for backend. And when I use docker-compose to mix all containers together, these two doesn't share the same volume. So backend doesn't know when the bundle has been created or updated. Also I must ensure that when any changes happen (in fronted) the bundle also must be updated in the host files? And if I'm getting everything right, if I would use named volume then the host files will not be effected. What's the other choice?
This is my root dir:
- frontend
- backend
- docker-compose.yml
The bundle is being created to backend static files dir. And the backend doesn't know that the bundle is updated or etc. All containers are isolated, right?
frontend:
tty: true
restart: unless-stopped
stdin_open: true
build: ./frontend
container_name: frontend
volumes:
- ./frontend:/frontend # Ensure that npm run dev would catch new changes
django:
build: ./web
ports:
- 5050:5050
restart: always
container_name: django
command: [django, runserver, 0.0.0.0:5050]
tty: true
stdin_open: true
depends_on:
- frontend
volumes:
- .:/werent # Update the container with local changes
This is the rollup.config.js:
input: "./main.ts",
output: {
format: "iife", // Immediately Invoked Function Expression
file: "../web/static/dist/bundle.js",
},
How should I make this work? What's the best practice for connecting these two and also updating local files?
答案1
得分: 1
你澄清了frontend
容器只是为django
应用程序构建静态资产。它实际上不需要一个正在运行的容器来完成这个任务。更好的方法是使用多阶段构建;这使用一个node
镜像来编译前端,然后使用COPY --from
将其复制到实际的Django镜像中。
大致上看起来是这样的:
FROM node:lts AS frontend
WORKDIR /frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm build
FROM python:3.11
WORKDIR /werent
COPY web/requirements.txt ./
...
COPY --from=frontend /frontend/dist/ static/dist/
...
CMD ["django", "runserver", "0.0.0.0:5050"]
这里需要注意的一个细节是,你要访问frontend
和web
目录中的文件。这意味着Docker构建上下文目录需要是这些目录的父目录,并且COPY
的左侧需要指定要使用的子目录。
在Compose文件中,重要的是不要使用volumes:
隐藏应用程序目录。由于前端只是在Dockerfile中注入,并不一定在主机上构建,绑定挂载会隐藏镜像构建的前端应用程序的副本。你也不需要在Compose文件中使用大部分其他选项。只需要这样写就足够了:
version: '3.8'
services:
# 没有frontend容器
django:
build: ./web
ports:
- 5050:5050
restart: always
# 没有container_name:, command:, tty:, stdin_open:, volumes:
另一个重要的细节是,即使你通常在开发中使用主机工具,你仍然可以使用这个基于Docker的设置。例如,你可以启动这个容器,然后在前端上使用Webpack开发服务器进行实时开发;或者你可以在本地的非Docker虚拟环境中编写Python源代码,在本地运行pytest
,只有在准备进行最终集成测试时才运行docker-compose up --build
。
英文:
You clarify that the frontend
container is just building the static assets for the django
application. It doesn't actually need a running container for this. A better approach is to use a multi-stage build; this uses a node
image to compile the front-end, and then COPY --from
that into the actual Django image.
This would roughly look like:
FROM node:lts AS frontend
WORKDIR /frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm build
FROM python:3.11
WORKDIR /werent
COPY web/requirements.txt ./
...
COPY --from=frontend /frontend/dist/ static/dist/
...
CMD ["django", "runserver", "0.0.0.0:5050"]
One detail to note here is that you're accessing files from both the frontend
and web
directories. This means the Docker build context directory needs to be a parent of these directories, and the left-hand side of COPY
needs to mention which subdirectory to use.
In the Compose file, then, it's important that you do not have volumes:
that hide the application directory. Since the frontend is only injected in the Dockerfile and isn't necessarily built on your host, a bind mount would hide the copy of the frontend application that the image builds. You also don't need most of the other options you show in the Compose file. It should be enough to say
version: '3.8'
services:
# no frontend: container
django:
build: ./web
ports:
- 5050:5050
restart: always
# no container_name:, command:, tty:, stdin_open:, volumes:
The other important detail is that you can still use this Docker-based setup even if you normally use host tools for development. You can for example launch this container but then use a Webpack dev server without Docker for live development on the frontend; or you could work on the Python source code locally in a non-Docker virtual environment, run pytest
locally, and run docker-compose up --build
only when you're ready to do final integration testing.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论