在 AWS ECS 上设置 Rails 6 的正确方法

Sti*_*cky 1 ruby-on-rails amazon-web-services amazon-ecs aws-application-load-balancer

我在 AWS ECS 上部署了 Rails 6(与 Puma 一起运行)。有一个 ECS 服务和一个 ECS 任务,该任务启动托管我的应用程序的 EC2 实例。我还使用我的 ECS 服务创建了一个应用程序负载均衡器。我向负载均衡器添加了一个 HTTPS 侦听器。我的侦听器指向专门通过HTTP协议接受流量的目标组。

我对请求流程的理解:

HTTPS request from internet:
  --> hits AWS load balancer 
    --> hits HTTPS listener
      --> passes traffic using HTTP to Target Group
        --> request finally reaches Rails app on Target Group EC2 targets *over HTTP*
Run Code Online (Sandbox Code Playgroud)

这是一个有效的设置吗?我读了这个StackOverflow 答案,我的解释是,我们只需要 HTTPS 作为我们的负载均衡器,而不是 Puma,因此也不需要目标组。

我还通过 HTTP 为我的目标组设置了运行状况检查,该目标组期望 301 状态代码响应作为健康目标(因为我config.force_ssl在 Rails 配置中已启用)。问题是,为什么来自负载均衡器的流量没有被重定向?为什么健康检查的流量会被重定向?他们不是都针对同一个目标群体吗?为什么一个请求的结果是 200,而另一个请求的结果是 301?

我画了一张图来尝试捕捉我的问题/困惑/当前的理解:

在此输入图像描述

这是我的负载均衡器和目标组设置:

在此输入图像描述

在此输入图像描述

不确定这是 AWS 问题还是 Puma 问题或其他问题。采纳所有想法!谢谢你!!

san*_*e89 5

回答你的2个问题。

  1. 为什么来自负载均衡器的流量没有被重定向?

这个答案也解释了这一点,但我会更深入地研究一下:当负载均衡器接收到 HTTPS 连接并通过 HTTP 将其转发到 Rails 服务器时,它将为X-FORWARDED-PROTO=https请求设置一个标头,并且 Rails 理解这一点就足够了对于force_ssl配置。

代码路径是Rails https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/ssl.rb(根据该文件中的注释,当为config.force_ssltrue时包含在请求链中)将调用request.ssl?

request在该上下文中是 的一个实例https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/http/request.rb,但您找不到ssl?在那里定义的方法;然而,该类包括include Rack::Request::Helpers.

如果你查看 Rack 的源代码,你会发现ssl?中定义的方法https://github.com/rack/rack/blob/master/lib/rack/request.rb,其中调用了schememethod,并且该部分会检查 X-Forwarded-Proto 标头elsif forwarded_scheme。就这样了 :) 即使这是一个 HTTP 请求,该标头的存在也会使返回request.ssl?true。

  1. 为什么健康检查的流量会被重定向?

在这种情况下,这是从负载均衡器到应用程序的 HTTP 请求,不携带 X-Forwarded-For 或 X-Forwarded-Proto 标头,因此 Rail 的 config.force_ssl 正在执行其应该执行的操作并进行重定向。

最后,查看有关 config.force_ssl 的文档。实际上,您可以将其设置为选项的哈希值,并将您的健康检查网址从force_ssl 行为中排除!

config.ssl_options = { redirect: { exclude: -> request { request.path =~ /healthcheck/ } } }
Run Code Online (Sandbox Code Playgroud)