1️⃣ はじめに:なぜCloudFormationを使うのか?
AWSマネジメントコンソールでのEC2構築は直感的ですが、再現性と管理性に課題があります。
手動構築の課題
- ❌ 同じ構成を再現するのが難しい
- ❌ 設定ミスが発生しやすい
- ❌ 変更履歴が残らない
- ❌ チーム共有が困難
CloudFormationのメリット
- ✅ インフラをコード化(IaC: Infrastructure as Code)
- ✅ バージョン管理が可能(Gitで管理)
- ✅ 再現性が高い(同じ環境を何度でも作成可能)
- ✅ 自動化しやすい
この記事で学べること
- VSCodeとAWS CLIを使ったローカル開発環境での構築
- CloudFormationテンプレートの作成と理解
- スタックの作成・更新・削除の実践手順
- セキュリティグループの適切な設定
対象読者
- AWS初心者でIaCに興味がある方
- EC2をコードで管理したい方
- VSCodeを使った開発に慣れている方
前提条件
- ✅ AWS CLIがインストール済み
- ✅ AWS CLIの初期設定完了(
aws configure) - ✅ VSCodeがインストール済み
- ✅ EC2キーペアを作成済み
キーペアの作成方法はこちらの記事を参照してください。
2️⃣ 構築する環境の全体像
アーキテクチャ図
┌──────────────────────────────┐
│ ローカル環境(VSCode) │
│ │
│ ┌──────────────────────────┐ │
│ │ template.yaml │ │
│ │ (CloudFormation) │ │
│ └──────────────────────────┘ │
│ │ │
│ │ AWS CLI │
│ ↓ │
└──────────────────────────────┘
│
│ スタック作成
↓
┌──────────────────────────────┐
│ AWS環境 │
│ │
│ ┌──────────────────────────┐ │
│ │ IAM Role │ │
│ │ EC2 Instance Profile │ │
│ │ Security Group │ │
│ │ EC2 Instance │ │
│ │ (Amazon Linux 2023) │ │
│ │ + Apache httpd │ │
│ └──────────────────────────┘ │
└──────────────────────────────┘構築されるリソース
| リソース | 用途 | 詳細 |
|---|---|---|
| IAM Role | EC2の権限管理 | SSM接続用の権限を付与 |
| Instance Profile | ロールのアタッチ | IAMロールとEC2の橋渡し |
| Security Group | ファイアウォール | SSH(22)とHTTP(80)を許可 |
| EC2 Instance | 仮想サーバー | t2.micro(無料枠対象) |
| User Data | 初期設定 | Apache自動インストール |
実現する機能
- Webサーバー:Apache httpdが自動起動
- サンプルページ:「Hello from Amazon Linux 2023!」を表示
- SSH接続:キーペアを使った安全な接続
- SSM接続:Session Managerでブラウザから接続可能
3️⃣ ローカル環境の準備
作業フォルダの作成
VSCodeのターミナルを開く:
# Windowsの場合
mkdir C:\my-aws\aws-learning-projects\ec2-cloudformation
cd C:\my-aws\aws-learning-projects\ec2-cloudformation
# Mac/Linuxの場合
mkdir -p ~/my-aws/aws-learning-projects/ec2-cloudformation
cd ~/my-aws/aws-learning-projects/ec2-cloudformationキーペアファイルの配置
作成済みのキーペアファイル(.pem)を作業フォルダにコピー:
# Windowsの場合(例)
copy %USERPROFILE%\.ssh\my-ec2-test-key.pem .
# Mac/Linuxの場合(例)
cp ~/.ssh/my-ec2-test-key.pem .
chmod 400 my-ec2-test-key.pemフォルダ構成:
ec2-cloudformation/
├── my-ec2-test-key.pem # キーペアファイル
└── template.yaml # これから作成
4️⃣ CloudFormationテンプレートの作成
テンプレートファイルを作成
VSCodeでファイルを開く:
code ./template.yaml完全なテンプレートコード
以下のYAMLコードをコピーして template.yaml に貼り付けてください:
AWSTemplateFormatVersion: '2010-09-09'
Description: 'EC2 Instance with Amazon Linux 2023'
Parameters:
KeyName:
Type: String
Default: my-ec2-test-key
Description: Name of an existing EC2 KeyPair
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64
Description: Latest Amazon Linux 2023 AMI ID from SSM Parameter Store
Resources:
EC2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: 'sts:AssumeRole'
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
Tags:
- Key: Name
Value: ec2-test-01-role
- Key: CmBillingGroup
Value: test
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Roles:
- !Ref EC2Role
EC2SecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: ec2-test-01-sg
GroupDescription: Security group for EC2 test instance
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0
Description: Allow SSH from anywhere (Change to your IP later)
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
Description: Allow HTTP from anywhere (Change to your IP later)
Tags:
- Key: Name
Value: ec2-test-01-sg
- Key: CmBillingGroup
Value: test
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAmiId
InstanceType: t2.micro
KeyName: !Ref KeyName
SecurityGroupIds:
- !Ref EC2SecurityGroup
IamInstanceProfile: !Ref EC2InstanceProfile
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Amazon Linux 2023!</h1>" > /var/www/html/index.html
echo "<p>Instance ID: $(ec2-metadata --instance-id | cut -d ' ' -f 2)</p>" >> /var/www/html/index.html
echo "<p>Availability Zone: $(ec2-metadata --availability-zone | cut -d ' ' -f 2)</p>" >> /var/www/html/index.html
Tags:
- Key: Name
Value: ec2-test-01-instance-al2023
- Key: CmBillingGroup
Value: test
Outputs:
InstanceId:
Description: EC2 Instance ID
Value: !Ref EC2Instance
PublicIP:
Description: Public IP Address
Value: !GetAtt EC2Instance.PublicIp
PublicDNS:
Description: Public DNS Name
Value: !GetAtt EC2Instance.PublicDnsName
WebsiteURL:
Description: Website URL
Value: !Sub 'http://${EC2Instance.PublicDnsName}'
SSHCommand:
Description: SSH Connection Command
Value: !Sub 'ssh -i my-ec2-test-key.pem ec2-user@${EC2Instance.PublicIp}'
AmiId:
Description: AMI ID used for this instance
Value: !Ref LatestAmiId保存: Ctrl + S
テンプレートの構造解説
Parameters(パラメータ)
KeyName:
KeyName:
Type: String
Default: my-ec2-test-key- SSH接続用のキーペア名
- 既存のキーペアを指定
LatestAmiId:
LatestAmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64- 自動取得:SSM Parameter Storeから最新のAmazon Linux 2023 AMI IDを取得
- メリット:AMI IDを手動で調べる必要がない
Resources(リソース)
1. EC2Role(IAMロール)
EC2Role:
Type: AWS::IAM::Role
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore- 役割:EC2インスタンスに権限を付与
- 権限:Session Manager接続を可能にする
2. EC2SecurityGroup(セキュリティグループ)
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
CidrIp: 0.0.0.0/0 # 初期設定:全公開- SSH(ポート22):SSH接続を許可
- HTTP(ポート80):Webアクセスを許可
- 注意:
0.0.0.0/0は全公開設定。構築後に自分のIPに制限することを強く推奨
3. EC2Instance(メインのインスタンス)
EC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref LatestAmiId
InstanceType: t2.micro
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd- AMI:Amazon Linux 2023(最新版を自動取得)
- インスタンスタイプ:t2.micro(無料枠対象)
- UserData:Apache httpdを自動インストール・起動
Outputs(出力)
Outputs:
PublicIP:
Value: !GetAtt EC2Instance.PublicIp
WebsiteURL:
Value: !Sub 'http://${EC2Instance.PublicDnsName}'- スタック作成後に表示される情報
- SSH接続コマンドやWebサイトURLなど
5️⃣ CloudFormationスタックの作成
スタック作成コマンド
VSCodeのターミナルで実行:
aws cloudformation create-stack \
--stack-name ec2-test-stack \
--template-body file://template.yaml \
--region ap-northeast-1 \
--capabilities CAPABILITY_IAMWindowsの場合:
aws cloudformation create-stack ^
--stack-name ec2-test-stack ^
--template-body file://template.yaml ^
--region ap-northeast-1 ^
--capabilities CAPABILITY_IAMコマンドの説明:
--stack-name ec2-test-stack:スタック名(任意の名前)--template-body file://template.yaml:テンプレートファイルを指定--region ap-northeast-1:東京リージョン--capabilities CAPABILITY_IAM:IAMリソース作成の明示的な許可
出力例:
{
"StackId": "arn:aws:cloudformation:ap-northeast-1:123456789012:stack/ec2-test-stack/xxxxx"
}スタック作成の進行状況を確認
進行状況をリアルタイムで確認:
aws cloudformation describe-stacks \
--stack-name ec2-test-stack \
--query "Stacks[0].StackStatus" \
--output textステータスの種類:
CREATE_IN_PROGRESS:作成中CREATE_COMPLETE:作成完了CREATE_FAILED:作成失敗
完了まで約3〜5分かかります。
スタック作成完了の確認
Outputs(出力情報)を取得:
aws cloudformation describe-stacks \
--stack-name ec2-test-stack \
--query "Stacks[0].Outputs" \
--output table出力例:
---------------------------------------------------------------------------------------
| DescribeStacks |
+----------------------+---------------------------------------------------------------+
| Description | OutputValue |
+----------------------+---------------------------------------------------------------+
| EC2 Instance ID | i-0123456789abcdef0 |
| Public IP Address | x.x.x.x |
| Public DNS Name | ec2-x-x-x-x.ap-northeast-1.compute.amazonaws.com |
| Website URL | http://ec2-x-x-x-x.ap-northeast-1.compute.amazonaws.com |
| SSH Connection | ssh -i my-ec2-test-key.pem ec2-user@x.x.x.x |
| AMI ID | ami-0abcdef1234567890 |
+----------------------+---------------------------------------------------------------+
6️⃣ EC2インスタンスの動作確認
Webサーバーへのアクセス
ブラウザでアクセス:
http://x.x.x.x(出力された PublicIP または WebsiteURL を使用)
表示される内容:
Hello from Amazon Linux 2023!
Instance ID: i-0123456789abcdef0
Availability Zone: ap-northeast-1aSSH接続の確認
出力されたSSHコマンドを実行:
ssh -i my-ec2-test-key.pem ec2-user@x.x.x.x初回接続時の確認:
The authenticity of host 'x.x.x.x' can't be established.
Are you sure you want to continue connecting (yes/no)?→ yes を入力
接続成功:
, #_
~\_ ####_ Amazon Linux 2023
~~ \_#####\
~~ \###|
~~ \#/ ___ https://aws.amazon.com/linux/amazon-linux-2023
~~ V~' '->
~~~ /
~~._. _/
_/ _/
_/m/'
[ec2-user@ip-172-31-xx-xx ~]$Apache確認:
sudo systemctl status httpd切断:
exit
7️⃣ セキュリティグループの設定変更
初期設定では 0.0.0.0/0(全公開)になっているため、自分のIPアドレスのみに制限します。
自分のIPアドレスを確認
方法1:ブラウザで確認
方法2:コマンドで確認
curl https://checkip.amazonaws.com/出力例:
y.y.y.yセキュリティグループIDを取得
aws cloudformation describe-stacks \
--stack-name ec2-test-stack \
--query "Stacks[0].Resources[?ResourceType=='AWS::EC2::SecurityGroup'].PhysicalResourceId" \
--output text出力例:
sg-0123456789abcdef0インバウンドルールを更新
既存のルールを削除:
# セキュリティグループIDを変数に設定
SG_ID=sg-0123456789abcdef0
# SSH(ポート22)の既存ルールを削除
aws ec2 revoke-security-group-ingress \
--group-id $SG_ID \
--ip-permissions IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges='[{CidrIp=0.0.0.0/0}]'
# HTTP(ポート80)の既存ルールを削除
aws ec2 revoke-security-group-ingress \
--group-id $SG_ID \
--ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges='[{CidrIp=0.0.0.0/0}]'自分のIPで新しいルールを追加:
# 自分のIPアドレス(例)
MY_IP=y.y.y.y/32
# SSH(ポート22)を自分のIPのみ許可
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--ip-permissions IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges="[{CidrIp=$MY_IP,Description='My IP only'}]"
# HTTP(ポート80)を自分のIPのみ許可
aws ec2 authorize-security-group-ingress \
--group-id $SG_ID \
--ip-permissions IpProtocol=tcp,FromPort=80,ToPort=80,IpRanges="[{CidrIp=$MY_IP,Description='My IP only'}]"確認:
aws ec2 describe-security-groups --group-ids $SG_ID
8️⃣ スタックの削除(リソースのクリーンアップ)
インスタンスを停止
停止コマンド:
# インスタンスIDを取得
INSTANCE_ID=$(aws cloudformation describe-stacks \
--stack-name ec2-test-stack \
--query "Stacks[0].Outputs[?OutputKey=='InstanceId'].OutputValue" \
--output text)
# インスタンスを停止
aws ec2 stop-instances --instance-ids $INSTANCE_ID確認:
aws ec2 describe-instances \
--instance-ids $INSTANCE_ID \
--query "Reservations[0].Instances[0].State.Name" \
--output textスタックを削除
削除コマンド:
aws cloudformation delete-stack --stack-name ec2-test-stack削除の進行状況を確認:
aws cloudformation describe-stacks \
--stack-name ec2-test-stack \
--query "Stacks[0].StackStatus" \
--output text完全に削除されるまで約5分かかります。
削除完了の確認(エラーが表示されればOK):
aws cloudformation describe-stacks --stack-name ec2-test-stackエラー例:
An error occurred (ValidationError) when calling the DescribeStacks operation:
Stack with id ec2-test-stack does not exist
9️⃣ トラブルシューティング
スタック作成が失敗する
原因1:キーペアが存在しない
確認:
aws ec2 describe-key-pairs --key-names my-ec2-test-key解決:
キーペアを作成するか、テンプレートの KeyName を修正
原因2:IAM権限不足
エラー例:
User is not authorized to perform: iam:CreateRole解決:
IAM権限を持つユーザーで実行するか、管理者に依頼
SSH接続ができない
原因1:セキュリティグループの設定
確認:
aws ec2 describe-security-groups --group-ids $SG_ID自分のIPアドレスが許可されているか確認
原因2:キーペアファイルの権限
エラー例:
WARNING: UNPROTECTED PRIVATE KEY FILE!解決:
chmod 400 my-ec2-test-key.pemWebページが表示されない
原因:User Dataの実行に時間がかかる
確認(SSH接続して):
sudo tail -f /var/log/cloud-init-output.logApache のインストールが完了するまで待つ(通常2〜3分)
🔟 まとめ
この記事では、VSCodeとCloudFormationを使ったEC2構築の実践的な手順を解説しました。
学んだこと
- ✅ CloudFormationテンプレートの構造:YAML形式でインフラを定義
- ✅ AWS CLIでのスタック管理:作成・更新・削除の一連の流れ
- ✅ セキュリティグループの適切な設定:全公開から自分のIPに制限
- ✅ User Dataでの自動化:Apache httpdの自動インストール
CloudFormationのメリット再確認
- 再現性:何度でも同じ環境を作成可能
- バージョン管理:Gitで履歴管理
- 自動化:CI/CDパイプラインに組み込める
- ドキュメント化:コードがそのままドキュメント
次のステップ
- テンプレートのカスタマイズ:EBSボリューム追加、RDS連携など
- GitHub管理:テンプレートをGitHubでバージョン管理
- CI/CD構築:GitHub Actionsで自動デプロイ
- 複数環境管理:開発・ステージング・本番環境の切り分け
参考リンク:
関連記事:
最終更新: 2026年1月11日
コメント