在多个容器之间共享卷。

huangapple go评论65阅读模式
英文:

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"]

这里需要注意的一个细节是,你要访问frontendweb目录中的文件。这意味着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.

huangapple
  • 本文由 发表于 2023年7月27日 17:18:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/76778248.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定