AWS AutoScalingGroup HealthCheckType'ELB'过早地考虑实例“InService”

时间:2014-11-25 07:15:22

标签: amazon-web-services autoscaling amazon-elb amazon-cloudformation

我正在尝试通过引入在线新实例来使AutoScalingRollingUpdate在我的自动扩展组上工作,然后只有在新实例接受流量时才,终止旧的实例。似乎AutoScalingRollingUpdate就是为此而设计的。

我的AutoScalingGroup的HealthCheckType设置为'ELB'。我还要求ELB上的HealthCheck要求:

  • 3次成功请求/“健康”
  • 10次对“不健康”
  • 的请求失败
  • 没有宽限期(零,0)

现在,从ELB的角度来看,当新实例联机时,它们不是InService几分钟,这就是我的期望。但是,从AutoScalingGroup的角度来看,它们几乎立即被视为InService,因此,我的AutoScalingGroup在新实例准备好接收流量之前将健康实例停止服务。我很困惑为什么ASG认为实例在ELB之前是健康的,当HealthCheckType明确地设置为'ELB'时。

我已尝试设置宽限期,但这根本不会改变任何内容。事实上,我删除了300秒的宽限期,因为我认为在宽限期内可能实例是隐含的“InService”或其他东西。

我知道我可以在滚动更新策略上设置PauseTime,但这很脆弱,因为有时在实例联机时会发生故障,并且在完成配置之前它们会被修复和替换,所以有时候 ,可能会超出PauseTime窗口。此外,我想尽量减少我的应用同时运行两个不同版本的时间。

    ... ELB stuff ...

    "HealthCheck": {
      "HealthyThreshold": "3",
      "UnhealthyThreshold": "10",
      "Interval": "30",
      "Timeout": "15",
      "Target": {
        "Fn::Join": [
          "",
          [
            {"Fn::Join": [":", ["HTTP", {"Ref": "hostPort"}]]},
            {"Ref": "healthCheckPath"}
          ]
        ]
      }
    },

   ... ASG Stuff ...

  {
    ... snip ...

    "HealthCheckType": "ELB",
    "HealthCheckGracePeriod": "0",
    "Cooldown": "300"
  },
  "UpdatePolicy" : {
    "AutoScalingRollingUpdate" : {
      "MinInstancesInService" : "1",
      "MaxBatchSize" : "1"
    }
  }

2 个答案:

答案 0 :(得分:21)

首先,根据我们使用CloudFormation的经验,ASG HealthCheckType和HealthCheckGracePeriod主要在CloudFormation事件范围之外使用。只要将新实例添加到ASG,这些属性就会发挥作用。这可以在CloudFormation更新期间,也可以在Auto Scaling事件期间或自我修复事件期间进行。在后一种情况下,重要的是将HealthCheckGracePeriod设置为一个值,以便在考虑ELB运行状况检查之前为新实例提供足够的上线时间。

您最感兴趣的功能似乎是在使用修改后的启动配置运行CloudFormation更新时调用的UpdatePolicy。神奇属性是WaitOnResourceSignals,它迫使ASG在考虑更新成功之前等待成功信号。

  "UpdatePolicy" : {
    "AutoScalingRollingUpdate" : {
      "MinInstancesInService" : "1",
      "MaxBatchSize" : "1",
      "PauseTime" : "PT15M",
      "WaitOnResourceSignals" : "true"
    }
  },

当WaitOnResourceSignals属性设置为true时,PauseTime属性将变为超时。如果ASG在15分钟的PauseTime内没有收到信号,则认为更新失败,新实例终止。一旦ASG收到成功信号,ASG健康检查就会发挥作用,除非HealthCheckGracePeriod尚未过期。我们通常将HealthCheckGracePeriod设置为与PauseTime相同的值。这可确保在实例有机会发送信号或达到PauseTime超时之前,我们永远不会开始使用ELB运行状况检查。 http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html

通常,成功信号将在ASG启动配置的UserData内的cfn-init引导脚本之后发送到ASG。

"UserData"       : { "Fn::Base64" : { "Fn::Join" : ["", [
     "#!/bin/bash -xe\n",
     "yum update -y aws-cfn-bootstrap\n",

     "/opt/aws/bin/cfn-init -v ",
     "         --stack ", { "Ref" : "AWS::StackName" },
     "         --resource LaunchConfig ",
     "         --configsets full_install ",
     "         --region ", { "Ref" : "AWS::Region" }, "\n",

     "/opt/aws/bin/cfn-signal -e $? ",
     "         --stack ", { "Ref" : "AWS::StackName" },
     "         --resource WebServerGroup ",
     "         --region ", { "Ref" : "AWS::Region" }, "\n"
]]}}

这对于许多情况来说已经足够了,但有时当我们将成功信号发送回ASG时,实例可能仍未准备就绪。例如,我们可能希望等待后台进程加载数据或等待我们的应用程序服务器启动。如果我们的ELB运行状况检查针对要求我们的应用程序运行的URL,则尤其如此。在这些情况下,我们希望延迟成功信号,直到我们的实例准备就绪。下面是一个如何创建启动配置configSet以延迟信号直到ELB API返回" InService"实例的状态。

  "verify_instance_health" : {
    "commands" : {
      "ELBHealthCheck" : {
        "command" : { "Fn::Join" : ["", [ 
          "until [ \"$state\" == \"\\\"InService\\\"\" ]; do ",
          "  state=$(aws --region ", { "Ref" : "AWS::Region" }, " elb describe-instance-health ",
          "              --load-balancer-name ", { "Ref" : "ElasticLoadBalancer" }, 
          "              --instances $(curl -s http://169.254.169.254/latest/meta-data/instance-id) ",
          "              --query InstanceStates[0].State); ",
          "  sleep 10; ",
          "done"
        ]]}
      }
    }
  }

有关更多信息和使用ELB运行状况检查的完整示例,请参阅此讨论论坛 - https://forums.aws.amazon.com/ann.jspa?annID=2741

注意:这些示例还要求您使用ASG CreationPolicy属性在ASG创建期间接收信号。过去,WaitCondition和WaitConditionHandle资源用于接收信号,但不再推荐这些信号。 Count属性是创建时应接收的信号数。该值应等于ASG MinSize编号。

  "CreationPolicy" : {
    "ResourceSignal" : {
      "Timeout" : "PT15M",
      "Count"   : "2"
    }
  },

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html

答案 1 :(得分:4)

我意识到这有点晚了,但也许可能会节省一些时间和精力。

如果使用elbv2,则命令如下所示。请注意"=""==",因为这会让我吵闹几个小时。 Ubuntu 16将命令运行为/bin/sh而不是/bin/bash,这意味着[ \"$state\" == \"\\\"healthy\\\"\" ]将永远不会生成。至少这是我的理解。

"commands": {
  "ELBHealthCheck": {
    "command": {
      "Fn::Join": ["", [
        "until [ \"$state\" = \"\\\"healthy\\\"\" ]; do ",
        "state=$(aws elbv2 describe-target-health ",
        "--region ", {
          "Ref": "AWS::Region"
        },
        " ",
        "--target-group-arn ", {
          "Ref": "ELBRestPublicTargetGroup"
        },
        " ",
        "--targets Id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) ",
        "--query TargetHealthDescriptions[0].TargetHealth.State); ",
        "echo $(date): [$state] >> /tmp/health.log; ",
        "sleep 10; ",
        "done"
      ]]
    }
  }
}