この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
AWSチームのすずきです。
2017年のre:InventでリリースされたEC2の起動テンプレート(Launch Templates for Amazon EC2 instances)。 EC2インスタンスの初期設定をテンプレートとして管理、再利用することが可能になりました。
【速報】新機能 Launch Templates for Amazon EC2 instancesが公開されました #reinvent
[新機能]Launch Templates for Amazon EC2 instancesを試してみた #reinvent
2018年3月、起動テンプレートのCloudFormationサポートがアナウンスされていました。
今回、CloudFormationを利用して、起動テンプレートによるEC2インスタンスと、オートスケール環境の設置を試す機会がありましたので、紹介させていただきます。
利点
CloudFormationで起動テンプレートを利用する利点について、まず紹介させていただきます。
設定の簡略化
- VPCサブネット指定のみでEC2インスタンスの起動する事が可能になりました。
- ライセンスなどの関係でオートスケールの導入が難しいが、負荷分散構成をとるEC2インスタンスを多数設置する場合には有効と思われます。
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref 'Ec2InstanceLaunchTemplate'
Version: !GetAtt 'Ec2InstanceLaunchTemplate.LatestVersionNumber'
SubnetId: !Ref 'VpcEc2Subnet1'
バージョン管理
- 起動テンプレートはバージョン管理機構を備えます。
- CloudFormationで作成した起動テンプレートを更新(UpdateStack)すると、起動テンプレートのバージョン番号が一つ繰り上がります。
- 今回、!GetAtt関数を利用し「LatestVersionNumber」を指定、該当起動テンプレートの最新のバージョンを利用する指定としました。
- 切り戻しなどの場合、バージョン指定を行う事で、古い起動テンプレートを利用したEC2環境を構築できます。
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref 'Ec2InstanceLaunchTemplate'
Version: 1
SubnetId: !Ref 'VpcEc2Subnet1'
- CloudFormationで作成した起動テンプレートは、AWSコンソール上で、作成日時、作業者情報、設定内容を確認可能です。
タグ管理
- EC2インスタンス、およびEBSのタグを一括管理する事が可能になりました。
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Env
Value: !Ref 'Env'
- ResourceType: volume
Tags:
- Key: Env
Value: !Ref 'Env'
- EC2起動後に増設したEBSや、AMIからの起動時に「Delete on Termination」(併せて削除)指定を省略して作成したEBSは、EC2の撤去後に取り残され用途不明となる事がありましたが、EBSへの適切なタグ付与を行う事で回避しやすくなります。
- EBSボリュームに適切なタグを付与する事で、コスト配分タグを有効としたAWSアカウントでは、EBSやスナップショット費用についてもタグによるコスト計算が可能になります。
Amazon Elastic Block Store (Amazon EBS) でスナップショットのコスト配分をサポート
T2無制限オプション
- 「T2」ファミリーのCPUクレジット枯渇を回避するオプション指定を起動テンプレートで設定する事が可能です。
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
CreditSpecification:
CpuCredits: unlimited
- 従来のLaunchConfigを利用したオートスケール環境では、T2無制限オプションの有効化のための「Userdata」設定などが必要。awscliのバージョンや、IAMロールの調整が必要でした。
スポットインスタンス
- スポット入札価格の省略が可能になりました。
- スポット価格高騰、強制停止に至る場合の動作として、EBS上のデータ消失を回避する停止やハイバネーションの指定も可能になりました。
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
InstanceMarketOptions:
SpotOptions:
SpotInstanceType: one-time
InstanceInterruptionBehavior: terminate
MarketType: spot
- 従来の起動設定(LaunchConfig)でも、スポット価格明示することでスポットインスタンスの利用は可能でしたが、インスタンスファミリーの変更などがあった場合、高額すぎる入札や、廉価すぎる入札により、意図しない状態が発生する事がありました。
Type: AWS::EC2::LaunchTemplate
Properties:
SpotPrice: 0.1
ストレージ設定
- EBSの増量設定を定義する事が可能です。
-
ルートデバイスとして「sda1」を利用するWindowsの設定例
- Device Naming on Windows Instances
LinuxAMI
- ルートデバイスとして「xvda」を利用する、Linuxの設定例
- Linux インスタンスでのデバイスの名前付け
Type: AWS::EC2::LaunchTemplate
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 8
VolumeType: gp2
DeleteOnTermination: true
- DeviceName: /dev/xvdf
Ebs:
VolumeSize: 1
VolumeType: gp2
DeleteOnTermination: true
WindowsAMI
- ルートデバイスとして「sda1」を利用するWindowsの設定例
- Device Naming on Windows Instances
Type: AWS::EC2::LaunchTemplate
Properties:
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
VolumeSize: 30
VolumeType: gp2
DeleteOnTermination: true
- DeviceName: /dev/xvdf
Ebs:
VolumeSize: 1
VolumeType: gp2
DeleteOnTermination: true
ネットワーク設定
- 今回オートスケール環境での利用を優先したため設定を省略しましたが、NetworkInterface プロパティタイプによるネットワーク設定は可能です。
まとめ
起動テンプレート(Launch Templates)の利用により、 AWSのアップデートで追加された多くのEC2の機能を活用し、より効率的な管理、利用が出来るようになりました。
特に、初期設定のみCloudFormationを利用、 リリース後のEC2インスタンスの更新、管理についてはAWSコンソールやCLIの利用が想定される環境では、 起動テンプレートの利用は大きな効果があると思われます。
また、起動テンプレートはスポットフリートや、AWS Auto Scalingとの連係にも利用することが可能です。 こちらは別の機会に改めて紹介させて頂きたいと思います。
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-fleet-automatic-scaling.html
テンプレート
- 今回紹介した環境のCloudFormationテンプレート(YAML)です。
- オートスケールと非オートスケールで、同一設定の2台のEC2インスタンスが起動します。
- AMIはAWS東京リージョンのAmazon Linux 2 LTS Candidate 2 をデフォルトのパラメータに反映しています
- 既存のVPC(デフォルトVPC)とサブネット、SSH接続情報をパラメータで指定します
- Userdataの動作確認の為、awslogs(CloudwatchLogsAgent)の設定を実施しています
AWSTemplateFormatVersion: '2010-09-09'
Description: ec2-LaunchTemplate-instance
Parameters:
Env:
Description: Choose the environment to create
Type: String
Default: development
AllowedValues:
- development
- staging
- production
VpcId:
Description: VPC ID
Type: AWS::EC2::VPC::Id
VpcSubnetCidr:
Description: VPC subnet CIDR
Type: String
Default: 172.31.0.0/16
StaticIPforSSH:
Description: Static IP for SSH access
Type: String
Default: 127.0.0.1/32
VpcEc2Subnet1:
Description: EC2 subnet 1(AZ-a)
Type: AWS::EC2::Subnet::Id
VpcEc2Subnet2:
Description: EC2 subnet 2(AZ-c)
Type: AWS::EC2::Subnet::Id
Ec2ImageId:
Description: AMI ID
Type: String
Default: ami-2724cf58
Ec2InstanceType:
Description: EC2 InstanceType
Type: String
Default: t2.micro
Ec2InstanceKeyName:
Description: EC2 SSH KEY
Type: AWS::EC2::KeyPair::KeyName
Default: SSHKey
Ec2InstanceTagName:
Description: EC2 Tag Name
Type: String
Default: test-lt-ec2-20180605
Ec2AutoscaleMinSize:
Description: AutoScalingGroup MinSize
Type: String
Default: '1'
Ec2AutoscaleMaxSize:
Description: AutoScalingGroup MaxSize
Type: String
Default: '1'
Ec2AutoscaleDesiredCapacity:
Description: AutoScalingGroup DesiredCapacity
Type: String
Default: '1'
Resources:
Ec2InstanceLaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
SecurityGroupIds:
- !Ref 'Ec2SecurityGroup'
- !Ref 'Ec2SecurityGroupSSH'
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Env
Value: !Ref 'Env'
- ResourceType: volume
Tags:
- Key: Env
Value: !Ref 'Env'
- ResourceType: instance
Tags:
- Key: Name
Value: !Ref 'AWS::StackName'
UserData:
Fn::Base64: |
#!/bin/bash -xe
date > /tmp/run.log
yum update -y
yum install jq awslogs -y
chkconfig awslogs on
service awslogs start
if [ ! -f /swapfile ]; then dd if=/dev/zero of=/swapfile bs=1M count=128; chmod 600 /swapfile; mkswap /swapfile; swapon /swapfile; echo "/swapfile swap swap defaults 0 0" >> /etc/fstab; fi
InstanceInitiatedShutdownBehavior: terminate
IamInstanceProfile:
Arn: !GetAtt 'Ec2IAMProfile.Arn'
KeyName: !Ref 'Ec2InstanceKeyName'
ImageId: !Ref 'Ec2ImageId'
Monitoring:
Enabled: false
CreditSpecification:
CpuCredits: standard
InstanceType: !Ref 'Ec2InstanceType'
InstanceMarketOptions:
SpotOptions:
SpotInstanceType: one-time
InstanceInterruptionBehavior: terminate
MarketType: spot
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 8
VolumeType: gp2
DeleteOnTermination: true
- DeviceName: /dev/xvdf
Ebs:
VolumeSize: 1
VolumeType: gp2
DeleteOnTermination: true
Ec2Instance:
Type: AWS::EC2::Instance
Properties:
LaunchTemplate:
LaunchTemplateId: !Ref 'Ec2InstanceLaunchTemplate'
Version: !GetAtt 'Ec2InstanceLaunchTemplate.LatestVersionNumber'
SubnetId: !Ref 'VpcEc2Subnet1'
Ec2InstanceAutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref 'VpcEc2Subnet1'
- !Ref 'VpcEc2Subnet2'
LaunchTemplate:
LaunchTemplateId: !Ref 'Ec2InstanceLaunchTemplate'
Version: !GetAtt 'Ec2InstanceLaunchTemplate.LatestVersionNumber'
MinSize: !Ref 'Ec2AutoscaleMinSize'
MaxSize: !Ref 'Ec2AutoscaleMaxSize'
DesiredCapacity: !Ref 'Ec2AutoscaleDesiredCapacity'
Ec2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref 'VpcId'
GroupDescription: allow ICMP via same VPC
SecurityGroupIngress:
- IpProtocol: icmp
FromPort: -1
ToPort: -1
CidrIp: !Ref 'VpcSubnetCidr'
Ec2SecurityGroupSSH:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref 'VpcId'
GroupDescription: allow SSH via static IP
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref 'StaticIPforSSH'
Ec2IAMRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM
Path: /
Policies: !Ref 'AWS::NoValue'
RoleName: !Ref 'AWS::NoValue'
Ec2RolePolicies:
Type: AWS::IAM::Policy
Properties:
PolicyName: Ec2RolePolicies
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- s3:List*
Resource:
- '*'
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogStreams
Resource:
- arn:aws:logs:*:*:*
Roles:
- !Ref 'Ec2IAMRole'
Ec2IAMProfile:
Type: AWS::IAM::InstanceProfile
DependsOn: Ec2IAMRole
Properties:
Path: /
Roles:
- !Ref 'Ec2IAMRole'