AutoScalingグループを作成する場合の注意点について

AutoScalingグループを作成する際の注意点について、まとめていきます。 特に言及していないプロパティはAWSの例通りでいいと思います。

AutoScalingGroupのプロパティ

インスタンスの数(MinSize,MaxSize,DesiredCapacity)

AZの倍数にする
東京なら1aと1cなので、2の倍数にする

※ELBの基本としてAZのインスタンス数は均等にすることが推奨されているため
http://docs.aws.amazon.com/ja_jp/ElasticLoadBalancing/latest/DeveloperGuide/enable-disable-crosszone-lb.html

耐障害性を高めるために有効な各アベイラビリティーゾーンにおよそ等しい数のバックエンドインスタンスを維持することをお勧めします。

HealthCheckGracePeriod

新しい EC2 インスタンスがサービス状態になってから、Auto Scaling がヘルスチェックを開始するまでの秒数。
デフォルトは300ですが、できるだけ早くヘルスチェックを開始しないと高負荷時にサービスが停止する可能性が高くなります。
そのため、起動時のプロビジョニングはできるだけしないようにして、プロビジョニング済みのAMIを使用すべきです。

※スケーリング時のインスタンス追加までの流れはおおまに以下のようになります

alarm(Threshold超えから次回のPeriod(最小60)まで): 60-α秒
インスタンス起動からサービス状態になる: 約3~10分
ELBのヘルスチェックのInterval(最小は5) * HealthyThreshold(最小は2): 最小5秒* 2
HealthCheckGracePeriod経過: 最小はなしだが、必ずヘルスチェック成功までの時間以上にする

つまり耐障害性を高めるためには以下のようにすべきです

* Periodを60
* 起動時のプロビジョニングはできるだけしない
* ヘルスチェックの成功までの時間をできるだけ短くする
* HealthCheckGracePeriodをできるだけ小さくする
* (ELBのヘルスチェック成功直後にAutoScalingGroupがヘルスチェックをする時間にする)

HealthCheckType

${デプロイ時間} > Interval * HealthyThresholdの場合はELBだとデプロイ時にインスタンスが増えます。
ELBにするとアクセスが集中して,ELBのヘルスチェック失敗時にインスタンスを増やしてくれます。

Tags

以下のようにして、オートスケーリンググループ内で起動したインスタンスに名前が設定されるようにします

        "Tags": [
          {
            "ResourceType"      : "auto-scaling-group",
            "ResourceId"        : "AutoScalingGroup",
            "PropagateAtLaunch" : true,
            "Key"               : "Name",
            "Value"             : { "Ref" : "AWS::StackName" }
          }
        ]

LaunchConfig

できるだけ、UserDataはシンプルにします。  
また、cfn-initでの各種インストールはAMIでしておくべきです。  
最後に成功のシグナルをCloudFormationが受け取れるようにcfn-signalを実行します。  
        "UserData": { "Fn::Base64" : { "Fn::Join" : ["", [
          "#!/bin/bash -xe\n",
          "# Install the files and packages from the metadata\n",
          "/opt/aws/bin/cfn-init",
          " --stack ", { "Ref" : "AWS::StackName" },
          " --resource LaunchConfig",
          " --configsets Install",
          " --region ", { "Ref" : "AWS::Region" }, "\n",

          "# Signal the status from cfn-init\n",
          "/opt/aws/bin/cfn-signal -e $?",
          " --stack ", { "Ref" : "AWS::StackName" },
          " --resource AutoScalingGroup",
          " --region ", { "Ref" : "AWS::Region" }, "\n"
        ]]}}

CreationPolicy

CountはUpdatePolicyのMinInstancesInServiceと同じ値を使用します。  
TimeoutはPT5Mにします。  
起動に5分以上かかる場合は実際に負荷の上昇にインスタンスの増加が間に合わなくなる可能性があります  
複数台でも同時に作成されます
※通常約3分でReceived SUCCESS signal with UniqueId i-XXXXXXXXXXXXXXXXXXXXになります
      "CreationPolicy": {
        "ResourceSignal": {
          "Count"  : "X",
          "Timeout": "PT5M"
        }
      }

UpdatePolicy

CloudFormationがAutoScalingGroupに対するUPDATEの設定です。
※AutoScaling時の設定ではありません

WillReplace

AutoScalingに対する設定で最も重要な設定です。

trueにすることで作成に成功したときしか前のAutoScalingGroupを削除しません
※trueにしない場合はスタックのロールバックに失敗する可能性があります

PauseTime

CreationPolicyのTimeoutと同じでシグナルを受け取るまでなので、5分にします。
※これでシグナル送信までに5分以上経過するとUpdateは失敗します
      "UpdatePolicy" : {
        "AutoScalingReplacingUpdate" : {
          "WillReplace" : "true"
        },
        "AutoScalingScheduledAction" : {
          "IgnoreUnmodifiedGroupSizeProperties" : "true"
        },
        "AutoScalingRollingUpdate" : {
          "MinInstancesInService" : { "Fn::FindInMap": [ "InstanceSettings", "Count", "Min"]},
          "MaxBatchSize"          : "X",
          "WaitOnResourceSignals" : "true",
          "PauseTime"             : "PT5M"
        }
      }

Outputs

AutoScalingGroupを差し替える(新グループの作成後に旧グループの削除)際にCodeDeployのデプロイ先のAutoScalingGroupも自動的に更新されるようにします。

  "Outputs" : {
    "AutoScalingGroup" : {
      "Value" : { "Ref" : "AutoScalingGroup" }
    }
  }

テンプレート

    "AutoScalingGroup" : {
      "Type" : "AWS::AutoScaling::AutoScalingGroup",
      "Properties" : {
        "LaunchConfigurationName" : { "Ref" : "LaunchConfig" },
        "MinSize"                 : "X",
        "MaxSize"                 : "X",
        "DesiredCapacity"         : "X",
        "HealthCheckGracePeriod"  : "XX",
        "HealthCheckType"         : "ELB",
        "LoadBalancerNames"       : [ { "Ref" : "ELBWeb" } ],
        "VPCZoneIdentifier"       : [
          { "Ref": "PublicSubnet1a" },
          { "Ref": "PublicSubnet1c" }
        ],
        "Tags": [
          {
            "ResourceType"      : "auto-scaling-group",
            "ResourceId"        : "AutoScalingGroup",
            "PropagateAtLaunch" : true,
            "Key"               : "Name",
            "Value"             : { "Ref" : "AWS::StackName" }
          }
        ]
      },
      "CreationPolicy": {
        "ResourceSignal": {
          "Count"  : "${MinInstancesInService}",
          "Timeout": "PT5M"
        }
      },
      "UpdatePolicy" : {
        "AutoScalingReplacingUpdate" : {
          "WillReplace" : "true"
        },
        "AutoScalingScheduledAction" : {
          "IgnoreUnmodifiedGroupSizeProperties" : "true"
        },
        "AutoScalingRollingUpdate" : {
          "MinInstancesInService" : "${MinInstancesInService}",
          "MaxBatchSize"          : "X",
          "WaitOnResourceSignals" : "true",
          "PauseTime"             : "PT5M"
        }
      }
    }