部署时 AWS ECS 503 服务暂时不可用

AWS ECS 503 Service Temporarily Unavailable while deploying

我正在为我的应用程序使用 Amazon Web Services EC2 容器服务和应用程序负载均衡器。当我部署新版本时,我会收到 503 Service Temporarily Unavailable 大约 2 分钟。它比我的应用程序的启动时间多一点。 这意味着我现在无法进行零停机部署。

是否有设置在启动时不使用新任务?或者我在这里缺少什么?

更新:

ALB 目标组的健康检查编号如下:

Healthy threshold:     5
Unhealthy threshold:   2
Timeout:               5 seconds
Interval:              30 seconds
Success codes:         200 OK

健康阈值是'The number of consecutive health checks successes required before considering an unhealthy target healthy'
不健康阈值是'The number of consecutive health check failures required before considering a target unhealthy.'
超时 为 'The amount of time, in seconds, during which no response means a failed health check.'
间隔是'The approximate amount of time between health checks of an individual target'

更新 2: 因此,我的集群由两个 EC2 实例组成,但可以根据需要进行扩展。所需的最小计数是 2。我 运行 每个实例一个任务,因为我的应用程序需要一个特定的端口号。在部署之前(jenkins 运行s 一个 aws cli 脚本)我将实例数设置为 4。否则,AWS 无法部署我的新任务(这是另一个需要解决的问题)。网络模式为网桥。

既然您使用的是AWS ECS,请问该服务的"minimum health percent"和"maximum health percent"

是什么

确保您有 "maximum health percent" 的 200 和 "minimum health percent" 的 50,以便在部署期间不会关闭所有服务。

请查找这两个术语的文档定义:

Maximum percent provides an upper limit on the number of running tasks during a deployment enabling you to define the deployment batch size.

Minimum healthy percent provides a lower limit on the number of running tasks during a deployment enabling you to deploy without using additional cluster capacity.

"minimum health percent" 的限制为 50 将确保在部署新版本的容器之前只有一半的服务容器被杀死,即如果服务的所需任务值是“2”而不是在部署时,只有“1”个旧版本的容器会首先被杀死,一旦部署了新版本,第二个旧容器将被杀死,并部署一个新版本的容器。这将确保在任何给定时间都有处理请求的服务。

同样,"maximum health percent" 的 200 限制告诉 ecs-agent 在部署期间的给定时间,服务的容器最多可以执行所需任务的两倍。

如有任何其他问题,请告诉我。

根据您的设置,您的应用程序启动时间应该超过 30 秒才能通过 2 次健康检查并被标记为不健康(假设在您的应用程序关闭后立即进行第一次检查)。并且至少需要 2 分钟,最多 3 分钟,然后再次标记为健康(在最好的情况下,您的应用程序恢复在线后立即检查,或者在最坏的情况下,在您的应用程序恢复之前立即检查)。

因此,一个快速而肮脏的修复方法是增加不健康阈值,这样它就不会在更新期间被标记为不健康。并且可能会降低健康阈值,以便更快地再次标记为健康。

但是如果你真的想实现零停机,那么你应该使用你的应用程序的多个实例并告诉 AWS 按照 Manish Joshi 的建议进行部署(这样你的 ELB 后面总是有足够的健康实例来保持你的站点运行)。

我如何解决这个问题是在应用程序根目录中有一个平面文件,ALB 将监视该文件以保持健康。在部署之前,脚本将在监视节点的同时删除此文件,直到它注册 OutOfService

那样的话,所有实时连接都会停止并耗尽。此时,通过停止节点或应用程序进程开始部署。部署后,通过添加回此平面文件将节点添加回 LB 并进行监视,直到它为该节点注册 Inservice,然后移动到第二个节点以完成上述相同步骤。

我的脚本如下所示

# Remove Health Check target
echo -e "\nDisabling the ELB Health Check target and waiting for OutOfService\n"
rm -f /home/$USER/$MYAPP/server/public/alive.html

# Loop until the Instance is Out Of Service
while true
do
        RESULT=$(aws elb describe-instance-health --load-balancer-name $ELB --region $REGION --instances $AMAZONID)
        if echo $RESULT | grep -qi OutOfService ; then
                echo "Instance is Deattached"
                break
        fi
        echo -n ". "
        sleep $INTERVAL
done

你说的是 Jenkins,所以我会考虑 Jenkins master 服务来回答,但我的回答仍然有效任何其他情况(即使它不是 ECS 的一个很好的例子,Jenkins master 不能正确扩展,所以只能有一个实例).

503 错误网关

我经常遇到 503 网关 负载均衡器未通过健康检查 (没有健康实例)相关的错误。查看您的负载均衡器 监控选项卡 以确保健康主机的数量始终高于 0。

如果您正在进行 HTTP 健康检查,它必须 return 一个 代码 200(有效代码列表可在负载平衡器设置中配置)仅当您的服务器真正启动并且 运行ning 时。否则,负载均衡器可能会处理尚未完全 运行ning 的实例。

如果问题是您总是遇到 503 错误网关,这可能是因为您的实例响应时间太长(在服​​务初始化时),所以ECS 认为它们关闭并在它们初始化完成之前关闭它们。 Jenkins 首先 运行.

经常出现这种情况

为避免最后一个问题,您可以考虑调整负载均衡器 ping 目标healthcheck 目标 用于 应用程序的经典负载均衡器侦听器 负载均衡器):

  • 使用 应用程序负载平衡器 ,尝试使用 总是 return 200 的东西(对于 Jenkins 可能是public 文件,例如 /robots.txt)。
  • 使用 经典负载均衡器,使用 TCP 端口测试 而不是 HTTP 测试.如果你正确打开了端口,它总是会成功。

每个实例一个节点

如果您需要确保每个实例只有一个节点,您可以使用 经典负载均衡器(它在 ECS).使用 经典负载均衡器ECS 确保每台服务器只有一个实例 运行。 这也是使 非 HTTP 端口 可访问的唯一解决方案(例如 Jenkins 需要 80,但从服务器也需要 50000)。

但是,由于经典负载均衡器的端口不是动态的,您必须进行一些端口映射,例如:

myloadbalancer.mydomain.com:80 (port 80 of the load balancer) -> instance:8081 (external port of your container) -> service:80 (internal port of your container).

当然,每个服务需要一个负载均衡器。

Jenkins 健康检查

如果这确实是您要启动的 Jenkins 服务,您应该使用 Jenkins Metrics 插件 以获得良好的 健康检查URL.

安装它,在全局选项中,生成一个令牌并激活 ping,您应该能够到达一个 URL,如下所示:http://myjenkins.domain.com/metrics/mytoken12b3ad1/ping

这个URL只有在服务器完全运行ning时才会回答HTTP代码200,这对负载均衡器激活它很重要只有当它完全准备好时。

日志

最后,如果您想知道您的实例发生了什么以及失败的原因,您可以添加日志以查看容器在 AWS Cloudwatch 中说的内容。

只需在任务定义(容器配置)中添加:

Log configuration: awslogs
awslogs-group: mycompany (the Cloudwatch key that will regroup your container logs)
awslogs-region: us-east-1 (your cluster region)
awslogs-stream-prefix: myservice (a prefix to create the log name)

它将让您更深入地了解容器初始化过程中发生的情况,是否花费太长时间或是否失败。

希望对您有所帮助!!!

所以,问题似乎出在任务定义中我的容器设置的端口映射上。 在我使用 80 作为主机和 8080 作为容器端口之前。我以为我需要使用这些,但主机端口实际上可以是任何值。如果将它设置为 0,则 ECS 将在 32768-61000 范围内分配一个端口,因此可以将多个任务添加到一个实例。为了让它工作,我还需要更改我的安全组,让流量从 ALB 到这些端口上的实例。
因此,当 ECS 可以 运行 同一实例上的多个任务时,50/200 min/max 健康百分比是有意义的,并且可以在不需要添加新实例的情况下部署新任务修订版。这也确保了零停机部署。

感谢大家提问或评论!