将React + Express App部署到Kubernetes如何用docker构建它?

时间:2019-05-30 19:44:22

标签: node.js reactjs express kubernetes docker-compose

所以我一直在努力部署dockerized应用程序。该应用程序包含一个React前端和一个Express API。 我的开发环境docker-compose.yml如下所示:

version: '3'
services:
  # Express Container
  backend:
    build: ./backend
    expose:
      - ${BACKEND_PORT}
    env_file:
      - ./.env
    environment:
      - PORT=${BACKEND_PORT}
    ports:
      - ${BACKEND_PORT}:${BACKEND_PORT}
    volumes:
      - ./backend:/backend
    command: npm run devstart
    links:
      - mongo
  # React Container
  frontend:
    build: './frontend'
    expose:
      - ${REACT_APP_PORT}
    env_file:
      - ./.env
    environment:
      - REACT_APP_BACKEND_PORT=${BACKEND_PORT}
    ports:
      - ${REACT_APP_PORT}:${REACT_APP_PORT}
    volumes: 
      - ./frontend/src:/frontend/src
      - ./frontend/public:/frontend/public
    links:
      - backend
    command: npm start
  mongo:
    image: mongo
    ports:
      - "27017:27017"

但是我一直在努力构建用于生产的结构。

我已经看到基本上有3种选择:

  1. 将前端和后端分别部署到不同的服务器。在这种情况下,react前端将在某些Web托管服务上,而Express后端将在kubernetes上托管
  2. 让快递应用服务于反应应用
  3. 将应用程序分开,但使用NGINX代理API请求到快速应用程序

我当时想使用选项3,因为它可以使开发和生产环境保持相似。 (如果结构不好,请告诉我,此应用程序有望收到大量流量。)

我是否应该忘记docker-compose并创建一个使用多阶段构建复制前端和后端代码的多阶段dockerfile?这样我可以部署一个Docker容器吗?

我的文件夹结构如下:

app/
  .env
  docker-compose.yml
  docker-compose.prod.yml
  .gitignore
  frontend/
    Dockerfile
    ... react stuff
  backend
    Dockerfile
    .. express stuff

我会把这一切弄错吗?您如何将带有docker-compose的应用程序部署到生产环境中(最好在kubernetes上)。

我可以找到大量有关如何使这些东西在开发中运行的知识,但是当涉及到部署这种类型的堆栈的方向时,我就迷失了。

3 个答案:

答案 0 :(得分:1)

您可能首先阅读Kubernetes documentation,并了解什么是简单的,什么不是简单的。您对部署和服务以及Ingress最感兴趣。具有关联的持久状态的MongoDB设置将更加复杂,您可能会看到预打包的解决方案,例如the stable/mongodb Helm chartMongoDB's official operator

请注意,Kubernetes设置的重要部分是几乎总是有多个Node,并且您对Pod将放置在哪个Node上没有太多控制。特别是,这意味着您显示的Docker Compose volumes:在Kubernetes环境中无法正常工作-除了完成所有正常的Kubernetes部署工作之外,您还需要将应用程序源代码复制到每个节点。这是相同部署工作的两倍。通常,您会希望所有应用程序代码都包含在Docker映像中,并且典型的基于Node的Dockerfile看起来像

FROM node:10
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install
COPY ./ ./
RUN yarn build
EXPOSE 3000
CMD yarn start

仅在docker-compose.yml文件中显示:

  • volumes:使您的容器与生产环境中的容器大不相同;删除它们。

  • 不要打扰使容器内部端口可配置。在普通Docker,Docker Compose和Kubernetes中,您可以在部署时将容器内部端口重新映射到任意外部可访问端口。您可以在此处选择固定数字,这很好。

  • 您显示的几个详细信息(例如,容器expose:和要运行的默认command:的端口)是映像的正确组成部分(每次运行映像时,它们都会相同),因此将它们移到Dockerfile中。

  • links:这些天是多余的,您可以删除它们。在Docker Compose中,您始终可以通过其他服务的服务块名称来获得其名称。

  • 在不同的环境中,其他相关服务的名称将有所不同。例如,当您实际在Docker之外开发应用程序时,MongoDB可能位于localhost上,您显示的配置中为mongo,在Kubernetes中为mongo.myapp.svc.cluster.local,或者您可以选择运行它完全不在Docker之外。通常,您通常希望使用环境变量来配置它们。

这使您的docker-compose.yml文件更像是:

version: '3'
services:
  backend:
    build: ./backend
    environment:
      - MONGO_URL: 'mongo://mongo'
    ports:
      - 3000:3000
  frontend:
    build: './frontend'
    environment:
      - BACKEND_URL: 'http://backend'
    ports:
      - 8000:8000
  mongo:
    image: mongo
    ports:
      - "27017:27017"

正如@frankd在他们的答案中暗示的那样,使用Webpack之类的工具将React应用程序预编译为一组静态文件也很普遍。取决于您实际部署的方式,可以提前运行此编译步骤,然后将那些已编译的Javascript和CSS文件推送到其他静态托管服务,然后将其完全从Docker / Kubernetes中删除。

答案 1 :(得分:0)

我将前端和后端保持为完全独立的应用程序。他们每个人都在自己的GitHub存储库中,拥有自己的测试套件,Dockerfiles,Jenkins构建,所有内容。这使我们能够独立地对它们进行版本控制,从而允许更频繁的迭代。规模较小,风险较低的部署;更快,更高效的开发。

所有对后端的调用都在/ API /路径上,该路径由nginx入口控制器处理(非常简单),并适当地路由到后端服务。

答案 2 :(得分:0)

我喜欢选项1而不是3,因为它使前端和后端保持分离。一个巨大的优势是您可以将前端托管在AWS S3 with a CloudFront CDN之类的东西上。因此,所有静态内容都分发到世界各地的边缘服务器。这样可以很快将繁重的项目(图像,大型js库,css等)提供给最终用户,并使您的应用程序运行更快。