LoginSignup
4
4

More than 1 year has passed since last update.

CloudFormationでEC2を構築してみた(※サンプルコード記載)

Posted at

はじめに

AWS CloudFormationでEC2を構築しました。
そこで学んだことを、記事にしています。

背景

現在参画している案件のシステムが重く、会社から付与していただいてるPCでは起動できず困っていました。(M1原因の可能性もあると思っています・・・)

そのため、なんとか手元で動かせるようにEC2を構築する必要がありました。
また、案件に参画しているメンバー全員が構築できる必要もあり、コードで管理できるCloudFormationで実装いたしました。

CloudFormationとは?

CloudFormationとは、AWSのリソースをテンプレートで管理できるAWSが提供するサービスです。
テンプレートを作成すれば、そこに記述されているAWSリソースを設定してくれます。

作成手順

事前に、EC2インスタンスに使用するキーペアを作成してください!
既に作成済みや既存のキーペアを使用する場合は、スルーで問題ありません。

まだの方は、以下を確認してください。

1. EC2コンソールを開く
2. ナビゲーションペインで、キーペア を選択する
3. キーペアの作成を選択する
4. 以下を参照に項目の入力をする

  • 名前:任意
  • キーペアのタイプ:RSA
  • プライベートキーファイル形式:.pem

スクリーンショット 2022-09-20 16.49.55.png

5. キーペアを作成を押すと、作成される

作成時にキーがダウンロードされるので、無くさないようにしましょう!

0. 全体のコード

CloudFormationテンプレートはJSONまたはYAML形式のテキストファイルです。
そのため、今回はyamlファイルで作成して以下に記載いたしました。(コードが多少長いため、折りたたみにしています。)

サンプルコード
qiita-sample.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とは、スタックを作成または更新するたびにテンプレートにカスタム値を入力できます。
今回で言うと、KeyNameMyIPというパラメーターで宣言しています。(この名前は自由に設定できます!)

  • 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アドレス

そのため、SecGrpSampleEC2ElaServerという名前で指定しています。(ここも自由に設定できます。)

セキュリティグループ

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つは必ずあります。)

VpcIdの探し方

1. VPCコンソールを開く
2. ナビゲーションペインで、お使いのVPC を選択する
3. 画面上に記載があるvpc-xxx...VPC IDとなる

スクリーンショット 2022-09-20 18.32.00.jpg

  • 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:インスタンスに追加するタグ。
    • KeyNameとすることで、コンソール上に表示する名前を指定することができる。
  • ImageId:AMI の ID。

個人的には、このAMI IDを指定するのに苦労しました・・・。
今回は無料枠でもある、Amazon Linux 2 AMIを指定しました。

AMI IDの探し方(Amazon Linux 2 AMI の場合)

1. EC2コンソールを開く
2. ナビゲーションペインで、インスタンス を選択する
3. インスタンスを起動を選択する
4. アプリケーションおよび OS イメージ (Amazon マシンイメージ)より、表示されているのがAMI IDとなる

スクリーンショット 2022-09-20 19.21.16.jpg

  • 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コンソールを開く。

スクリーンショット 2022-09-20 21.09.28.png

1. 作成

1. スタックの作成から、新しいリソースを使用(標準)
スクリーンショット 2022-09-20 21.12.28.png

2. テンプレートの準備完了から、テンプレートファイルのアップロードから作成したファイルをアップロードして、次へを押す
スクリーンショット 2022-09-20 21.18.58.jpg

3. スタックの名前を任意で記載し、各パラメータを設定して、次へを押す
スクリーンショット 2022-09-20 21.37.23.jpg

パラメータは、作成手順で説明したParametersを記述したことによって、記載することができるようになっています。
デフォルトで設定しておくと、自動で表示されるのでおすすめです。

4. スタックオプションの設定では、特に記載を変更することなく、次へを押す
スクリーンショット 2022-09-20 21.44.30.png

5. 最後に内容を確認して、問題なければスタックの作成を押す。
スクリーンショット 2022-09-20 21.46.18.jpg

6. 無事、全てのリソースが作成できたら完了!

これで、コードの実装から実際のCloudFormationを触ってAWSリソースを作成するところまで、終了いたしました:tada::tada:
お疲れ様でした。

補足

エラーでうまく作成できなかった場合

途中でエラーが出てリソースが作成できない場合も、スタックとして残ってしまうため、一度削除してからもう一度試してください。
ただ削除して、もう一度試しても解決はできないと思うので、エラー内容をよく見て調べましょう!

おわりに

案件でCloudFormationが必要になった時、自分は そもそも、CloudFormationってなんだ? というところからスタートしました。
ただそこからドキュメントなりいろいろ調べていく中で、CloudFormationの概要からセキュリティグループやAMIなど、仕組みの部分がふわっとした知識から、少しは固められたかなと思います。

CloudFormationでAWSリソースを構築する記事はたくさん出てくるので、その中の1つとしてこの記事も皆さんのお役に立てれば嬉しいです。

記事をご覧いただき、ありがとうございました。

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4