調子は乗るのものって誰かが言ってた。
((ヽ|・∀・|ノ
|__| ))
||
調子
""""""""""""""""""
「EFSあるならAutoScalingしたいよねー」と思うわけです。
でドキュメントみてたら普通にCloudFormationのサンプルテンプレートあったんで立ち上げてみました。
Amazon Elastic File System サンプルテンプレート - AWS CloudFormation : http://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/quickref-efs.html
$ kumogata create template.json efsdemo \
-s AWS_SECRET_KEY \
-k AWS_ACCESS_KEY \
-r us-east-1 \
-p "KeyName=KEY_FILE_NAME,AsgMaxSize=1" \
--capabilities=CAPABILITY_IAM
立ち上げた結果
EC2は全部Auto Scaling Groupから立ち上がる実装になってます。
SSHで中身を見る
/myEFSvolumeにEFSがマウントされてます。
適当に各インスタンスでファイルを作成してみましたが、下の画像のようにしっかり同期されてます。
CFN抜き出し
ついでに、コード読みたいという人向けにEFS / AutoScaling部分だけ抜き出してみました。
EFS設定部分のJSON
"MountTargetSecurityGroup": {
"Type": "AWS::EC2::SecurityGroup",
"Properties": {
"VpcId": { "Ref": "VPC" },
"GroupDescription": "Security group for mount target",
"SecurityGroupIngress": [
{
"IpProtocol": "tcp",
"FromPort": "2049",
"ToPort": "2049",
"CidrIp": "0.0.0.0/0"
}
]
}
},
"FileSystem": {
"Type": "AWS::EFS::FileSystem",
"Properties": {
"FileSystemTags": [
{
"Key": "Name",
"Value": { "Ref" : "VolumeName" }
}
]
}
},
"MountTarget": {
"Type": "AWS::EFS::MountTarget",
"Properties": {
"FileSystemId": { "Ref": "FileSystem" },
"SubnetId": { "Ref": "Subnet" },
"SecurityGroups": [ { "Ref": "MountTargetSecurityGroup" } ]
}
},
AutoScaling部分のJSON
"LaunchConfiguration": {
"Type": "AWS::AutoScaling::LaunchConfiguration",
"Metadata" : {
"AWS::CloudFormation::Init" : {
"configSets" : {
"MountConfig" : [ "setup", "mount" ]
},
"setup" : {
"packages" : {
"yum" : {
"nfs-utils" : []
}
},
"files" : {
"/home/ec2-user/post_nfsstat" : {
"content" : { "Fn::Join" : [ "", [
"#!/bin/bash\n",
"\n",
"INPUT=\"$(cat)\"\n",
"CW_JSON_OPEN='{ \"Namespace\": \"EFS\", \"MetricData\": [ '\n",
"CW_JSON_CLOSE=' ] }'\n",
"CW_JSON_METRIC=''\n",
"METRIC_COUNTER=0\n",
"\n",
"for COL in 1 2 3 4 5 6; do\n",
"\n",
" COUNTER=0\n",
" METRIC_FIELD=$COL\n",
" DATA_FIELD=$(($COL+($COL-1)))\n",
"\n",
" while read line; do\n",
" if [[ COUNTER -gt 0 ]]; then\n",
"\n",
" LINE=`echo $line | tr -s ' ' `\n",
" AWS_COMMAND=\"aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, "\"\n",
" MOD=$(( $COUNTER % 2))\n",
"\n",
" if [ $MOD -eq 1 ]; then\n",
" METRIC_NAME=`echo $LINE | cut -d ' ' -f $METRIC_FIELD`\n",
" else\n",
" METRIC_VALUE=`echo $LINE | cut -d ' ' -f $DATA_FIELD`\n",
" fi\n",
"\n",
" if [[ -n \"$METRIC_NAME\" && -n \"$METRIC_VALUE\" ]]; then\n",
" INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)\n",
" CW_JSON_METRIC=\"$CW_JSON_METRIC { \\\"MetricName\\\": \\\"$METRIC_NAME\\\", \\\"Dimensions\\\": [{\\\"Name\\\": \\\"InstanceId\\\", \\\"Value\\\": \\\"$INSTANCE_ID\\\"} ], \\\"Value\\\": $METRIC_VALUE },\"\n",
" unset METRIC_NAME\n",
" unset METRIC_VALUE\n",
"\n",
" METRIC_COUNTER=$((METRIC_COUNTER+1))\n",
" if [ $METRIC_COUNTER -eq 20 ]; then\n",
" # 20 is max metric collection size, so we have to submit here\n",
" aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, " --cli-input-json \"`echo $CW_JSON_OPEN ${CW_JSON_METRIC%?} $CW_JSON_CLOSE`\"\n",
"\n",
" # reset\n",
" METRIC_COUNTER=0\n",
" CW_JSON_METRIC=''\n",
" fi\n",
" fi \n",
"\n",
"\n",
"\n",
" COUNTER=$((COUNTER+1))\n",
" fi\n",
"\n",
" if [[ \"$line\" == \"Client nfs v4:\" ]]; then\n",
" # the next line is the good stuff \n",
" COUNTER=$((COUNTER+1))\n",
" fi\n",
" done <<< \"$INPUT\"\n",
"done\n",
"\n",
"# submit whatever is left\n",
"aws cloudwatch put-metric-data --region ", { "Ref": "AWS::Region" }, " --cli-input-json \"`echo $CW_JSON_OPEN ${CW_JSON_METRIC%?} $CW_JSON_CLOSE`\""
] ] },
"mode": "000755",
"owner": "ec2-user",
"group": "ec2-user"
},
"/home/ec2-user/crontab" : {
"content" : { "Fn::Join" : [ "", [
"* * * * * /usr/sbin/nfsstat | /home/ec2-user/post_nfsstat\n"
] ] },
"owner": "ec2-user",
"group": "ec2-user"
}
},
"commands" : {
"01_createdir" : {
"command" : {"Fn::Join" : [ "", [ "mkdir /", { "Ref" : "MountPoint" }]]}
}
}
},
"mount" : {
"commands" : {
"01_mount" : {
"command" : { "Fn::Join": [ "", [
"mount -t nfs4 $(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone).",
{ "Ref": "FileSystem" },
".efs.",
{ "Ref": "AWS::Region" },
".amazonaws.com:/ /",
{"Ref" : "MountPoint" }
] ] }
},
"02_permissions" : {
"command" : {"Fn::Join" : [ "", [ "chown ec2-user:ec2-user /", { "Ref" : "MountPoint" }]]}
}
}
}
}
},
"Properties": {
"AssociatePublicIpAddress" : true,
"ImageId": {
"Fn::FindInMap": [ "AWSRegionArch2AMI", { "Ref": "AWS::Region" }, {
"Fn::FindInMap": [ "AWSInstanceType2Arch", { "Ref": "InstanceType" }, "Arch" ]
} ]
},
"InstanceType": { "Ref": "InstanceType" },
"KeyName": { "Ref": "KeyName" },
"SecurityGroups": [ { "Ref": "InstanceSecurityGroup" } ],
"IamInstanceProfile" : { "Ref" : "CloudWatchPutMetricsInstanceProfile" },
"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 LaunchConfiguration ",
" --configsets MountConfig ",
" --region ", { "Ref" : "AWS::Region" }, "\n",
"crontab /home/ec2-user/crontab\n",
"/opt/aws/bin/cfn-signal -e $? ",
" --stack ", { "Ref" : "AWS::StackName" },
" --resource AutoScalingGroup ",
" --region ", { "Ref" : "AWS::Region" }, "\n"
]]}}
}
},
"AutoScalingGroup": {
"Type": "AWS::AutoScaling::AutoScalingGroup",
"DependsOn": ["MountTarget", "GatewayToInternet"],
"CreationPolicy" : {
"ResourceSignal" : {
"Timeout" : "PT15M",
"Count" : { "Ref": "AsgMaxSize" }
}
},
"Properties": {
"VPCZoneIdentifier": [ { "Ref": "Subnet" } ],
"LaunchConfigurationName": { "Ref": "LaunchConfiguration" },
"MinSize": "1",
"MaxSize": { "Ref": "AsgMaxSize" },
"DesiredCapacity": { "Ref": "AsgMaxSize" },
"Tags": [ {
"Key": "Name",
"Value": "EFS FileSystem Mounted Instance",
"PropagateAtLaunch": "true"
} ]
}
}
```