Terraform 创建了 AWS ECS infra:健康检查不断失败

Terraform created AWS ECS infra: health check keep failing

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

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

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,以 link 我在 Route 53 上的域名。我注意到还有另一个地方在做健康检查:目标组和应用程序负载均衡器。这里的检查也失败了,我的实例状态是 draining.

安全组

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

那么为什么健康检查失败以及还缺少什么?

有很多文章指出AWS上的Nginx配置、PORT或入站限制(安全group/target组)可能是常见的原因,我都看了一下。我让nginx监听80,设置容器端口为80,安全组允许范围广泛的入站端口。我还能缺少什么?

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

问题与原因

原来是和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 故障排除页面中的以下内容:

  1. Confirm that the security group associated with your container instance allows all ingress traffic on the ephemeral port range (typically ports 32768-65535) from the security group associated with your load balancer

Important: If you declare the host port in your task definition, the service will be exposed on the specified port rather than in the ephemeral port range. For this reason, be sure that your security group reflects the specified host port instead of the ephemeral port range.


其他问题

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