在 docker compose 中的服务之间共享动态文件的正确方法

Right way to share dynamic files between services in docker compose

我有以下 docker-compose 文件。我想与 nginxweb 服务

共享来自 react 服务的静态文件
version: '3.6'

services:

  web:
    image: shahrukh/learnup:web
    networks:
      - main
    command: >
      sh -c "python manage.py collectstatic --no-input
      && gunicorn learnup.wsgi:application --bind 0.0.0.0:8000 --reload"
    volumes:
      - static_cdn:/var/www/learnup/static_cdn
    depends_on:
      - react
  
  react:
    image: shahrukh/learnup:react
    volumes: 
      - static_cdn:/app/Learnup-Frontend/learnup/export-build/static

  nginx:
    image: shahrukh/learnup:nginx
    restart: always
    ports:
      - 80:80
    command: nginx -g 'daemon off;'
    volumes:
      - static_cdn:/var/www/static
    networks:
      - main
    depends_on:
      - web
      - react

networks:
  main:

volumes: 
  static_cdn:

为此,我创建了一个命名卷 static_cdn,将在其上执行以下步骤

  1. 来自 react 服务的我的 React 应用程序的构建文件夹将是 安装在这里
  2. 来自 django 的 collectstatic 命令的静态数据将被复制到这里
  3. 这与 nginx 共享,后者将提供它。

这是我面临的问题。

在使用最新版本更新我的 react 容器映像时,卷 static_cdn 没有最新的静态文件,因为在我使用后没有重新创建该卷docker-compose up -d

所以我的问题是 在这种情况下,在服务之间共享文件的最佳方式是什么? 以便它负责更新。

请注意,我知道首先使用 docker-compose down -v 停止并删除卷然后执行 docker-compose up -d 的解决方案。但这会导致我不希望在生产中出现停机时间。

同时执行 docker-compose pull react 以提取 react 的最新映像,然后执行 docker-compose -d 也没有用,因为卷没有更新。 Docker compose 目前不提供任何选项来强制在启动时重新创建卷。我也不能使用 docker volume rm ...,因为卷正在使用中。

另外,请注意,我可以在启动时创建反应构建文件,而不是将其作为图像的一部分来解决问题。但是我做不到,因为我是 运行 系统上资源有限的应用程序 npm run build 就崩溃了。

您似乎想使用 docker-compose 进行生产。

docker-compose 不适用于生产用途。例如,它不会尝试重新启动失败的容器。它还会在重新创建容器之前销毁容器,从而导致停机。请考虑使用 docker-swarm(更简单)或 kubernetes(行业 de-facto 标准)。

这些工具知道如何执行更新、管理持久卷、处理硬件故障等。

在生产环境中处理静态文件

如果您的静态内容确实是代码,基本上是开发更改,您可能希望在出现错误时恢复并且使用 git 之类的版本进行版本控制,然后使用它创建一个容器并对其进行版本控制.

当您发布新版本并通知您的生产集群时,它会使用合理的更新策略自动更新您的所有生产节点。如果您发现新版本有问题,您可以回滚。

如果它真的是动态的,您可能需要为您的卷使用另一个驱动程序,例如映射到网络文件系统。

无论如何看看 docker-swarm 和 kubernetes 是如何工作的,它会阐明什么对生产环境有好处。

本地工作

在本地,使用-v选项删除容器并有几秒的停机时间是完全可以接受的。

通常,如果您正在构建 React 应用程序,您会希望将其编译为静态文件以进行部署。您将使用像 Webpack 这样的工具来生成一组构建的 HTML、Javascript 和 CSS 文件,然后您可以直接为那些使用 Nginx 的文件提供服务。如果您使用的是像 Create React App 这样的入门工具包,您通常可以 运行 类似

npm run build

它会创建一个包含构建文件的 dist 目录。

既然你已经有了一个Nginx容器,这意味着你不需要一个单独的React容器;你可以从 Nginx 容器中提供编译后的文件。此外,后端容器可能不需要直接访问构建的 front-end 代码,它只需要从 Nginx 代理提供服务。

这意味着您可以在单个 multi-stage 构建中使用构建的 React 应用程序构建 Nginx 代理映像。该 Dockerfile 看起来或多或少像:

FROM node:lts AS react
WORKDIR /app
COPY package*.json .
RUN npm install
COPY . .
RUN npm run build

FROM nginx
COPY --from=react /app/dist /usr/share/nginx/html
COPY default.conf.template /etc/nginx/templates/
# Base image includes a useful CMD

在 Compose 设置中,您不需要专用的 React 容器,如前所述;您不需要卷,因为您已经将应用程序构建到静态文件中;您不需要重述图像中已经声明的 command: 之类的内容;您可以使用 Compose 为您提供的 default 网络。这会给你一个 much-simplified docker-compose.yml 文件:

version: '3.6'
services:
  web:
    build: ./backend
    image: shahrukh/learnup-web:latest

  nginx:
    build: ./frontend
    image: shahrukh/learnup-nginx:latest
    restart: always
    ports:
      - 80:80
    depends_on:
      - web