[AWS]CloudFormationを使いこなして早く帰るTips5選

CloudFromationを使いこなして早く帰るTips5選です。繰り返しの作業はコード化、変数でパラメータ化で、しかもログインせずに作業を高速化できます。そんなTipsをまとめました。コピペで使えるコードも置いてあるので保存必須!?
2019.02.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

コンニチハ、千葉です。

最近CloudFormationで20台くらい、どっかーんとEC2立てて気持ちよくなってる私です。 CloudFormationを利用すると、規模が大きかったり環境(dev/stg/prd)がたくさんあっても、かなり楽できます。そうです、早く帰れます。

ということで、使ったTipsをまとめておきます。今回は、よく構築するであろうEC2にフォーカスします。

Tips

Tips1:環境によってパラメータを変える

パラメータを変数化して、1つのCFnファイルで複数の環境(dev/stg/prd)を扱います。Mappingsを使います。コードの例です。*Mappingsに関連する部分だけ抜粋 CFnスタック作成するときに、prd/stgを選ぶと、Mappingsで定義したパラメータを利用できます。これで、1つのCFnでprd/stgを管理できます。

Mappings:
prd:
PublicSubnet1a: { ID: subnet-xxxxx }
stg:
PublicSubnet1a: { ID: subnet-xxxxx }
Parameters:
Environment:
Description: Type of this environment.
Type: String
Default: prd
AllowedValues:
- prd
- stg
BastionEc2Instance:
・・・省略
- SubnetId: !FindInMap [ !Ref Environment, PublicSubnet1a, ID ]

Tips2:命名規則

リソース名など、最初から命名規則を決めて組み込みましょう。

Parameters:
Environment:
Description: Type of this environment.
Type: String
Default: prd
AllowedValues:
- prd
- stg
Parameters:
SystemName:
Description: Name of this system.
Type: String
Default: chiba-system
・・・省略
Tags:
- Key: Name
Value: !Sub ${SystemName}-${Environment}-web1

Tips3:ユーザーデータを使って初期構築windows編

windowsの初期構築です。ユーザーデータを使って、ホスト名、時刻同期、文字コード、タイムゾーンを設定します。 Mappings!Subをうまく組み合わせて変数を取り込んでます。ちょっと複雑。ただ、ログインしなくていいんですよ、圧倒的です。

Mappings:
prd:
OSSettings:
TimeZone: "Tokyo Standard Time"
BastionEc2Instance:
HostName: chiba-bastion
・・・省略
UserData:
Fn::Base64:
!Sub
- |
# hostname
Rename-Computer -NewName ${HostName} -Force

# TimeZone
Set-TimeZone -id "${TimeZone}"

# time sync
w32tm /config /manualpeerlist:169.254.169.123 /syncfromflags:manual /update

- { HostName: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ], TimeZone: !FindInMap [ !Ref Environment, OSSettings, TimeZone ] }

Tips4:ユーザーデータを使って初期構築Linux編

Linuxバージョンです。ホスト名、時刻同期、文字コード、タイムゾーンを設定します。

Mappings:
prd:
OSSettings:
Locale: ja_JP.utf8
TimeZone: "Asia/Tokyo"
BastionEc2Instance:
HostName: chiba-bastion
・・・省略
UserData:
Fn::Base64:
!Sub
- |
#!/bin/sh -ex

# timezon
timedatectl set-timezone ${TimeZone}

# hostname
hostnamectl set-hostname --static ${HostName}
echo 'preserve_hostname: true' >> /etc/cloud/cloud.cfg

# time sync
yum erase 'ntp*'
yum install chrony
echo '#Add TimeSync' >> /etc/chrony.conf
echo 'server 169.254.169.123 prefer iburst' >> /etc/chrony.conf
systemctl start chrony
systemctl enable chrony

# locale
localectl set-locale LANG=${Locale}

- { HostName: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ], TimeZone: !FindInMap [ !Ref Environment, OSSettings, TimeZone ], Locale: !FindInMap [ !Ref Environment, OSSettings, Locale ] }

Tips5:注意:DeviceNameは気をつける

EC2構築時にDeviceNameを利用しますが、デバイス名を意識して指定する必要があります。指定を誤るとEC2が起動できなかったりします。インスタンスタイプ(仮想化方式の違い)やAMIによって違ったりします。こちらを参考にしたり、実際に手動でEC2を作るときに確認できます。

全部入りコード

これらをまとめたコードを置いておきます!

windows

windows1台構築します。EC2の設定に加え、ホスト名、時刻同期、タイムゾーンを設定します。

AWSTemplateFormatVersion: '2010-09-09'
Description: This CloudFormation template to create EC2 instances.

Mappings:
prd:
PublicSubnet1a: { ID: subnet-xxxxxx }
PublicSubnet1c: { ID: subnet-xxxxxx }
PrivateSubnet1a: { ID: subnet-xxxxxx }
PrivateSubnet1c: { ID: subnet-xxxxxx }
OSSettings:
TimeZone: "Tokyo Standard Time"
BastionEc2Instance:
HostName: xxxx_ec2
InstanceType: t3.small
AmiId: ami-0a2de1c3b415889d2
RootVolumeSize: 30
PrivateIpAddress: xx.xx.xx.xx
SecurityGroupId: sg-xxxxxxx

Parameters:
Environment:
Description: Type of this environment.
Type: String
Default: prd
AllowedValues:
- prd
- stg
SystemName:
Description: Name of this system.
Type: String
Default: chiba-web
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable access to instances.

Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Environment Configuration
Parameters:
- SystemName
- Environment
- Label:
default: EC2 Instance Keypair Name
Parameters:
- KeyName

Resources:
BastionEc2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !FindInMap [ !Ref Environment, BastionEc2Instance, InstanceType ]
ImageId: !FindInMap [ !Ref Environment, BastionEc2Instance, AmiId ]
KeyName: !Ref KeyName
BlockDeviceMappings:
- DeviceName: /dev/sda1
Ebs:
VolumeType: gp2
VolumeSize: !FindInMap [ !Ref Environment, BastionEc2Instance, RootVolumeSize ]
DeleteOnTermination: true
NetworkInterfaces:
- SubnetId: !FindInMap [ !Ref Environment, PublicSubnet1a, ID ]
PrivateIpAddress: !FindInMap [ !Ref Environment, BastionEc2Instance, PrivateIpAddress ]
AssociatePublicIpAddress: false
GroupSet:
- !FindInMap [ !Ref Environment, BastionEc2Instance, SecurityGroupId ]
DeviceIndex: 0
DeleteOnTermination: true
DisableApiTermination: true
UserData:
Fn::Base64:
!Sub
- |
# hostname
Rename-Computer -NewName ${HostName} -Force

# TimeZone
Set-TimeZone -id "${TimeZone}"

# time sync
w32tm /config /manualpeerlist:169.254.169.123 /syncfromflags:manual /update

- { HostName: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ], TimeZone: !FindInMap [ !Ref Environment, OSSettings, TimeZone ] }

Tags:
- Key: Name
Value: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ]

Linux

Linux1台構築します。EC2の設定に加え、ホスト名、時刻同期、タイムゾーンを設定します。

AWSTemplateFormatVersion: '2010-09-09'
Description: This CloudFormation template to create EC2 instances.

Mappings:
prd:
PublicSubnet1a: { ID: subnet-xxxxxx }
PublicSubnet1c: { ID: subnet-xxxxxx }
PrivateSubnet1a: { ID: subnet-xxxxxx }
PrivateSubnet1c: { ID: subnet-xxxxxx }
OSSettings:
Locale: ja_JP.utf8
TimeZone: "Asia/Tokyo"
BastionEc2Instance:
HostName: xxxx_ec2
InstanceType: t3.small
AmiId: ami-0a2de1c3b415889d2
RootVolumeSize: 50
PrivateIpAddress: xx.xx.xx.xx
SecurityGroupId: sg-xxxxxxx

Parameters:
Environment:
Description: Type of this environment.
Type: String
Default: prd
AllowedValues:
- prd
- stg
SystemName:
Description: Name of this system.
Type: String
Default: chiba-web
KeyName:
Type: AWS::EC2::KeyPair::KeyName
Description: Name of an existing EC2 KeyPair to enable access to instances.

Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Environment Configuration
Parameters:
- SystemName
- Environment
- Label:
default: EC2 Instance Keypair Name
Parameters:
- KeyName

Resources:
# Bastion instance
BastionEc2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: !FindInMap [ !Ref Environment, BastionEc2Instance, InstanceType ]
ImageId: !FindInMap [ !Ref Environment, BastionEc2Instance, AmiId ]
KeyName: !Ref KeyName
CreditSpecification:
CPUCredits: standard
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
VolumeSize: !FindInMap [ !Ref Environment, BastionEc2Instance, RootVolumeSize ]
DeleteOnTermination: true
NetworkInterfaces:
- SubnetId: !FindInMap [ !Ref Environment, PublicSubnet1a, ID ]
PrivateIpAddress: !FindInMap [ !Ref Environment, BastionEc2Instance, PrivateIpAddress ]
AssociatePublicIpAddress: false
GroupSet:
- !FindInMap [ !Ref Environment, BastionEc2Instance, SecurityGroupId ]
DeviceIndex: 0
DeleteOnTermination: true
DisableApiTermination: true
UserData:
Fn::Base64:
!Sub
- |
#!/bin/sh -ex

# timezon
timedatectl set-timezone ${TimeZone}

# hostname
hostnamectl set-hostname --static ${HostName}
echo 'preserve_hostname: true' >> /etc/cloud/cloud.cfg

# time sync
yum erase 'ntp*'
yum install chrony
echo '#Add TimeSync' >> /etc/chrony.conf
echo 'server 169.254.169.123 prefer iburst' >> /etc/chrony.conf
systemctl start chrony
systemctl enable chrony

# locale
localectl set-locale LANG=${Locale}

- { HostName: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ], TimeZone: !FindInMap [ !Ref Environment, OSSettings, TimeZone ], Locale: !FindInMap [ !Ref Environment, OSSettings, Locale ] }
Tags:
- Key: Name
Value: !FindInMap [ !Ref Environment, BastionEc2Instance, HostName ]

まとめ

仕事はサクッと終わらせて早く帰りたい派のみなさま。早く帰って家族と過ごしたり、自分のスキル磨いたり、ゲームしたり、温泉入ったりライフワークバランスを大切にしたいものです。