如何从前端容器访问 Docker API 容器?

bry*_*ejl 2 cloud networking amazon-web-services amazon-ecs docker

我是 Docker 新手,并试图了解容器之间的网络。我正在运行两个容器,一个用于 Node.js API 服务器的容器,一个用于保存前端 React UI 的容器。在本地运行它们时一切正常。API 服务器公开端口 3001,我可以从我的 React 站点调用 localhost:3001/api。

鉴于容器的思想是可以在任何地方运行,那么如何保证这两个容器服务在不在本地机器上运行时可以连接?我知道可以在 docker 容器之间设置网络,但这似乎不适用于这种情况,因为反应容器没有发出请求,而是客户端访问反应容器(因此 localhost 现在将引用他们的机器而不是我的 API 容器)。

部署此类架构的最佳实践是什么?

需要什么样的设置来保证这些容器可以在云部署中进行通信,其中 API 主机可以在部署时动态生成?

如果相关的话,我正在专门寻找部署到 AWS ECS 的方法。

编辑:

package.json 代理仅在开发中相关,因为代理在 React 应用程序的生产构建中不会生效。

Mar*_*per 5

据我了解,您希望将一个由 React 前端和 Node.js 后端组成的经典两层应用程序部署到 Amazon ECS(生产环境)。

我们不久前为我们的应用程序设置了这个,我想概述一下解决方案。

部署此类架构的最佳实践是什么?

这是一个非常棘手的问题,因为它还取决于您的问题中未完全指定的两层的某些特征。

前端

我想到的第一个问题是,您是否真的需要从 docker 容器运行 React UI?是动态内容吗?如果您的 React 应用程序是为生产而正确构建的(如 [1] 中所述),那么它应该是静态内容。静态内容的优点是,它可以轻松缓存,因此不需要在生产中从 Docker 容器提供服务。情况恰恰相反:我认为在生产中从 ECS 容器提供静态内容是一种不好的做法。你应该做的是:

  • 创建 S3 存储桶并将静态资产部署到该存储桶中。
  • 可选,但强烈建议用于生产:使用某种内容交付网络 (CDN) 来分发内容并在边缘有效地缓存它。AWS 服务环境为此提供了 CloudFront 服务。使用 CloudFront 是否有回报取决于应用程序的流量模式。您可以直接从 S3 存储桶提供静态资产,这可能会导致更高的延迟,但可能更具成本效益。

总而言之,我建议:如果您计划将一些重要的应用程序投入生产,预计会收到相当大的流量负载和/或设计为单页应用程序 (SPA),请将您的静态资产外包到 S3 并为它们提供服务通过CloudFront

后端

此处的最佳实践很简单:创建一个应用程序负载均衡器 (ALB)、一个目标组,并将目标组指向您的 ECS 服务。ECS 提供了 AWS Elastic Load Balancing 的集成。此处使用 AWS ALB 的优点是会自动为您创建 DNS 记录。[3]

但是如果我确实需要在 ECS 中使用两个容器怎么办?

如果您决定不外包静态资产,因为您的 React 内容中有动态部分,或者上述解决方案的定价不合适,那么让我回答您的第二个问题:

需要什么样的设置来保证这些容器可以在云部署中进行通信,其中 API 主机可以在部署时动态生成?

如何在 ECS 中将事物连接在一起有多种策略。我猜你的 React 容器不需要直接连接到 Node.js 容器,对吧?如果这个假设是错误的,请纠正我。对我来说,场景如下:

  1. 客户端 --> Docker 容器 1“React”(加载例如index.html)
  2. 客户端(例如在index.html中使用Ajax)--> Docker容器2“Node.js”

如果这两层确实完全独立,我建议创建两个单独的 ECS 服务 - 每个服务运行单独的 ECS 任务定义。其次,您创建一个应用程序负载均衡器并在每个服务上激活负载均衡器集成。最后,您需要在负载均衡器上为每个服务创建单独的目标组,并在负载均衡器上分配单独的侦听器以将流量重定向到相应的目标组。

例子:

  • 应用程序负载均衡器的 DNS 名称:my-loadbalancer-1234567890.us-west-2.elb.amazonaws.com
  • 带有 React 前端的服务 A
  • 带有 Node.js 后端的服务 B
  • 将流量重定向到服务 A 的目标组 A
  • 将流量重定向到服务 B 的目标组 B
  • ALB 监听器 A 将负载均衡器端口 80 上的流量重定向到目标组 A
  • ALB 侦听器 B,将负载均衡器端口 8080 上的流量重定向到目标组 B
  • 可选:您自己的域的自定义 DNS 记录,该记录指向负载均衡器(通过别名记录),以便在浏览器中提供对客户更友好的名称,而不是在 aws 区域 elb.amazonaws.com 中自动创建的记录

现在,可以通过负载均衡器域的标准 HTTP 端口访问前端,并且可以通过端口 8080 访问后端。您可以轻松在负载均衡器上激活 SSL 并改用端口 443。[4]
这允许在负载均衡器而不是 Docker 容器上终止 SSL - 这一功能称为 SSL 终止 [5]。

但是如果这些容器必须相互通信怎么办?

通过上述方法,容器能够通过应用程序负载均衡器相互通信。但是,如果此通信本质上是内部通信,则这并不理想,因为它是通过公共负载均衡器端点进行路由的。如果我们想确保流量不会离开容器之间的专用网络,我们可以*将它们放在一起:

  • 在 ECS [6] 中创建一个任务定义并将两个容器放入其中
  • "NetworkMode": "bridge"为任务指定
  • Links使用相应容器定义上的属性(在任务定义内)指定容器之间的链接

*再次有多种策略可以实现这一目标,我在这里概述了我所知道的最简单的策略(例如,任务也可以使用服务发现 [7] 或任务网络模式awsvpc私下链接在一起)

我知道这是一个复杂且特别广泛的话题,因为有多种策略,每种策略都有其优点和缺点,但我希望我能给你一些有用的参考。

参考

[1] https://create-react-app.dev/docs/product-build/
[2] https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-load-balancing.html
[ 3] https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-creating.html#resource-record-sets-elb-dns-name-procedure
[4] https:// docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html
[5] https://infra.engineer/aws/36-aws-ssl-offloading-with-an-application-load-平衡器
[6] https://docs.aws.amazon.com/AmazonECS/latest/developerguide/create-task-definition.html
[7] /sf/answers/4027836081/