Подтвердить что ты не робот

AWS AutoScalingGroup HealthCheckType "ELB" преждевременно рассматривает экземпляр "InService"

Я пытаюсь получить AutoScalingRollingUpdate для работы с моей группой автомасштабирования, путем ввода новых онлайн-экземпляров, а затем только после того, как новый экземпляр принимает трафик, завершая старые экземпляры. Кажется, что AutoScalingRollingUpdate предназначен для этой цели.

У меня есть значение HealthCheckType для моей модели AutoScalingGroup, заданное как "ELB". У меня также есть HealthCheck на ELB, который требует:

  • 3 успешных запроса/для "здоровых"
  • 10 неуспешных запросов/для "нездоровых"
  • нет льготного периода (ноль, 0)

Теперь, с точки зрения ELB, когда новые экземпляры подключаются к сети, они не являются InService в течение нескольких минут, что я и ожидаю. Тем не менее, с точки зрения AutoScalingGroup, они почти сразу рассматриваются как InService, и поэтому моя AutoScalingGroup выводит здоровые экземпляры из строя до того, как новые экземпляры действительно готовы принять трафик. Я смущен, почему ASG считает, что экземпляры здоровы до того, как ELB сделает, когда для параметра HealthCheckType явно установлено значение "ELB".

Я пробовал установить льготный период, но это ничего не меняет. Фактически, я удалил льготный период в 300 секунд, потому что я думал, что экземпляры были неявно "InService" в течение льготного периода или что-то в этом роде.

Я знаю, что могу установить PauseTime в скользящей политике обновления, но это хрупко, потому что иногда случаются сбои, когда экземпляры появляются в сети, и они получают nuked и заменяются до того, как они когда-либо завершат подготовку, поэтому иногда окно 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"
    }
  }
4b9b3361

Ответ 1

Во-первых, из нашего опыта использования CloudFormation ASG HealthCheckType и HealthCheckGracePeriod используются в основном вне сферы событий CloudFormation. Эти свойства вступают в игру в любое время, когда в ASG добавляется новый экземпляр. Это может быть во время обновления CloudFormation, но также во время событий Auto Scaling или во время события самовосстановления. В последнем случае важно установить для параметра HealthCheckGracePeriod значение, которое дает новому экземпляру достаточное время для выхода в Интернет, прежде чем рассматривать проверки работоспособности ELB.

Похоже, вам больше всего интересна функция UpdatePolicy, которая вызывается при запуске обновления CloudFormation с измененной конфигурацией запуска. Свойством magic является WaitOnResourceSignals, который заставляет ASG ждать сигнала успеха, прежде чем считать обновление успешным.

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

Если для свойства WaitOnResourceSignals установлено значение true, свойство PauseTime становится таймаутом. Если ASG не получает сигнал в течение PauseTime в течение 15 минут, обновление считается сбоем, а новый экземпляр прекращается. Как только ASG получает сигнал успеха, проверяется проверка работоспособности ASG, если срок действия HealthCheckGracePeriod еще не истек. Обычно мы устанавливаем значение параметра HealthCheckGracePeriod равным значению PauseTime. Это гарантирует, что мы никогда не начнем использовать проверку работоспособности ELB, прежде чем экземпляр сможет отправить сигнал или достигнуть таймаута PauseTime. http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html

Как правило, сигнал успешности отправляется в ASG после начальной загрузки cfn-init script из пользовательских данных конфигурации запуска 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-адрес, который требует, чтобы наше приложение работало. В этих случаях мы хотим отложить сигнал успеха до тех пор, пока наш экземпляр не будет готов. Вот пример того, как создать конфигурационный конфигуратор Launch Configuration для задержки сигнала до тех пор, пока 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

Ответ 2

Я понимаю, что это немного поздно, но, возможно, это может сэкономить время и силы.

Если вы используете 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"
      ]]
    }
  }
}