【実践】VSCodeとCloudFormationで学ぶAWS EC2構築|コードでインフラ管理

AWS Basic
スポンサーリンク
スポンサーリンク

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 RoleEC2の権限管理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_IAM

Windowsの場合:

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-1a

SSH接続の確認

出力された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.pem

Webページが表示されない

原因:User Dataの実行に時間がかかる

確認(SSH接続して):

sudo tail -f /var/log/cloud-init-output.log

Apache のインストールが完了するまで待つ(通常2〜3分)

 

🔟 まとめ

この記事では、VSCodeとCloudFormationを使ったEC2構築の実践的な手順を解説しました。

学んだこと

  • CloudFormationテンプレートの構造:YAML形式でインフラを定義
  • AWS CLIでのスタック管理:作成・更新・削除の一連の流れ
  • セキュリティグループの適切な設定:全公開から自分のIPに制限
  • User Dataでの自動化:Apache httpdの自動インストール

CloudFormationのメリット再確認

  1. 再現性:何度でも同じ環境を作成可能
  2. バージョン管理:Gitで履歴管理
  3. 自動化:CI/CDパイプラインに組み込める
  4. ドキュメント化:コードがそのままドキュメント

次のステップ

  • テンプレートのカスタマイズ:EBSボリューム追加、RDS連携など
  • GitHub管理:テンプレートをGitHubでバージョン管理
  • CI/CD構築:GitHub Actionsで自動デプロイ
  • 複数環境管理:開発・ステージング・本番環境の切り分け

参考リンク:

関連記事:

最終更新: 2026年1月11日

コメント