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

问题描述

我有以下docker-compose文件。我想与reactNginx服务共享web服务中的静态文件

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服务的我的应用程序的构建文件夹将是 安装在这里
  2. django的collectstatic命令中的静态数据将在此处复制
  3. 这与将为其提供服务的Nginx共享。

这是我面临的问题。

使用最新的构建版本更新react容器映像时,卷static_cdn没有最新的静态文件,因为在使用{{1}之后不会重新创建该卷}

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

请注意,我知道首先使用docker-compose up -d来停止和删除卷然后执行docker-compose down -v解决方案。但这会导致停机,而这是我不想在生产中进行的。

也执行docker-compose up -d提取docker-compose pull react的最新图像,然后再进行react无效,因为该卷不会更新。到目前为止,Docker compose还没有提供任何选项来强制在启动时重新创建卷。卷正在使用时,我也不能使用docker-compose -d

另外,请注意,我可以在启动时创建react build文件,而不是将其作为解决问题的映像的一部分。但是我无法做到这一点,因为我正在资源有限的系统上运行应用程序,docker volume rm ...崩溃了。

解决方法

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

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

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

处理生产中的静态文件

如果实际上您的静态内容是代码,基本上是一个开发更改,则可能需要在发生错误的情况下还原并使用git之类的版本,然后使用该容器创建一个版本并对其进行版本化。

发布新版本并通知产品集群时,它将使用健全的更新策略自动更新所有生产节点。如果发现新版本存在问题,则可以回滚。

如果它确实是动态的,则可能需要另一个驱动程序来驱动您的卷,例如映射到网络文件系统。

无论如何,docker-swarm&kubernetes的工作方式一目了然,它将阐明对产品环境有什么好处。

在本地工作

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

,

通常,如果要构建React应用程序,则需要将其编译为静态文件以进行部署。您将使用Webpack之类的工具来生成一组内置的HTML,Javascript和CSS文件,然后可以使用Nginx直接为其提供服务。如果您使用的是诸如Create React App之类的入门工具包,通常可以运行

npm run build

,它将使用生成的文件创建一个dist目录。

由于您已经有了Nginx容器,因此这第一件事就是您不需要单独的React容器;您可以只从Nginx容器中提供已编译的文件。另外,后端容器可能不需要直接访问已构建的前端代码,而只需要从Nginx代理获得服务即可。

这意味着您可以在单个多阶段构建中使用构建的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网络。这将为您提供一个大大简化的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