Terraform 创建了 AWS ECS 基础设施:运行状况检查一直失败

Posted

技术标签:

【中文标题】Terraform 创建了 AWS ECS 基础设施:运行状况检查一直失败【英文标题】:Terraform created AWS ECS infra: health check keep failing 【发布时间】:2019-07-17 16:18:08 【问题描述】:

简而言之,我想将我的 nginx 和 Node.js docker 映像部署到 AWS ECS。为了构建基础设施,我使用的是 Terraform。但是,在服务器中运行的任务不断失败。我在访问我的域bb-diner-api-https.shaungc.com 时也得到了503 Service Temporarily Unavailable

(您可以see my entire project repo here,但我会在下面嵌入链接并引导您浏览特定的相关文件。)

terraform apply 之后,它报告创建了 15 个资源,我可以看到在 ECS 门户网站中运行的服务和任务。但是,我的任务总是会在一段时间后失败,如下所示:

因为健康检查总是失败:

对于nodejs,我有错误代码137,这是由接收关闭信号引起的。这意味着 nodejs 不是原因——它是 nginx 失败了太多的健康检查,以至于它终止了 nodejs。对于 nginx,点击View logs in CloudWatch 后根本没有显示任何消息(我确实在task definition 中设置了awslogs)。

我的健康检查设置

任务定义容器健康检查

基本上我在 nginx 中准备了一条路由,只是为了进行健康检查。在task definition > container_definition(json 格式)中,我对容器nginx 进行了健康检查,如下所示: "command": ["CMD-SHELL","curl -f http://localhost/health-check || exit 1"],在我的nginx.conf 我有:

...
server 
  listen 80;
  ...

  location /health-check 
        # access_log off;
        return 200 "I'm healthy!" ; # refer to https://serverfault.com/questions/518220/nginx-solution-for-aws-amazon-elb-health-checks-return-200-without-if 
  

所以我真的不知道为什么任务没有通过健康检查。

负载均衡器的目标组健康检查

我还为我创建了一个 Application Load Balancer,以将我在 Route 53 上的域名链接到它。我注意到还有另一个地方在做健康检查:目标组和应用程序负载均衡器。这里的检查也失败了,我的实例状态是draining

安全组

我想我打开了所有可能的端口。

那么为什么运行状况检查会失败以及还缺少什么?

有很多文章指出 AWS 上的 Nginx 配置、PORT 或入站限制(安全组/目标组)可能是常见原因,我查看了所有这些。我让nginx监听80,将容器端口设置为80,在安全组中允许大范围的入站端口。我还能错过什么?

【问题讨论】:

【参考方案1】:

我自己想通了。虽然我从未通过容器级别的健康检查,但我设法修复了应用程序负载均衡器上的健康检查失败。

问题及原因

原来这和EC2实例的安全组有关。当我关注AWS troubleshooting page 进行健康检查失败时,我注意到了这一点,他们建议通过 ssh 进入实例并直接在实例上尝试curl -v ...curl 失败,我发现我的 EC2 实例安全组使用的是默认的 sg。虽然默认安全组 (sg) 允许所有流量,但它会将其来源限制为自身,即默认安全组。这可能会令人困惑,但我认为这表明它只允许来自也使用默认安全组的 aws 服务的流量。无论如何,这会阻止 aws 服务之外的任何流量,因此我无法通过我的域名访问,ALB 运行状况检查代理也无法访问。

解决方案

我的最终解决方案是为 ALB 设置一个专用安全组,然后为 EC2 实例创建一个新的安全组,该安全组只允许来自 ALB 安全组的流量。另请注意,由于我们已经在 ALB 的安全组中将端口限制为 80 和 443,并且现在 EC2 实例 sg 设置在 ALB 的 sg 之后(现在所有内部流量),因此无需在 EC2 实例 sg 中将端口限制为 80 / 443。您可以将其保留为 0 以允许所有端口。如果您限制到错误的端口,健康检查将开始失败。请参阅 AWS 故障排除页面中的以下内容:

    确认与您的容器实例关联的安全组允许来自与您的负载均衡器关联的安全组的临时端口范围(通常是端口 32768-65535)上的所有入口流量

重要:如果您在任务定义中声明主机端口,则服务将在指定端口上公开,而不是在临时端口范围内。因此,请确保您的安全组反映的是指定的主机端口,而不是临时端口范围。


其他问题

这确实花了我很多精力和时间来弄清楚。一个小问题是我仍然无法让容器级别的健康检查工作,这是在 AWS ECS 的任务定义中定义的。我尝试将ssh 放入容器实例(EC2 实例),结果发现localhost 显然不起作用。在直接在 EC2 实例上测试 curl 时,甚至 AWS trouble shooting page 也在使用从 docker inspect 生成的一些 IP 地址。但是对于任务定义容器健康检查,如果不检查localhost,我应该检查什么?我是否应该在运行状况检查命令中也运行docker inspect 以首先获取IP 地址?这个问题还没有解决,现在我只是给一个exit 0 绕过健康检查。如果有人知道配置它的正确方法是什么,请随时分享,我也很想知道。

【讨论】:

以上是关于Terraform 创建了 AWS ECS 基础设施:运行状况检查一直失败的主要内容,如果未能解决你的问题,请参考以下文章

Terraform + AWS ECS,持续部署流程?

Terraform 中的 ECS 服务如何连接到 AWS 自动缩放组

Terraform:ECS 服务 - InvalidParameterException

用于 ECS 任务/容器的 Terraform AWS CloudWatch 日志组

在 Terraform 的 aws_ecs_task_definition 资源中设置 ulimit 堆栈大小

terraform-ecs。已注册的容器实例显示为 0