はじめに
AWS CloudFormationでEC2を構築しました。
そこで学んだことを、記事にしています。
背景
現在参画している案件のシステムが重く、会社から付与していただいてるPCでは起動できず困っていました。(M1原因の可能性もあると思っています・・・)
そのため、なんとか手元で動かせるようにEC2を構築する必要がありました。
また、案件に参画しているメンバー全員が構築できる必要もあり、コードで管理できるCloudFormationで実装いたしました。
CloudFormationとは?
CloudFormationとは、AWSのリソースをテンプレートで管理できるAWSが提供するサービスです。
テンプレートを作成すれば、そこに記述されているAWSリソースを設定してくれます。
作成手順
事前に、EC2インスタンスに使用するキーペアを作成してください!
既に作成済みや既存のキーペアを使用する場合は、スルーで問題ありません。
まだの方は、以下を確認してください。
1. EC2コンソールを開く
2. ナビゲーションペインで、キーペア を選択する
3. キーペアの作成を選択する
4. 以下を参照に項目の入力をする
- 名前:任意
- キーペアのタイプ:RSA
- プライベートキーファイル形式:.pem
5. キーペアを作成を押すと、作成される
作成時にキーがダウンロードされるので、無くさないようにしましょう!
0. 全体のコード
CloudFormationテンプレートはJSON
またはYAML
形式のテキストファイルです。
そのため、今回はyamlファイル
で作成して以下に記載いたしました。(コードが多少長いため、折りたたみにしています。)
サンプルコード
Parameters:
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instance
Type: "AWS::EC2::KeyPair::KeyName"
Default: xxxxxx # 作成するEC2に紐づくキーを記載する
MyIP:
Description: IP address allowed to access EC2
Type: String
Default: xxxxxx # IPアドレスを記載する
Resources:
SecGrp:
Type: AWS::EC2::SecurityGroup # セキュリティグループを作成するタイプを指定【AWS::EC2::SecurityGroup】
Properties:
GroupName: ec2-sg
GroupDescription: Allow SSH and HTTP access only MyIP
VpcId: vpc-00000000 # 使用するVPCのIDを記載する
SecurityGroupIngress: # インバウンドルールの設定
# ssh
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref MyIP
- IpProtocol: tcp
FromPort: 3000
ToPort: 3000
CidrIp: !Ref MyIP
SampleEC2:
Type: AWS::EC2::Instance # インスタンスを作成するタイプを指定【AWS::EC2::Instance】
Properties:
Tags:
- Key: Name
Value: "sample-ec2" # 表示する名前を記載する
ImageId: ami-00000000000000000 # 使用するAMI IDを記載する
KeyName: !Ref KeyName
InstanceType: t3.xlarge # インスタンスタイプを指定
InstanceInitiatedShutdownBehavior: stop
NetworkInterfaces: # インターフェースの設定
- AssociatePublicIpAddress: "true" # 自動割り当てパブリックIPの設定。trueで有効可。
DeviceIndex: "0" # パブリックIPを自動で割り振り
GroupSet:
- !Ref SecGrp # 上のセキュリティグループを指定
BlockDeviceMappings: # ストレージの設定
- DeviceName: /dev/xvda # デバイス名
Ebs:
VolumeType: gp2 # ボリュームタイプ
DeleteOnTermination: true # インスタンス終了時に削除するのか
VolumeSize: 50 # ディスクサイズ(GiB)
UserData:
Fn::Base64: |
#!/bin/bash
sudo yum update -y
sudo yum install -y git
ElaServer:
Type: AWS::EC2::EIP # Elastic IP アドレスを作成するタイプを指定【AWS::EC2::EIP】
Properties:
InstanceId: !Ref SampleEC2 #【!Ref】で割り当てるインスタンス指定
今回のコードで作成するリソースは以下になります。
- セキュリティグループ
- EC2インスタンス
- ElasticIPアドレス
1. Parameters
Parameters:
KeyName:
Description: The EC2 Key Pair to allow SSH access to the instance
Type: "AWS::EC2::KeyPair::KeyName"
Default: xxxxxx # 作成するEC2に紐づくキーを記載する
MyIP:
Description: IP address allowed to access EC2
Type: String
Default: xxxxxx # IPアドレスを記載する
Parametersとは、スタックを作成または更新するたびにテンプレートにカスタム値を入力できます。
今回で言うと、KeyName
とMyIP
というパラメーターで宣言しています。(この名前は自由に設定できます!)
- KeyName:EC2に紐づくキーペアを設定
- MyIP:IPアドレスを設定
宣言することによって、!Ref MyIP
のように記述を省略することができます。(この後に出てきます。)
各プロパティに関しては、以下にまとめました。
- Description:パラメーターについて説明する最大 4000 文字の文字列。
- Type:パラメーターのデータ型。
- Default:スタックの作成時に値を指定しなかった場合に、テンプレートで使用される適切な型の値。
- デフォルトを設定する場合は、必ず値を記載すること。
IPアドレスなど、コード上で何度も使用するものに関して設定しておくと、記載が省略できるので個人的には大きいメリットかと思います!
2. Resources
Resources:
SecGrp:
Type: AWS::EC2::SecurityGroup # セキュリティグループを作成するタイプを指定【AWS::EC2::SecurityGroup】
Properties:
GroupName: ec2-sg
GroupDescription: Allow SSH and HTTP access only MyIP
VpcId: vpc-00000000 # 使用するVPCのIDを記載する
SecurityGroupIngress:
# ssh
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref MyIP
- IpProtocol: tcp
FromPort: 3000
ToPort: 3000
CidrIp: !Ref MyIP
SampleEC2:
Type: AWS::EC2::Instance # インスタンスを作成するタイプを指定【AWS::EC2::Instance】
Properties:
Tags:
- Key: Name
Value: "sample-ec2" # 表示する名前を記載する
ImageId: ami-00000000000000000 # 使用するAMI IDを記載する
KeyName: !Ref KeyName
InstanceType: t2.micro # インスタンスタイプを指定
InstanceInitiatedShutdownBehavior: stop
NetworkInterfaces: # インターフェースの設定
- AssociatePublicIpAddress: "true" # 自動割り当てパブリックIPの設定。trueで有効可。
DeviceIndex: "0" # パブリックIPを自動で割り振り
GroupSet:
- !Ref SecGrp # 上のセキュリティグループを指定
BlockDeviceMappings: # ストレージの設定
- DeviceName: /dev/xvda # デバイス名
Ebs:
VolumeType: gp2 # ボリュームタイプ
DeleteOnTermination: true # インスタンス終了時に削除するのか
VolumeSize: 50 # ディスクサイズ(GiB)
UserData:
Fn::Base64: |
#!/bin/bash
sudo yum update -y
sudo yum install -y git
ElaServer:
Type: AWS::EC2::EIP # Elastic IP アドレスを作成するタイプを指定【AWS::EC2::EIP】
Properties:
InstanceId: !Ref SampleEC2 #【!Ref】で割り当てるインスタンス指定
Resourcesとは、スタックに含める Amazon EC2 インスタンスや Amazon S3 バケットなどの AWS リソースを宣言します。
今回は先ほども記載しましたが、以下のリソースを作成します。
- セキュリティグループ
- EC2インスタンス
- ElasticIPアドレス
そのため、SecGrp
・SampleEC2
・ElaServer
という名前で指定しています。(ここも自由に設定できます。)
セキュリティグループ
SecGrp:
Type: AWS::EC2::SecurityGroup # セキュリティグループを作成するタイプを指定【AWS::EC2::SecurityGroup】
Properties:
GroupName: ec2-sg
GroupDescription: Allow SSH and HTTP access only MyIP
VpcId: vpc-00000000 # 使用するVPCのIDを記載する
SecurityGroupIngress: # インバウンドルールの設定
# ssh
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: !Ref MyIP
- IpProtocol: tcp
FromPort: 3000
ToPort: 3000
CidrIp: !Ref MyIP
今回のセキュリティグループでは、ポート22と3000で接続できるように設定しています。
ポートに関しては、各自必要な数だけ設定してください。
各プロパティに関しては、以下にまとめました。
- GroupName:セキュリティグループの名前。
- GroupDescription:セキュリティグループの説明。
- VpcId:使用するVPCのID。
今回はVPCを作成していないので、以下3パターンの中から使用してください!
- 新しく作成する
- 既存のVPC
- デフォルトのVPC
個人的には、デフォルトのVPCで十分かと思っています。
(VPCは、各リージョンにデフォルトで1つは必ずあります。)
- SecurityGroupIngress:インバウンドルールの設定。
- IpProtocol:IPプロトコル名(tcp、udp、icmp、icmpv6)または番号。
- FromPort:ポート範囲の開始番号。
- ToPort:ポート範囲の終了番号。
- CidrIp:IPv4 アドレス範囲。
- 今回は、自身が使用しているIPアドレスのみしか通信できないようにしている。
- IPアドレスの調べ方は、こちら。
Ref
ここで先ほどパラメーターで設定したMyIP
を、以下のように!Ref MyIP
とすることで、指定した値を返すことができます。
CidrIp: !Ref MyIP
EC2インスタンス
SampleEC2:
Type: AWS::EC2::Instance # インスタンスを作成するタイプを指定【AWS::EC2::Instance】
Properties:
Tags:
- Key: Name
Value: "sample-ec2" # 表示する名前を記載する
ImageId: ami-00000000000000000 # 使用するAMI IDを記載する
KeyName: !Ref KeyName
InstanceType: t3.xlarge # インスタンスタイプを指定
InstanceInitiatedShutdownBehavior: stop
NetworkInterfaces: # インターフェースの設定
- AssociatePublicIpAddress: "true" # 自動割り当てパブリックIPの設定。trueで有効可。
DeviceIndex: "0" # パブリックIPを自動で割り振り
GroupSet:
- !Ref SecGrp # 上のセキュリティグループを指定
BlockDeviceMappings: # ストレージの設定
- DeviceName: /dev/xvda # デバイス名
Ebs:
VolumeType: gp2 # ボリュームタイプ
DeleteOnTermination: true # インスタンス終了時に削除するのか
VolumeSize: 50 # ディスクサイズ(GiB)
UserData:
Fn::Base64: |
#!/bin/bash
sudo yum update -y
sudo yum install -y git
今回のEC2インスタンスでは、t3.xlargeで、EBSのボリュームを50GiBとかなりサイズを大きくして作成しています。
このままで作成すると有料となってしまうので、インスタンスタイプなど無料枠なのかどうか、しっかり確認しましょう!
各プロパティに関しては、以下にまとめました。
- Tags:インスタンスに追加するタグ。
-
Key
をName
とすることで、コンソール上に表示する名前を指定することができる。
-
- ImageId:AMI の ID。
個人的には、このAMI IDを指定するのに苦労しました・・・。
今回は無料枠でもある、Amazon Linux 2 AMI
を指定しました。
AMI IDの探し方(Amazon Linux 2 AMI の場合)
1. EC2コンソールを開く
2. ナビゲーションペインで、インスタンス を選択する
3. インスタンスを起動を選択する
4. アプリケーションおよび OS イメージ (Amazon マシンイメージ)より、表示されているのがAMI IDとなる
- KeyName:キーペアの名前。
- 今回は
Parameters
で定義しているため、!Ref KeyName
としている。
- 今回は
- InstanceType:インスタンスのタイプ。
- InstanceInitiatedShutdownBehavior:インスタンスからシャットダウンを開始したときに、インスタンスが停止または終了するかどうかを示す。
- NetworkInterfaces:インスタンスに関連付けるネットワーク インターフェイス。
- AssociatePublicIpAddress:インスタンスにパブリック IPv4 アドレスを割り当てるかどうかを示す。
- DeviceIndex:接続順序におけるネットワークインターフェイスの位置。
- GroupSet:セキュリティグループの ID。
- 今回は
SecGrp
という名前で作成済みなので、!Ref SecGrp
で指定している。
- 今回は
- BlockDeviceMappings:起動時にインスタンスに接続するブロックデバイスを定義。
- DeviceName:デバイス名。
- Ebs:インスタンスの起動時に EBSボリュームを自動的にセットアップするために使用されるパラメーター。
- VolumeType:ボリュームタイプ。
- DeleteOnTermination:インスタンスの終了時に EBSボリュームが削除されるかどうかを示す。
- VolumeSize:ボリュームのサイズ (GiB 単位)。
- UserData:インスタンスで使用できるようにするユーザーデータスクリプト。
- インスタンス起動時に、記載のあるコマンドを実行してくれる。
- 複数のコマンドを実行したい場合は、改行して記載する。
ElasticIPアドレス
ElaServer:
Type: AWS::EC2::EIP # Elastic IP アドレスを作成するタイプを指定【AWS::EC2::EIP】
Properties:
InstanceId: !Ref SampleEC2 #【!Ref】で割り当てるインスタンス指定
今回は、先ほど作成したインスタンスにElasticIPアドレスを付与しています。
各プロパティに関しては、以下にまとめました。
- InstanceId:インスタンスのID。
- 今回は
SampleEC2
という名前で作成済みなので、!Ref SampleEC2
で指定している。
- 今回は
AWS上の操作
これでコードは実装できたので、実際にCloudFormationを利用して、AWSリソースを作成していきます。
0. CloudFormationを検索
「CloudFormation」と検索して、CloudFormationコンソールを開く。
1. 作成
2. テンプレートの準備完了から、テンプレートファイルのアップロードから作成したファイルをアップロードして、次へを押す
3. スタックの名前を任意で記載し、各パラメータを設定して、次へを押す
パラメータは、作成手順で説明したParametersを記述したことによって、記載することができるようになっています。
デフォルトで設定しておくと、自動で表示されるのでおすすめです。
4. スタックオプションの設定では、特に記載を変更することなく、次へを押す
5. 最後に内容を確認して、問題なければスタックの作成を押す。
6. 無事、全てのリソースが作成できたら完了!
これで、コードの実装から実際のCloudFormationを触ってAWSリソースを作成するところまで、終了いたしました
お疲れ様でした。
補足
エラーでうまく作成できなかった場合
途中でエラーが出てリソースが作成できない場合も、スタックとして残ってしまうため、一度削除してからもう一度試してください。
ただ削除して、もう一度試しても解決はできないと思うので、エラー内容をよく見て調べましょう!
おわりに
案件でCloudFormationが必要になった時、自分は そもそも、CloudFormationってなんだ? というところからスタートしました。
ただそこからドキュメントなりいろいろ調べていく中で、CloudFormationの概要からセキュリティグループやAMIなど、仕組みの部分がふわっとした知識から、少しは固められたかなと思います。
CloudFormationでAWSリソースを構築する記事はたくさん出てくるので、その中の1つとしてこの記事も皆さんのお役に立てれば嬉しいです。
記事をご覧いただき、ありがとうございました。