无停机 AWS + ECS Cloudformation

No Down-Time AWS + ECS Cloudformation

伙计们。

我有一个小问题,到目前为止我还没有解决。 事情是这样的:我有一个在 ECS 上运行的小应用程序。 为了创建应用程序,我创建了一个 ASG 并在 LaunchConfig 上将实例注册到我的 ECS 集群.后来,我在我的ASG前面放了一个ALB,这样我的应用程序就可以在Internet上使用了;到目前为止一切都很好。当我想对我的 ECS 实例进行更新时,问题就来了。我的停机时间很短,只有 20 秒。

嗯,这不是完全停机,但发生的是我的 LB 在更新期间不断向我的 ECS1 发送请求滚动,所以我在浏览器上得到了一个非常好的 502。当然,一旦更新完成,一切都会好起来的。当更新我的 ECS2 实例时,同样的 502 也会发生。如果我刷新,我会得到一个可用的应用程序;如果我第二次刷新,我会得到 502,因为正如我所说,ALB 不断向我的 IN 发送请求PROGRESS(滚动更新)ECS 实例。

所以,我想我可以在更新 ECS 实例时注销它,然后,当它完成时,我可以重新注册它。但我正在使用 CloudFormation 来滚动更新,我真的不想手动做事。

我当前的健康检查每 30 秒进行一次,以便目标组将某个实例视为不健康,因此停止向其发送请求。

我怎样才能完成它?

谢谢!

有一个很棒的 article on the AWS blog 解释了如何完成此操作。他们甚至使用 CloudFormation 作为示例,因此不涉及手动步骤。

他们基本上使用与 SNS 和 Lambda 配对的 Autoscaling Groups Lifecycle hook 在 ASG 实例停止服务时触发连接耗尽。最重要的是,这在 CloudFormation 触发滚动更新时也有效。

They open sourced the solution on GitHub,你可以使用整个东西,也可以根据需要复制有趣的部分。

我找到了答案,希望这对以后的人有所帮助。

避免停机的关键是将LB注册到ECS服务,这样LB就会为我们做脏活。在容器更新之前,LB 将耗尽实例,因此不会向它发送请求。同时,只有一个实例,它是一个健康的实例。

当另一个实例耗尽时,LB 只向健康的实例发送请求。一旦实例被耗尽并从 LB 中注销,更新将在耗尽的实例上滚动。凉爽的!!不是吗?

因此,一旦完成更新,LB 将其重新注册,等待它通过健康检查,然后再次开始发送请求。 这个更新完之后,LB就要开始对剩下的那个做同样的事情了(Drain it, update it, and register it back)

我将与您分享对我有用的片段:

 Resources:
   ECSServiceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [ecs.amazonaws.com]
          Action: ['sts:AssumeRole']
      Path: /
      Policies:
      - PolicyName: ecs-service
        PolicyDocument:
          Statement:
          - Effect: Allow
            Action: ['elasticloadbalancing:DeregisterInstancesFromLoadBalancer', 'elasticloadbalancing:DeregisterTargets',
              'elasticloadbalancing:Describe*', 'elasticloadbalancing:RegisterInstancesWithLoadBalancer',
              'elasticloadbalancing:RegisterTargets', 'ec2:Describe*', 'ec2:AuthorizeSecurityGroupIngress']
            Resource: '*'

  Service:
    Type: AWS::ECS::Service
    Properties:
      Cluster: !Ref Cluster
      DesiredCount: !Ref DesiredCount
      TaskDefinition: !Ref TaskDefinition
      LoadBalancers:
        - ContainerName: nginx
          ContainerPort: '80'
          TargetGroupArn: !Ref TargetGroupARN
      Role: !Ref 'ECSServiceRole'
      DeploymentConfiguration:
        MaximumPercent: 100
        MinimumHealthyPercent: 50

  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ...

从服务中调用 LB 确实有效。您还应该考虑设置一个 MinimumHealthyPercent 来告诉服务有多少实例必须始终运行并且 运行.

希望对您有所帮助!