当您的实例位于 ELB 之后时,您如何为 AWS 建立维护页面?

Posted

技术标签:

【中文标题】当您的实例位于 ELB 之后时,您如何为 AWS 建立维护页面?【英文标题】:How do you put up a maintenance page for AWS when your instances are behind an ELB? 【发布时间】:2012-11-21 13:12:18 【问题描述】:

当您想在 ELB 后面部署新版本的应用程序时,如何在 AWS 中建立维护页面?我们希望在新的自动扩展实例出现时让 ELB 将流量路由到维护实例,并且只有在它们完全启动后才“翻转”到新实例。我们使用自动缩放来降低现有实例并启动具有新代码的新实例。

我们试图避免的情况是让 ELB 为新 EC2 实例提供流量,同时还提供维护页面。由于我们没有启用粘性会话,我们希望防止用户在维护模式页面和部署在 EC2 实例中的应用程序之间来回切换。我们也不能只是扩大规模(例如从 2 个实例增加到 4 个实例,然后再回到 2 个)来引入新实例,因为代码更改可能涉及数据库更改,这会破坏旧代码的更改。

【问题讨论】:

【参考方案1】:

想出了另一个对我们很有效的解决方案。以下是获得简单的 503 http 响应所需的步骤:

    复制您的 EB 环境以创建另一个环境,例如将其命名为 app-environment-maintenance。 更改自动缩放配置并将最小和最大服务器都设置为零。这不会花费您任何 EC2 服务器,并且环境将变为灰色并出现在您的列表中。

    最后,您现在可以使用 AWS CLI 交换环境 CNAME 以使您的主环境进入维护模式。例如:

    aws elasticbeanstalk swap-environment-cnames \
        --profile "$awsProfile" \
        --region "$awsRegion" \
        --output text \
        --source-environment-name app-prod \
        --destination-environment-name app-prod-maintenance
    

这会将您的 app-prod 环境切换到维护模式。这将导致 ELB 抛出 503,因为没有任何正在运行的 EC2 实例,然后 Cloudfront 可以捕获 503 并返回您的自定义 503 错误页面,如果您愿意,如下所述。


使用 Cloudfront 的自定义错误页面的奖励配置:

我们使用 Cloudfront,就像许多人使用 HTTPS 等一样。Cloudfront 有错误页面。这是一个要求。

    使用您的错误页面创建一个新的 S3 网站托管存储桶。考虑为响应代码、503 等创建单独的文件。有关目录要求和路由,请参见 #6。 将 S3 存储桶添加到您的 Cloudfront 分配中。 为类似/error/* 的路由向 Cloudfront 分配添加新行为。 在 Cloudfront 中设置错误页面以处理 503 响应代码并将其指向您的 S3 存储桶路由,例如 /error/503-error.html

现在,当您的 ELB 出现 503 错误时,将显示您的自定义错误页面。

就是这样。我知道有很多步骤可以获取自定义错误页面,并且我尝试了很多建议的选项,包括 Route53 等。但是所有这些都存在与 ELB 和 Cloudfront 等的工作方式的问题。

请注意,交换环境的主机名后,传播大约需要一分钟左右。

【讨论】:

Elastic Beanstalk 的绝佳方法!如果您不需要花哨,只需让 EB 负载均衡器直接提供您的“503 服务暂时不可用”页面(通过缩放到零)。在这种情况下,您只需要第 1、2 和 8 步(也可以在 EB GUI 中完成第 8 步)。另一种变化是在维护环境中部署一个简单的自定义维护页面服务器。 @nobar,你是对的。如果您不想要任何花哨的东西,例如向用户显示自定义错误页面,则只需要步骤 1、2 和 8。我会更新帖子,以便更清楚。【参考方案2】:

据我所知,我们处于上述答案不适用或不理想的情况。

我们有一个在 64 位 Amazon Linux/2.9.0 上运行 Puma 和 Ruby 2.3 的 Rails 应用程序,似乎带有(经典)ELB。

所以 ALB 503 处理不是一个选项。

我们还有各种硬件客户端,我不相信它们总是尊重 DNS TTL,所以 Route53 是有风险的。

似乎运行良好的是平台附带的 nginx 上的辅助端口。

我将此添加为.ebextensions/maintenance.config

files:
  "/etc/nginx/conf.d/maintenance.conf":
    content: |
      server 
        listen 81;
        server_name _ localhost;
        root /var/app/current/public/maintenance;
      

container_commands:
  restart_nginx:
    command: service nginx restart

并将https://gist.github.com/pitch-gist/2999707 的副本放入public/maintenance/index.html

现在要设置维护,我只需将 ELB 侦听器切换为指向端口 81 而不是默认的 80。没有额外的实例、s3 存储桶或等待客户端访问新的 DNS。

beantalk(可能主要是在后端等待云形成)只需大约 15 秒左右即可申请。

【讨论】:

您是如何处理健康检查的?由于运行状况检查失败,我的 ELB 停止服务。我手动将健康检查更改为 TCP:81,但它不起作用。 在我的情况下,该应用程序仍在进行健康检查,所以这不是问题。你的方法应该奏效。如果ELB无法连接到辅助nginx端口,我会检查(1)安全组规则(可以elb出口到81,实例sg是否允许81入口),(2)nginx肯定在监听(需要重启) 【参考方案3】:

我意识到这是一个老问题,但在今天(2018 年 12 月)遇到同样的问题之后,似乎还有另一种方法可以解决这个问题。

今年早些时候,AWS 引入了对 redirects and fixed responses to Application Load Balancers 的支持。简而言之:

在控制台中找到您的 ELB。 查看相应侦听器的规则。 为您的应用程序的主机名添加一个固定的 503 响应规则。 可选择提供text/plaintext/html 响应(即您的维护页面HTML)。 保存更改。

一旦规则传播到 ELB(我花了大约 30 秒),当您尝试在浏览器中访问您的主机时,您将看到 503 维护页面。

部署完成后,只需删除您添加的规则即可。

【讨论】:

在这里操作...感谢您添加此汤姆。一旦 ALB 和此功能出现,我们就开始做一些与我们的解决方案非常相似(但基本上是这样)的事情。 也使用这个策略。它简单而且效果很好。【参考方案4】:

我们的部署过程首先运行一个 cloudformation 来启动一个 ec2 微实例(维护实例),它将预定义的静态页面从 s3 复制到 ec2。 Cloudformation 与附加了微型 ec2 实例的 elb 一起提供。然后运行一个脚本(powershell 或 cli)从 elb 的离开维护实例中删除 Web 实例(ec2)。

这样我们在部署过程中切换到维护实例。

在我们的例子中,我们有两个 elb,一个用于外部,另一个用于内部。在此过程中,我们的内部 elb 将不会更新,这也是我们完成产品部署后冒烟测试的方式。 测试完成后,我们运行另一个脚本将 Web 实例附加回 elb 并删除维护堆栈。

【讨论】:

【参考方案5】:

Route53 不是解决这个问题的好方法。在维护页面出现之前,DNS 条目需要很长时间才能过期(然后在维护完成后更新它们需要同样的时间)。我意识到在提出这个问题时 Lambda 和 CodeDeploy 触发器并不存在,但我想让其他人知道 Lambda 可用于为此创建一个相对干净的解决方案,我在一篇博文中对此进行了详细说明: http://blog.ajhodges.com/2016/04/aws-lambda-setting-temporary.html

该解决方案的主要目的是为 CodeDeploy 事件订阅 Lambda 函数,这会将您的 ASG 替换为在部署期间为负载均衡器中的静态页面提供服务的微型实例。

【讨论】:

这取决于您是否在 Route 53 中使用 Alias 记录。一旦发生健康故障,客户端将不会看到切换到其他资源的延迟(如果它设置了 Route 53 别名记录) 这假设您正在使用 CodeDeploy 事件。【参考方案6】:

AWS 上最简单的方法是使用他们的 DNS 服务 Route 53。

您可以使用Weighted Round Robin的功能。

“您可以使用 WRR 将服务器投入生产,执行 A/B 测试, 或平衡不同地区或数据中心的流量 大小。”

更多信息在AWS documentations on this feature

编辑:Route 53 最近添加了一项允许 DNS 故障转移到 S3 的新功能。查看他们的文档以获取更多详细信息:http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-failover.html

【讨论】:

尚不清楚这将如何工作-您能否扩展您的答案? (请注意,我们确实在我们的堆栈中设置了 Route 53,只是不清楚我们如何使用加权循环来一次只为一些 EC2 实例提供服务) 即我们的 EC2 实例位于单个 ELB 之后 Guy 可能意味着您将在 DNS 记录集中拥有 2 个资源:一个用于 ELB,第二个用于维护页面。一旦进入“维护模式”,您将把维护页面服务的权重增加到一个巨大的价值。这意味着另一条路线(您的 ELB)将没有连接。维护结束后 - 您将页面的权重重置为零。 啊,我应该自己想出来的。感谢您澄清@Froyke! 对于仅阅读此答案的任何人,请同时阅读其他答案,因为 AWS 自发布以来添加了更多功能,包括一个完全不同的选项(基本上,ALB 也可以帮助实现这个)

以上是关于当您的实例位于 ELB 之后时,您如何为 AWS 建立维护页面?的主要内容,如果未能解决你的问题,请参考以下文章

当服务器位于 AWS ELB 之后时,ASP.NET Core MVC 应用程序如何获取客户端 IP 地址?

如何为 ELB 实例安装外部 SSL?

您如何为代码签名的 Dotnet 程序集添加时间戳?

如何为 WebSocket 协议配置 AWS ELB 和 Nginx? [关闭]

如何为 AWS Elb 后面的 reactJs SPA 重定向 http 到 https?

使用Cloudfront而不是单个EC2实例的AWS ELB设置有什么意义?