AWS Auto Scalingの構築

  • 2019.11.01
  • AWS
AWS Auto Scalingの構築

はじめに

AWS の Auto Scalingについて構築して動作確認をしてみたいと思います。
今回もCLIで構築していきます。

構築するためのVPC周り

今回は既存のVPCとサブネットを使用するため、どのVPCとサブネットを使うか先に確認しておきます。

$ aws ec2 describe-vpcs

(途中省略)
        {
            "CidrBlock": "10.1.0.0/16",
            "DhcpOptionsId": "dopt-70b2ea17",
            "State": "available",
            "VpcId": "vpc-04e72e6413b624d29",
            "OwnerId": "281230433728",
            "InstanceTenancy": "default",
            "CidrBlockAssociationSet": [
                {
                    "AssociationId": "vpc-cidr-assoc-0881ba835faad6c8b",
                    "CidrBlock": "10.1.0.0/16",
                    "CidrBlockState": {
                        "State": "associated"
                    }
                }
            ],
            "IsDefault": false,
            "Tags": [
                {
                    "Key": "Name",
                    "Value": "myvpc02"
                }
            ]
        }
    ]
}

$ echo $vpc_id
vpc-04e72e6413b624d29

$ aws ec2 describe-subnets --filter Name=vpc-id,Values=$vpc_id
{
    "Subnets": [
        {
            "AvailabilityZone": "ap-northeast-1c",
            "AvailabilityZoneId": "apne1-az1",
            "AvailableIpAddressCount": 250,
            "CidrBlock": "10.1.1.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": true,
            "State": "available",
            "SubnetId": "subnet-0f2edab09ccc98c0f",
            "VpcId": "vpc-04e72e6413b624d29",
            "OwnerId": "281230433728",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "SubnetArn": "arn:aws:ec2:ap-northeast-1:281230433728:subnet/subnet-0f2edab09ccc98c0f"
        },
        {
            "AvailabilityZone": "ap-northeast-1a",
            "AvailabilityZoneId": "apne1-az4",
            "AvailableIpAddressCount": 248,
            "CidrBlock": "10.1.0.0/24",
            "DefaultForAz": false,
            "MapPublicIpOnLaunch": true,
            "State": "available",
            "SubnetId": "subnet-0b99e52d17314979d",
            "VpcId": "vpc-04e72e6413b624d29",
            "OwnerId": "281230433728",
            "AssignIpv6AddressOnCreation": false,
            "Ipv6CidrBlockAssociationSet": [],
            "SubnetArn": "arn:aws:ec2:ap-northeast-1:281230433728:subnet/subnet-0b99e52d17314979d"
        }
    ]
}

起動テンプレートの作成

Auto Scaling機能によって新しく作成されるEC2インスタンスのための起動テンプレートを作成します。ここではイメージではなく、起動テンプレートを作成し、ユーザーデータのところを工夫したいと思います。

ユーザーデータは次のようなシェルにします。まずは、この内容のテキストデータを作成してください。

#!/usr/bin/bash

outfile=/home/ec2-user/www/index.html

mkdir /home/ec2-user/www

echo "<html>" > ${outfile}
echo "  <body> " >> ${outfile}
echo -n "    EC2 " >> ${outfile}
echo $HOSTNAME | cut -f1 -d. | cut -f2-5 -d- >> ${outfile}
echo "  </body>" >> ${outfile}
echo "</html>" >> ${outfile}

cd /home/ec2-user/www
nohup python -m SimpleHTTPServer 80 &
echo "@reboot cd /home/ec2-user/www;nohup python -m SimpleHTTPServer 80 &" | crontab

次にこのユーザーデータを起動テンプレートのjsonファイルに設定するためにBase64にエンコードしてやります。

$ base64 userdata.txt 
IyEvdXNyL2Jpbi9iYXNoCgpvdXRmaWxlPS9ob21lL2VjMi11c2VyL3d3dy9pbmRleC5odG1sCgpta2RpciAvaG9tZS9lYzItdXNlci93d3cKCmVjaG8gIjxodG1sPiIgPiAke291dGZpbGV9CmVjaG8gIiAgPGJvZHk+ICIgPj4gJHtvdXRmaWxlfQplY2hvIC1uICIgICAgRUMyICIgPj4gJHtvdXRmaWxlfQplY2hvICRIT1NUTkFNRSB8IGN1dCAtZjEgLWQuIHwgY3V0IC1mMi01IC1kLSA+PiAke291dGZpbGV9CmVjaG8gIiAgPC9ib2R5PiIgPj4gJHtvdXRmaWxlfQplY2hvICI8L2h0bWw+IiA+PiAke291dGZpbGV9CgpjZCAvaG9tZS9lYzItdXNlci93d3cKbm9odXAgcHl0aG9uIC1tIFNpbXBsZUhUVFBTZXJ2ZXIgODAgJgplY2hvICJAcmVib290IGNkIC9ob21lL2VjMi11c2VyL3d3dztub2h1cCBweXRob24gLW0gU2ltcGxlSFRUUFNlcnZlciA4MCAmIiB8IGNyb250YWIK

起動テンプレートの設定内容をjsonファイルとして作成します。先ほどBase64にエンコードした内容をUserDataの項目の値としてセットします。

{
    "NetworkInterfaces": [{
        "AssociatePublicIpAddress": true,
	      "DeleteOnTermination": true,
        "DeviceIndex": 0
     }],
    "ImageId": "ami-0ff21806645c5e492",
    "InstanceType": "t2.micro",
    "KeyName": "myawskey-tokyo",
    "UserData": "IyEvdXNyL2Jpbi9iYXNoCgpvdXRmaWxlPS9ob21lL2VjMi11c2VyL3d3dy9pbmRleC5odG1sCgpta2RpciAvaG9tZS9lYzItdXNlci93d3cKCmVjaG8gIjxodG1sPiIgPiAke291dGZpbGV9CmVjaG8gIiAgPGJvZHk+ICIgPj4gJHtvdXRmaWxlfQplY2hvIC1uICIgICAgRUMyICIgPj4gJHtvdXRmaWxlfQplY2hvICRIT1NUTkFNRSB8IGN1dCAtZjEgLWQuIHwgY3V0IC1mMi01IC1kLSA+PiAke291dGZpbGV9CmVjaG8gIiAgPC9ib2R5PiIgPj4gJHtvdXRmaWxlfQplY2hvICI8L2h0bWw+IiA+PiAke291dGZpbGV9CgpjZCAvaG9tZS9lYzItdXNlci93d3cKbm9odXAgcHl0aG9uIC1tIFNpbXBsZUhUVFBTZXJ2ZXIgODAgJgplY2hvICJAcmVib290IGNkIC9ob21lL2VjMi11c2VyL3d3dztub2h1cCBweXRob24gLW0gU2ltcGxlSFRUUFNlcnZlciA4MCAmIiB8IGNyb250YWIK"
}

次のコマンドで起動テンプレートを作成します。

$ aws ec2 create-launch-template --launch-template-name TestTemplate --version-description "Auto Scaling Test" --launch-template-data file://template-data.json
{
    "LaunchTemplate": {
        "LaunchTemplateId": "lt-02c5e20f44eea5b35",
        "LaunchTemplateName": "TestTemplate",
        "CreateTime": "2019-10-28T08:15:24.000Z",
        "CreatedBy": "arn:aws:iam::281230433728:user/admin",
        "DefaultVersionNumber": 1,
        "LatestVersionNumber": 1
    }
}

Auto Scaling グループの作成

まずは次のような内容の JSON ファイルを作成します。

{
    "AutoScalingGroupName": "TestGroup",
    "LaunchTemplate": {
        "LaunchTemplateId": "lt-02c5e20f44eea5b35"
    },
    "MinSize": 1,
    "MaxSize": 3,
    "VPCZoneIdentifier": "subnet-0f2edab09ccc98c0f,subnet-0b99e52d17314979d"
}

これは先ほど作成した起動テンプレートを元に、指定したサブネットに1〜3個のEC2インスタンスを作成する設定です。それでは次のコマンドでAuto Scaling グループを作成しましょう。

$ aws autoscaling create-auto-scaling-group --cli-input-json file://autoscaling.json

しばらくするとEC2インスタンスが1つ自動的に起動してくるはずです。
ここで使用している desc-ins-vpc はエイリアスです。

$ aws desc-ins-vpc $vpc_id
[
    {
        "InstanceId": "i-095d59e1d63a21900",
        "State": "running",
        "AvailabirityZone": "ap-northeast-1c",
        "PrivateDnsName": "ip-10-1-1-89.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.1.89",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    }
]

PublicDnsNameに対してブラウザで接続してみます。

正常に稼働しているようです。

スケーリングポリシーの作成

スケールアウトしたときのポリシーを作成しておきます。

$ aws autoscaling put-scaling-policy --policy-name mystep-scalein-policy --auto-scaling-group-name TestGroup --policy-type StepScaling --adjustment-type ChangeInCapacity --step-adjustments MetricIntervalLowerBound=30,ScalingAdjustment=1 --estimated-instance-warmup 60
{
    "PolicyARN": "arn:aws:autoscaling:ap-northeast-1:281230433728:scalingPolicy:cbd51753-9c55-4df7-b314-1bfa46960eb7:autoScalingGroupName/TestGroup:policyName/mystep-scalein-policy",
    "Alarms": []
}

CloudWatch アラームの作成

ここからアラームが発生したらEC2インスタンスの数を増やす設定をしていきます。まずは、CloudWatch のアラームを作成します。

最初にどのようなメトリクスがあるか調べてみます。

$ aws cloudwatch list-metrics --namespace AWS/EC2 --dimensions Name=AutoScalingGroupName,Value=TestGroup
{

(途中省略)

        {
            "Namespace": "AWS/EC2",
            "MetricName": "NetworkPacketsIn",
            "Dimensions": [
                {
                    "Name": "AutoScalingGroupName",
                    "Value": "TestGroup"
                }
            ]
        },

(以降省略)

今回はこの NetworkPacketsIn を元に EC2インスタンスの増減を実施してみたいと思います。

まずどの程度の値で推移するか確認しておきます。

$ aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name NetworkPacketsIn --dimensions Name=AutoScalingGroupName,Value=TestGroup --start-time 2019-10-31T0:00 --end-time 2019-10-31T02:00 --period 300 --statistics Average --output text | sort -k 3 | awk '{print $3,$2}'
 
2019-10-31T00:25:00Z 222.0
2019-10-31T00:30:00Z 201.8
2019-10-31T00:35:00Z 53.0
2019-10-31T00:40:00Z 14.0
2019-10-31T00:45:00Z 9.6
2019-10-31T00:50:00Z 16.0
2019-10-31T00:55:00Z 36.6
2019-10-31T01:00:00Z 13.8
2019-10-31T01:05:00Z 9.0
2019-10-31T01:10:00Z 7.6
2019-10-31T01:15:00Z 12.6
2019-10-31T01:20:00Z 9.0
2019-10-31T01:25:00Z 9.4
2019-10-31T01:30:00Z 63.8
2019-10-31T01:35:00Z 6.4

試しに作成したEC2インスタンスのWebページを何回か更新してみました。1:30の63.8がその時の値になります。この結果から30以上になったら、EC2インスタンスを増加させるくらいでいいのかなと分かりました。

それではアラートを作成する準備をします。次のようなJSONファイルを作ります。

{
    "AlarmName": "NetworkPacketInOver30",
    "AlarmDescription": "AutoScaling Test",
    "AlarmActions": [
	"arn:aws:autoscaling:ap-northeast-1:281230433728:scalingPolicy:dc0014ff-d2cf-417e-9244-49988546ad06:autoScalingGroupName/TestGroup:policyName/mystep-scalein-policy"
    ],
    "MetricName": "NetworkPacketsIn",
    "Namespace": "AWS/EC2",
    "Statistic": "Average",
    "Dimensions": [
        {
            "Name": "AutoScalingGroupName",
            "Value": "TestGroup"
        }
    ],
    "Period": 300,
    "EvaluationPeriods": 1,
    "Threshold": 30,
    "ComparisonOperator": "GreaterThanOrEqualToThreshold"
}

次のコマンドでアラートを作成します。

$ aws cloudwatch put-metric-alarm --cli-input-json file://alert.json

これでNetworkPacketsInが30以上になるとEc2インスタンスが1つ追加されるようになります。

動作確認

それではEC2インスタンス上のWebページを何回か更新してみてトリガーを発生させてみます。

$ aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name NetworkPacketsIn --dimensions Name=AutoScalingGroupName,Value=TestGroup --start-time 2019-10-31T23:00 --end-time 2019-11-01T00:00 --period 300 --statistics Average --output text | sort -k 3 | awk '{print $3, $2}';aws desc-ins-vpc $vpc_id
 
2019-10-31T23:40:00Z 11.4
2019-10-31T23:45:00Z 13.133333333333333
2019-10-31T23:50:00Z 13.733333333333333
2019-10-31T23:55:00Z 9.933333333333334
[
    {
        "InstanceId": "i-08c4d6898c951da65",
        "State": "running",
        "AvailabirityZone": "ap-northeast-1a",
        "PrivateDnsName": "ip-10-1-0-6.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.0.6",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    }
]

更新前はまだEC2インスタンスは1つしかありません。

$ aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name NetworkPacketsIn --dimensions Name=AutoScalingGroupName,Value=TestGroup --start-time 2019-10-31T23:00 --end-time 2019-11-01T00:00 --period 300 --statistics Average --output text | sort -k 3 | awk '{print $3, $2}';aws desc-ins-vpc $vpc_id
 
2019-10-31T23:20:00Z 12.75
2019-10-31T23:25:00Z 50.8
2019-10-31T23:30:00Z 9.4
2019-10-31T23:35:00Z 76.0
2019-10-31T23:40:00Z 11.4
2019-10-31T23:45:00Z 13.133333333333333
2019-10-31T23:50:00Z 13.733333333333333
2019-10-31T23:55:00Z 9.933333333333334
[
    {
        "InstanceId": "i-0f14db208f1cc7c6e",
        "State": "pending",
        "AvailabirityZone": "ap-northeast-1c",
        "PrivateDnsName": "ip-10-1-1-215.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.1.215",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    },
    {
        "InstanceId": "i-08c4d6898c951da65",
        "State": "running",
        "AvailabirityZone": "ap-northeast-1a",
        "PrivateDnsName": "ip-10-1-0-6.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.0.6",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    }
]

EC2インスタンスが2つになりました。まだ、cloudwatch側では表示されていませんが、実際には30を超えていると思われます。無料枠のcloudwatchは5分間隔なので、表示されてきていないだけなのでしょうか。

$ aws cloudwatch get-metric-statistics --namespace AWS/EC2 --metric-name NetworkPacketsIn --dimensions Name=AutoScalingGroupName,Value=TestGroup --start-time 2019-10-31T23:00 --end-time 2019-11-01T01:00 --period 300 --statistics Average --output text | sort -k 3 | awk '{print $3, $2}';aws desc-ins-vpc $vpc_id
 
2019-10-31T23:20:00Z 12.75
2019-10-31T23:25:00Z 50.8
2019-10-31T23:30:00Z 9.4
2019-10-31T23:35:00Z 76.0
2019-10-31T23:40:00Z 11.4
2019-10-31T23:45:00Z 13.133333333333333
2019-10-31T23:50:00Z 13.733333333333333
2019-10-31T23:55:00Z 9.933333333333334
2019-11-01T00:00:00Z 11.4
2019-11-01T00:05:00Z 12.6
2019-11-01T00:10:00Z 11.133333333333333
2019-11-01T00:15:00Z 12.666666666666666
2019-11-01T00:20:00Z 9.266666666666667
2019-11-01T00:25:00Z 9.333333333333334
2019-11-01T00:30:00Z 13.428571428571429
2019-11-01T00:40:00Z 276.0
2019-11-01T00:45:00Z 43.2
[
    {
        "InstanceId": "i-0f14db208f1cc7c6e",
        "State": "running",
        "AvailabirityZone": "ap-northeast-1c",
        "PrivateDnsName": "ip-10-1-1-215.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.1.215",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    },
    {
        "InstanceId": "i-08c4d6898c951da65",
        "State": "running",
        "AvailabirityZone": "ap-northeast-1a",
        "PrivateDnsName": "ip-10-1-0-6.ap-northeast-1.compute.internal",
        "PrivateIpAddress": "10.1.0.6",
        "PublicDnsName": "ec2-hoge.ap-northeast-1.compute.amazonaws.com",
        "PublicIpAddress": "hoge",
        "Name": null
    }
]

end-timeの指定がミスっていました。なんにしてもこれでAutoScalingとCloudWatchを連携させることができました。