1. ホーム
  2. 記事一覧
  3. 【Part 4/4】AWSの環境構築で学ぶトラブルシューティング【Cloud Formation】

2023.11.21

【Part 4/4】AWSの環境構築で学ぶトラブルシューティング【Cloud Formation】

本記事で学べること

本記事は「AWSの環境構築で学ぶトラブルシューティング」シリーズの最終回となっています。

本シリーズは、実際に手を動かしながらWSの環境構築とその過程でトラブルが起こった場合の対処方法や問題の特定方法などを体系的に学べる内容になっています。また、トラブルシューティングのセクションでは、遭遇した問題の問題の特定方法や解決方法について解説します。

今回は、Part 1で手動で構築した内容をCloud Formationを使用して自動で構築できるようにします。自動で構築することは人の操作によるミスがないことや、誰でも構築を行えるようにできるため、作業効率や労働生産性を向上させることができます。

「AWSの環境構築で学ぶトラブルシューティング」シリーズはこちら

https://envader.plus/article/259

https://envader.plus/article/260

https://envader.plus/article/262

環境構築のゴール

本記事における、環境構築のゴールを以下の図にまとめました。Cloud Formationで環境構築し、VPC内のパブリックサブネットに配置したインスタンスにSSH接続することがゴールです。

今までの記事の片付け

Cloud Formationで環境を構築する際に、既存の環境が存在すると環境の作成が行えませんので、Part1~3で使用した環境を削除します。

既に環境を削除している場合はこちらのセクションは飛ばして構いません。

  1. インスタンスの削除

    作成した全てのインスタンスを選択し、インスタンスの状態 → 「インスタンスの終了」を選択し、削除します。

  2. VPCの削除

    作成した全てのVPCを選択し、アクション → 「VPCを削除」を選択し、削除します。

VPCを削除すると、VPCに紐付いたコンポーネント(セキュリティグループ、サブネット、インターネットゲートウェイなど)も削除されます。

前提知識の解説

Cloud FormationはYAMLと呼ばれるファイル(テンプレート)に構築内容を記載し、そのファイルを基に環境を構築します。まず、YAMLについて解説します。

YAMLとは

YAMLは、”YAML Ain’t Markup Language”の再帰的な呼称で「ヤムル」と発音されることが多いです。YAMLは主に設定ファイルやデータのシリアライズ(複数の並列データを直列化して送信すること)に使用され、その構文は人間が読みやすいことを目的としています。

  • YAML Ain’t Markup Language

    ”YAML Ain’t Markup Language”というフレーズは、YAMLはマークアップ言語ではなく、データを表現するための言語であることを示しています。

  • 再帰的な呼称

    再帰的な呼称とは、呼称自体がその略称を説明するために使われている単語を含んでいることを意味します。YAMLの場合、”YAML Ain’t Markup Language”のYAMLが、その定義の一部として再び使用されています。

  • YAMLの特徴

    YAMLはデータを階層的に表現するのに適しており、インデントを使用してデータの構造を表現します。

    YAMLファイルでインデントが揃っていない場合、正しく読み込まれず、エラーになります。そのためYAMLファイルを記述する際には、インデントを正確に行うことが重要です。

  • YAMLファイルの記述例

    YAMLファイルの記述例は以下になります。

    # これはコメントです
    person:
      name: John Doe
      age: 30
      married: true
      children:
        - name: Jane Doe
          age: 10
        - name: Doe Junior
          age: 7

    この例ではpersonというオブジェクトがどんな情報であるかを表現しています。personの名前、年齢、婚姻に関する情報(フィールド)や、childrenという配列があり、それぞれの子供についての情報が含まれています。

    コメントアウトは#で表現できます。複数行に渡るコメントアウトはできません。

テンプレートファイル

Cloud Formationで環境構築の基となるYAMLファイルはテンプレートファイルと呼びます。ローカルのどこでも良いので、YAMLファイルを作成します。今回ファイル名はnetworking-cf.yamlとして作成します。

以後、項目ごとにテンプレートファイルに記述する内容を記載していきますが、最後に全文載せますのでご安心ください。

記述する際にはインデントに注意する必要があります。YAMLのリンターを設定したVSCodeなどのエディター上で記述するのをおすすめします。

また、設定に関する説明は適宜コメントを挿入しますので参考にしてください。

1-1. フォーマットバージョンの指定

冒頭ではテンプレートのフォーマットバージョンを指定します。テンプレートファイルの説明の有無は任意です。

以後、Resources配下に作りたいリソースやテンプレートファイル内で一意の名前などを設定していきます。

# 2010-09-09: 2023年11月現在の時点で最新のバージョン
AWSTemplateFormatVersion: 2010-09-09
# このテンプレートファイルがどんなものであるかを記述する
Description: template file for cloud formation

# リソースの定義
Resources:

1-2. VPCの作成

VPCを作成します。

	# VPCの作成
  NetworkingVPC:
    Type: AWS::EC2::VPC
    Properties:
      # CIDRブロックの指定
      CidrBlock: 10.0.0.0/16
      # DNSサポートの有効化
      EnableDnsSupport: true
      # DNSホスト名の有効化
      EnableDnsHostnames: true
      # 一意になるように名前をつける
      Tags:
        - Key: Name
          Value: networking-vpc

1-3. サブネットの作成

定義したVPC内にサブネットを作成します。今までの演習ではパブリックサブネット、プライベートサブネットを3つずつ作成しましたが、今回は各サブネットは1つずつ作成します。

以下に!RefGetAZsが出てきますが、これらはCloud Formationの組み込み関数です。!RefGetAZsに関して以下の表にまとめました。

関数説明
!Refテンプレート内で定義されたリソースやパラメータを参照する。!Ref MySecurityGroup は、テンプレート内で定義された MySecurityGroup という名前のリソースを参照する。
GetAZs指定されたリージョンの利用可能なアベイラビリティゾーンのリストを返す。!GetAZs '' は、スタックがデプロイされているリージョンの全アベイラビリティゾーンを返す。

アベイラビリティーゾーンをハードコーディングするとリンターで弾かれるケースがあるのでGetAZs関数を使用して定義します。

	# パブリックサブネットの作成
  NetworkingPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      # VPCのIDを指定
      VpcId: !Ref NetworkingVPC
      # CIDRブロックの指定
      CidrBlock: 10.0.1.0/24
      # パブリックサブネットの場合はtrueにし、インターネットゲートウェイをアタッチする
      MapPublicIpOnLaunch: true
      # ハードコードを避けるために、!GetAZs ""を使用
      # 現在のリージョンのAvailability Zoneのリストの最初のAvailability Zoneを選択
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: networking-public-subnet

  # プライベートサブネットの作成
  NetworkingPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref NetworkingVPC
      CidrBlock: 10.0.4.0/24
      # プライベートサブネットの場合はfalseにし、インターネットゲートウェイをアタッチしない
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: networking-private-subnet

1-4. インターネットゲートウェイ

パブリックサブネットに配置するインスタンスはインターネット接続できる必要があるので、インターネットゲートウェイを作成し、VPCにアタッチします。

	# インターネットゲートウェイの作成
  NetworkingInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: networking-igw

  # VPCにインターネットゲートウェイをアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref NetworkingVPC
      InternetGatewayId: !Ref NetworkingInternetGateway

1-5. ルートテーブル

パブリックサブネット、プライベートサブネット用のルートテーブルを作成し、作成したルートテーブルとサブネットを関連付け(紐付け)ます。

インスタンスにパブリックIPを自動で割り当てる場合はDeviceIndex0に設定します。DeviceIndex0というのは、インスタンスインスタンスにアタッチされる最初のネットワークインターフェースであることを意味します。

	# パブリックルートテーブルの作成
  NetworkingPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref NetworkingVPC
      Tags:
        - Key: Name
          Value: networking-public-route-table

  # プライベートルートテーブルの作成
  NetworkingPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref NetworkingVPC
      Tags:
        - Key: Name
          Value: networking-private-route-table

  # パブリックルートテーブルをパブリックサブネットに関連付け
  NetworkingPublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref NetworkingPublicSubnet
      RouteTableId: !Ref NetworkingPublicRouteTable

  # プライベートルートテーブルをプライベートサブネットに関連付け
  NetworkingPrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref NetworkingPrivateSubnet
      RouteTableId: !Ref NetworkingPrivateRouteTable

1-6. セキュリティグループ

インバウンドルールでは単一ポートを解放するので、ToPortFromPortは同じポートを指定します。

アウトバウンドルールは全てのトラフィックの通信を許可します。

※学習目的のため、全てのトラフィックを受け入れる設定を行ていることをご留意ください。

	# セキュリティグループ
  # SSHとHTTPのアクセスを許可
  NetworkingSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH and HTTP access
      VpcId: !Ref NetworkingVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0

1-7. インスタンス

インスタンスはUbuntu Server 22.04 LTSで作成します。

キーペアは事前に作成しておく必要があります。既存のキーペアを使用するか、新たに作成し、そのキーペアの名前を指定します。

	# インスタンスの作成
  NetworkingEC2Public:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-09a81b370b76de6a2
      InstanceType: t2.micro
      KeyName: networking-key
      NetworkInterfaces:
        # パブリックサブネットに関連付け
        # パブリックサブネットに関連付ける場合は、AssociatePublicIpAddressをtrueにする(パブリックIPの自動割り当て)
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref NetworkingSG
          SubnetId: !Ref NetworkingPublicSubnet
      Tags:
        - Key: Name
          Value: networking-ec2-public

Cloud Formationで環境構築

ここまで作成したテンプレートファイルを基に環境を構築します。Cloud Formationでは、1つのテンプレートファイルで作成できるリソース全体を1つのユニット(集まり)として管理し、それをスタックと呼びます。

スタックの作成

マネージメントコンソールからCloud Formationのページへいき、スタックの作成を選択します。(新しいスタックの作成(標準))

最低限設定する項目を以下にまとめました。

設定項目選択項目
テンプレートの準備テンプレートの準備
テンプレートの指定テンプレートファイルのアップロード
スタック名networking-1-stack

作成された環境の確認

スタックの状態がCREATE_IN_PROGRESSからCREATE_COMPLETEになったらスタックの作成が完了しています。各環境が問題なくされたか確認してください。

インスタンスにSSH接続する

作成されたインスタンスにSSH接続します。インスタンスの接続タブからSSH接続するためのコマンドをコピーし、実行します。(

# 接続場所に`networking-key.pem`があることを確認
$ ls
networking-key.pem ...

$ ssh -i "networking-key.pem" ubuntu@ec2-3-112-198-111.ap-northeast-1.compute.amazonaws.com

しばらく待っても接続できません。

トラブルシューティング

インスタンスにSSH接続できない問題がどこにあるのか確認します。考えられる原因としては以下の2点です。

  1. セキュリティグループでSSH接続を許可していない
  2. ルーティングの問題

1. セキュリティグループの確認

networking-1-ec2-publicのセキュリティタブから、セキュリティグループの設定を確認します。

SSHでは全てのトラフィックを許可しており、設定に問題はありません。

2. ルーティングの確認

SSHで接続を確立するためには、接続元と接続先の相互でパケットのやり取りができる必要があります。

networking-1-ec2-publicのネットワーキングタブから、サブネットのページへいき、サブネットのルートテーブルを確認します。

上記では、10.0.0.0/16というルーティングが存在します。これはnetworking-1-vpc内のリソース(インスタンスやデータベースなど)が互いに通信する際のルーティング定義です。

外部のネットワーク(インターネットやSSH)との通信が必要な場合は、インターネットゲートウェイやNATゲートウェイなどの追加のルーティング設定が必要になります。

インターネットゲートウェイにルーティングの追加

テンプレートファイルのパブリックルートテーブルの定義の下に、以下を追加します。

	# パブリックルートテーブルに、インターネットゲートウェイをルートとして追加
  NetworkingPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      RouteTableId: !Ref NetworkingPublicRouteTable
      GatewayId: !Ref NetworkingInternetGateway

スタックの更新

テンプレートファイルに変更を加えた場合、スタックを削除して再作成する必要はありません。代わりに更新操作を行います。

作成したスタック(networking-1-stack)を選択し、更新をクリックします。

設定項目選択項目
テンプレートの準備既存のテンプレートを置き換える
テンプレートの指定テンプレートファイルのアップロード

ルーティングの確認

追加したルーティングが反映されているか確認し、再度インスタンスにSSH接続します。

  • 追加したルーティングの確認

  • インスタンスにSSH接続する

    $ ssh -i "networking-key.pem" ubuntu@ec2-3-112-198-111.ap-northeast-1.compute.amazonaws.com
    
    ...
    Welcome to Ubuntu 22.04.3 LTS (GNU/Linux 6.2.0-1012-aws x86_64)
    
     * Documentation:  https://help.ubuntu.com
     * Management:     https://landscape.canonical.com
     * Support:        https://ubuntu.com/advantage

    今度はインスタンスにSSH接続することができました。

テンプレートファイルの全文

今回作成したテンプレートファイルの全文が以下です。

# 2010-09-09: 2023年11月現在の時点で最新のバージョン
AWSTemplateFormatVersion: 2010-09-09
# yamlファイルの説明
Description: template file for cloud formation

# リソースの定義
Resources:
  # --------------------
  # 1つ目のVPCの設定
  # --------------------
  # VPCの作成
  NetworkingVPC:
    Type: AWS::EC2::VPC
    Properties:
      # CIDRブロックの指定
      CidrBlock: 10.0.0.0/16
      # DNSサポートの有効化
      EnableDnsSupport: true
      # DNSホスト名の有効化
      EnableDnsHostnames: true
      # 一意になるように名前をつける
      Tags:
        - Key: Name
          Value: networking-vpc

  # パブリックサブネットの作成
  NetworkingPublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      # VPCのIDを指定
      VpcId: !Ref NetworkingVPC
      # CIDRブロックの指定
      CidrBlock: 10.0.1.0/24
      # パブリックサブネットの場合はtrueにし、インターネットゲートウェイをアタッチする
      MapPublicIpOnLaunch: true
      # ハードコードを避けるために、!GetAZs ""を使用
      # 現在のリージョンのAvailability Zoneのリストの最初のAvailability Zoneを選択
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: networking-public-subnet

  # プライベートサブネットの作成
  NetworkingPrivateSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref NetworkingVPC
      CidrBlock: 10.0.4.0/24
      # プライベートサブネットの場合はfalseにし、インターネットゲートウェイをアタッチしない
      MapPublicIpOnLaunch: false
      AvailabilityZone: !Select [0, !GetAZs ""]
      Tags:
        - Key: Name
          Value: networking-private-subnet

  # インターネットゲートウェイの作成
  NetworkingInternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: networking-igw

  # VPCにインターネットゲートウェイをアタッチ
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref NetworkingVPC
      InternetGatewayId: !Ref NetworkingInternetGateway

  # パブリックルートテーブルの作成
  NetworkingPublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref NetworkingVPC
      Tags:
        - Key: Name
          Value: networking-public-route-table

  # パブリックルートテーブルに、インターネットゲートウェイをルートとして追加
  NetworkingPublicRoute:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      RouteTableId: !Ref NetworkingPublicRouteTable
      GatewayId: !Ref NetworkingInternetGateway

  # プライベートルートテーブルの作成
  NetworkingPrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref NetworkingVPC
      Tags:
        - Key: Name
          Value: networking-private-route-table

  # パブリックルートテーブルをパブリックサブネットに関連付け
  NetworkingPublicSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref NetworkingPublicSubnet
      RouteTableId: !Ref NetworkingPublicRouteTable

  # プライベートルートテーブルをプライベートサブネットに関連付け
  NetworkingPrivateSubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref NetworkingPrivateSubnet
      RouteTableId: !Ref NetworkingPrivateRouteTable

  # セキュリティグループ
  # SSHとHTTPのアクセスを許可
  NetworkingSG:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable SSH and HTTP access
      VpcId: !Ref NetworkingVPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
      SecurityGroupEgress:
        - IpProtocol: tcp
          FromPort: 0
          ToPort: 65535
          CidrIp: 0.0.0.0/0

  # インスタンスの作成
  NetworkingEC2Public:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-09a81b370b76de6a2
      InstanceType: t2.micro
      KeyName: networking-key
      NetworkInterfaces:
        # パブリックサブネットに関連付け
        # パブリックサブネットに関連付ける場合は、AssociatePublicIpAddressをtrueにする(パブリックIPの自動割り当て)
        - AssociatePublicIpAddress: true
          DeviceIndex: 0
          GroupSet:
            - !Ref NetworkingSG
          SubnetId: !Ref NetworkingPublicSubnet
      Tags:
        - Key: Name
          Value: networking-ec2-public

本記事の片付け

Cloud Formationでは、テンプレートを基に作成した全ての環境は、スタックを削除するだけでまとめて削除されます。

Cloud Formationのページから作成したスタック(networking-1-stack)を選択し、削除を選択し、スタックを削除します。

まとめ

今回はCloud Formationで環境構築の自動化を行いました。

環境構築の自動化は、ファイルを基に作成するので、環境構築の共有が簡単です。また、一度ファイルを定義すれば人的ミスを防ぐことができます。

本シリーズではAWSの環境構築とその過程でのトラブルシューティングの方法や問題の特定までの手順などに触れました。エラーに遭遇し、解決した数だけトラブルシューティングのレベルは上がります。是非手を動かして学習してみましょう。

エンベーダー編集部

エンベーダーは、ITスクールRareTECHのインフラ学習教材として誕生しました。 「遊びながらインフラエンジニアへ」をコンセプトに、インフラへの学習ハードルを下げるツールとして運営されています。

RareTECH 無料体験授業開催中! オンラインにて実施中! Top10%のエンジニアになる秘訣を伝授します! RareTECH講師への質疑応答可

関連記事