首页 > 解决方案 > 如何通过 docker 将 API 与 Web SPA 连接起来

问题描述

我有一个基于 PHP(流明)的 API 和一个基于 React 的电子商务。两者的工作都很好。当我尝试通过 Docker 使其工作时,问题就来了。我想部署整个应用程序只运行一个命令

问题是反应应用程序没有与 API 连接。

我在这篇文章中尝试了@Suman Kharel 的答案

在运行反应应用程序的 Docker 容器中代理 API 请求

但它不起作用。有谁知道我该如何解决?

这是我在 bitbucket 上的回购。

https://bitbucket.org/mariogarciait/ecommerce-submodule/src/master/

希望有人知道我做错了什么。

谢谢

标签: reactjsdockerapidocker-composesingle-page-application

解决方案


如果您想使用docker使用单个命令启动所有应用程序,则唯一的选项是docker-compose

使用 docker-compose 仅​​用于测试目的或非常有限的生产基础设施。最好的方法是将您的工件分别放在不同的主机中。

请阅读这些内容以了解一些要点:

当您使用 docker-compose 时,所有服务都部署在同一台机器上,但每个服务都部署在一个容器中。并且只有一个进程在容器内运行。

因此,如果您进入一个容器(例如 nodejs 中的一个 web)并列出该进程,您将看到如下内容:

nodejs .... 3001

并进入另一个容器,如数据库 postgres:

postgres .... 5432

因此,如果 nodejs web 需要从内部连接到数据库,则必须需要 ip 而不是postgress 数据库的localhost,因为在 nodejs 容器内部,只有一个进程在 localhost 中运行:

localhost 3001

因此,使用localhost:5432在 nodejs 容器内不起作用。解决方案是使用 postgres 的 ip 而不是 localhost :10.10.100.101:5432

解决方案

当我们有多个容器(docker-compose)之间存在依赖关系时,docker 建议我们:

总而言之,凭借这些特性,docker 创建了一种“特殊网络”,您的所有容器都可以在其中平静地离开,没有 ips 的复杂性!

带有 host.docker.internal 的 Docker 网络

仅用于测试、快速部署或在非常有限的生产环境中,您可以使用最新版本的 docker-compose(1.29.2) 和 docker 中的新功能。

在 docker-compose 的末尾添加这个

networks:
  mynetwork:
    driver: bridge

这对你所有的容器

networks:
  - mynetwork     

如果某些容器需要主机 ip,请使用host.docker.internal而不是 ip

environment:
  - DATABASE_HOST=host.docker.internal
  - API_BASE_URL=host.docker.internal:8020/api

最后在使用host.docker.internal的容器中添加:

extra_hosts:
  - "host.docker.internal:host-gateway"

注意:这是在 ubuntu 上测试的,而不是在 mac 或 windows 上,因为没有机构在该操作系统上部署其真实应用程序

环境变量方法

在我看来,Docker 链接或网络是一种幻觉或欺骗,因为这只适用于一台机器(开发或登台),对我们隐藏依赖关系和其他复杂主题,当您的应用程序离开笔记本电脑并转到您的准备好供您的用户使用的真实服务器。

无论如何,如果您将 docker-compose 用于开发人员或实际目的,这些步骤将帮助您管理容器之间的 ip:

  • 获取您机器的本地 ip 并将其存储在类似$MACHINE_HOST这样的脚本中的变量中:startup.sh
  • 从 docker-compose.json 中删除链接或网络
  • 使用$MACHINE_HOST来引用容器中的另一个容器。

例子:

db:
  image: mysql:5.7.22
  container_name: db_ecommerce
  ports:
    - "5003:3306"
  environment:
    MYSQL_DATABASE: lumen
    MYSQL_ROOT_PASSWORD: ${DATABASE_PASSWORD}

api-php:
  container_name: api_ecommerce
  ports:
    - "8020:80"
    - "445:443"
  environment:
    - DATABASE_HOST=$MACHINE_HOST
    - DATABASE_USER=$DATABASE_USER
    - DATABASE_PASSWORD=$DATABASE_PASSWORD
    - ETC=$ETC

web-react:
  container_name: react_ecommerce
  ports:
    - 3001:3000
  environment:
    - API_BASE_URL=$MACHINE_HOST:8020/api
  • 最后只运行你的 startup.sh ,它有变量和经典docker-compose up -d

同样在您的反应应用程序中,使用 var 而不是 package.json 中的代理读取您的 api 的 url:

process.env.REACT_APP_API_BASE_URL

检查这个以了解如何从反应应用程序中读取环境变量。

在这里您可以找到有关如何使用MACHINE_HOST变量及其使用的更详细步骤:

建议

  • 在 docker-compose.json 文件中使用变量而不是硬编码值
  • 分离您的环境:开发、测试和生产
  • 构建正处于开发阶段。换句话说,不要在 docker-compose.json 中使用build 。也许对于本地发展可能是一种选择
  • 对于测试和生产阶段,只需运行您的容器,在开发阶段构建和上传(docker 注册表)
  • 如果您使用代理或环境变量在您的 react 应用程序中读取您的 api 的 url,那么您的构建将只能在一台机器上工作。如果您需要在多个环境之间移动它,例如:测试、登台、uat 等,您必须执行新的构建,因为 react 中的代理或环境变量是硬编码在 bundle.js 中的。
  • 这不仅仅是 react 的问题,也存在于 angular、vue 等中:检查限制 1:每个环境都需要此页面中的单独构建部分
  • 如果申请,您可以评估https://github.com/utec/geofrontend-server以解决前面解释的问题(以及其他类似身份验证的问题)。
  • 如果你的计划是向真实用户展示你的网站,那么 web 和 api 必须有不同的域,当然还有 https。例子
    • ecomerce.zenit.com 为您的 react 应用程序
    • api.zenit.com 或 ecomerce-api.zenit.com 用于您的 php api
  • 最后,如果您想避免这种基础设施复杂性的头痛,并且您没有开发人员和系统管理员团队,您可以使用 heroku、数字海洋、openshift 或其他类似的平台。几乎所有这些都与 docker 兼容。因此,您只需要对每个带有 Dockerfile 的 repo 执行 git push 即可。该平台将解释您的 Dockerfile,部署并为您分配一个可立即使用的 http 域进行测试或一个很酷的域用于生产(事先获得域和证书)。

推荐阅读