【30分AWSハンズオン(7)】Transit Gatewayを使ってVPC間通信をしてみよう

記事タイトルとURLをコピーする

こんにちは、ラーニングエクスペリエンス課の小倉です。
いつも書いているハンズオンブログですが、今回は サーバーワークス Advent Calendar 2023 シリーズ1 の 10日目のブログとして投稿します。

サーバーワークスでは、自由に勉強会を開催してスキルアップをしています。その中で私は毎週月曜日の朝、「30分AWSハンズオン」という30分でできるAWSハンズオンを2021年9月から継続して開催しています。その内容をブログで定期的に紹介していきます。AWSをご利用のみなさまのスキルアップにお役立ていただければと考えています。

7回目は、「Transit Gatewayを使ってVPC間通信をしてみよう」をやります。

ハンズオンは、以下の流れで実施します。

1.CloudFormationでハンズオン環境の作成
2.Transit Gatewayを作成してVPCへ接続
3.VPCのルートテーブルにTransit Gatwayあてのルートを追加
4.EC2 1にログインして、EC2 2にpingを実行

使用するAWSサービス

Amazon VPC

VPCとは、AWS内で作成できる仮想ネットワークです。同じAWSアカウントで複数のVPCを作成することができますが、それぞれが独立したネットワークのため、直接通信することはできず、インターネットゲートウェイ経由での通信となります。VPC間で直接通信をするためにはいくつか方法があるのですが、その一つが今回のハンズオンで取り扱うTransit Gatewayです。

参考サイト: [AWS Black Belt Online Seminar]Amazon VPC

AWS Transit Gateway

Transit Gatewayとは、VPCやオンプレミスを単一のゲートウェイへ簡単に接続できるサービスです。Transit Gatewayに接続できるのは、Amazon VPC、AWS VPN、AWS Direct Connect Gatewayです。接続するVPCやオンプレミスでCIDRブロックが重複してしまうとルーティングできなくなり、接続することができなくなるため、アドレス設計が重要です。
VPC間を接続する機能としてVPCピアリングというものがあるのですが、それぞれのVPC間での設定が必要となり、VPCの数が多くなるほど管理が煩雑になります。

例えば、VPCが5つあってすべてのVPCとVPCピアリングをする場合、VPCピアリングを10回設定します(左図)。それに対してTransit Gatewayを導入するとすべてのVPCをTransit Gatewayに接続してルートテーブルを設定するだけでVPC間の通信ができるようになり、構成が簡略化されます。

参考サイト: [AWS Black Belt Online Seminar]AWS Transit Gateway

構成図

今回の構成図です。
VPCを2つ作成し、それぞれのVPC内に疎通確認用のEC2を1台ずつ作成します。
Transit Gatewayを作成し、2つのVPCをTransit Gatewayに接続し、Transit Gateway経由でVPC間通信をできるようにします。

ハンズオン手順

1. CloudFormationでハンズオン環境を作成します

まず、ハンズオン環境をCloudFormationを使って準備します。CloudFormationとはコードでインフラを管理できるAWSサービスです。以下のコードをコピーしてローカルのメモ帳などのテキストエディタに貼りつけて、ファイル名 handson7.yml で保存します。このコードを利用するとVPC、サブネット、EC2を作成してくれます。

AWSTemplateFormatVersion: "2010-09-09"
Description: Provision handson environment

Parameters:
  ImageId:
    Type: AWS::SSM::Parameter::Value<String>
    Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64

Resources:
  VPC1:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.1.0/24
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: handson1-vpc
  InternetGateway1:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: handson1-igw
  InternetGatewayAttachment1:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway1
      VpcId: !Ref VPC1
  PublicSubnetA1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.1.0/26
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: handson1-subnet-public-a
  PrivateSubnetA1:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.1.64/26
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: handson1-subnet-private-a
  PublicRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: handson1-rtb-public
  PrivateRouteTable1:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC1
      Tags:
        - Key: Name
          Value: handson1-rtb-private
  PublicRoute1:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable1
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway1
  PublicSubnetARouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA1
      RouteTableId: !Ref PublicRouteTable1
  PrivateSubnetARouteTableAssociation1:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetA1
      RouteTableId: !Ref PrivateRouteTable1
  SecurityGroupforEC21:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: handson1-ec2-sg
      GroupDescription: handson1-ec2-sg
      VpcId: !Ref VPC1
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0
      - IpProtocol: icmp
        FromPort: -1
        ToPort: -1
        CidrIp: 0.0.0.0/0
      Tags:
      - Key: Name
        Value: handson1-ec2-sg
  WebAppInstance1:
    Type: AWS::EC2::Instance
    Properties:
      Tags:
        - Key: Name
          Value: handson1-ec2
      ImageId: !Ref ImageId
      InstanceType: t3.nano
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
      UserData:
        Fn::Base64: "#!/bin/bash -v\nexec > >(tee /var/log/user-data.log || logger -t user-data -s 2> /dev/console) 2>&1\nreboot"
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeleteOnTermination: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetA1
          GroupSet:
            - !Ref SecurityGroupforEC21
  VPC2:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.2.0/24
      EnableDnsSupport: true
      EnableDnsHostnames: true
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: handson2-vpc
  InternetGateway2:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: handson2-igw
  InternetGatewayAttachment2:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      InternetGatewayId: !Ref InternetGateway2
      VpcId: !Ref VPC2
  PublicSubnetA2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.2.0/26
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: handson2-subnet-public-a
  PrivateSubnetA2:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      CidrBlock: 10.0.2.64/26
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: handson2-subnet-private-a
  PublicRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: handson2-rtb-public
  PrivateRouteTable2:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC2
      Tags:
        - Key: Name
          Value: handson2-rtb-private
  PublicRoute2:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable2
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway2
  PublicSubnetARouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA2
      RouteTableId: !Ref PublicRouteTable2
  PrivateSubnetARouteTableAssociation2:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetA2
      RouteTableId: !Ref PrivateRouteTable2
  SecurityGroupforEC22:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: handson2-ec2-sg
      GroupDescription: handson2-ec2-sg
      VpcId: !Ref VPC2
      SecurityGroupIngress:
      - IpProtocol: tcp
        FromPort: 22
        ToPort: 22
        CidrIp: 0.0.0.0/0
      - IpProtocol: icmp
        FromPort: -1
        ToPort: -1
        CidrIp: 0.0.0.0/0
      Tags:
      - Key: Name
        Value: handson2-ec2-sg
  WebAppInstance2:
    Type: AWS::EC2::Instance
    Properties:
      Tags:
        - Key: Name
          Value: handson2-ec2
      ImageId: !Ref ImageId
      InstanceType: t3.nano
      DisableApiTermination: false
      EbsOptimized: false
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 8
      UserData:
        Fn::Base64: "#!/bin/bash -v\nexec > >(tee /var/log/user-data.log || logger -t user-data -s 2> /dev/console) 2>&1\nreboot"
      NetworkInterfaces:
        - AssociatePublicIpAddress: "true"
          DeleteOnTermination: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PublicSubnetA2
          GroupSet:
            - !Ref SecurityGroupforEC22


CloudFormationで上記のコードを実行すると以下の構成ができあがります。


AWSマネジメントコンソールにログインし、画面上の検索窓で「CloudFormation」と入力し、サービスの下に表示された [CloudFormation] をクリックし、CloudFormationのコンソール画面を開きます。また今回のハンズオンは東京リージョンで実施しますので、右上のリージョンが東京になっていない場合は東京に変更しておきましょう。


スタック一覧の画面が表示されるので、右上の [スタックの作成] - [新しいリソースを使用 (標準)] をクリックします。 もしスタック一覧が表示されない場合は、左上のハンバーガーメニュー(三本線のアイコン)をクリックし、ナビゲーションペイン(左メニュー)を表示し、スタックをクリックしてスタック一覧を表示します。


スタックの作成画面が表示されるので、以下を設定して [次へ] をクリックします。

・テンプレートソース: テンプレートファイルのアップロード
・テンプレートファイルのアップロード: ファイルの選択をクリックし、先ほどローカルに保管した handson7.yml を選択


スタックの詳細を指定の画面で、スタック名に tgw-handson と入力して、右下の [次へ] をクリックします。 パラメータの変更は不要です。


スタックオプションの設定画面が表示されるので、ここはなにも変更せずに下にスクロールして右下の [次へ] をクリックします。


レビューの画面が表示されるので、下にスクロールして右下の [送信] をクリックします。

[送信] をクリックすると、CloudFormationによって、AWSリソースの作成が始まります。ステータスが CREATE_IN_PROGRESS から CREATE_COMPLETE になったら作成完了です。3分ほどかかりますので、作成完了まで待ちます。

【作成中】

【作成完了】

2. Transit Gatewayを作成してVPCへ接続します

まず、Transit Gatewayを作成します。
画面上の検索窓で「VPC」と入力し、サービスの下に表示された [VPC] をクリックしVPCのコンソール画面を開きます。また今回のハンズオンは東京リージョンで実施しますので、右上のリージョンが東京になっていない場合は東京に変更しておきましょう。


ナビゲーションペイン(左メニュー)の [Transit Gateway] をクリックし、Transit Gateway一覧の画面を表示した後、画面右上の [Transit Gatewayを作成] をクリックします。


Transit Gatewayを作成の画面で、以下を入力し、[Transit Gatewayを作成] をクリックします。

・名前タグ: yyyymmdd-handson-tgw (yyyymmdd は年月日で、例えば2023年12月10日なら 20231210 となります)


作成したTransit Gatewayが一覧に表示され、状態が Pending から Available に変わったら利用可能となります。
次の手順がAvailableの状態じゃないとできませんので、Availableになるまで2分ほど待ちましょう。


Transit Gatwayの作成が終わったので、次に作成したTransit GatewayをVPCに接続します。
ナビゲーションペイン(左メニュー)の [Transit Gatewayアタッチメント] をクリックし、Transit Gatewayアタッチメント一覧の画面を表示した後、画面右上の [Transit Gatewayアタッチメントを作成] をクリックします。


Transit Gatewayアタッチメントを作成の画面で、以下を入力し、[Transit Gatewayアタッチメントを作成] をクリックします。

詳細
・名前タグ: yyyymmdd-handson1-vpc (yyyymmdd は年月日で、例えば2023年12月10日なら 20231210 となります)
・Transit Gateway ID: yyyymmdd-handson-tgw を選択
・アタッチメントタイプ: VPC


VPCアタッチメント
・VPC ID: handson1-vpc を選択 ・サブネットID: ap-northeast-1 にチェックを入れ、handson1-subnet-private-aを選択


作成したTransit Gatewayアタッチメントが一覧に表示され、状態が Pending から Available に変わったら利用可能となります。


同様の手順で handson2-vpcへのアタッチメントを作成します。

画面右上の [Transit Gatewayアタッチメントを作成] をクリックします。


Transit Gatewayアタッチメントを作成の画面で、以下を入力し、[Transit Gatewayアタッチメントを作成] をクリックします。

詳細
・名前タグ: yyyymmdd-handson2-vpc (yyyymmdd は年月日で、例えば2023年12月10日なら 20231210 となります)
・Transit Gateway ID: yyyymmdd-handson-tgw を選択
・アタッチメントタイプ: VPC

VPCアタッチメント
・VPC ID: handson2-vpc を選択 ・サブネットID: ap-northeast-1 にチェックを入れ、handson2-subnet-private-aを選択


これでTransit Gatewayアタッチメントの作成が終わり、Transit GatewayとVPCの接続が終わりました。

3. VPCのルートテーブルにTransit Gatwayあてのルートを追加します

Transit GatewayとVPCの接続が終わりましたが、今のままだとまだ通信することはできません。それぞれのVPC内のルートテーブルにTransit Gatewayあてのルートを追加する必要があります。

ナビゲーションペイン(左メニュー)の [ルートテーブル] をクリックし、ルートテーブル一覧の中から handson1-rtb-public にチェックを入れます。ルートテーブルの検索窓で、handson1などと検索すると探しやすいです。
画面下のルートタブをクリックし、[ルートを編集] をクリックします。


ルートを編集の画面で、[ルートを追加] をクリックします。
追加された行の送信先に 10.0.2.0/24、ターゲットに Transit Gateway を選択し、先ほど作成したTransit Gatewayアタッチメント(yyyymmdd-handson1-vpc) を選択します。追加が終わりましたら、[変更を保存] をクリックします。


同様にhandson2-vpcのルートテーブルも編集します。
ナビゲーションペイン(左メニュー)の [ルートテーブル] をクリックし、ルートテーブル一覧の中から handson2-rtb-public にチェックを入れます。画面下のルートタブをクリックし、[ルートを編集] をクリックします。


ルートを編集の画面で、[ルートを追加] をクリックします。
追加された行の送信先に 10.0.1.0/24、ターゲットに Transit Gateway を選択し、先ほど作成したTransit Gatewayアタッチメント(yyyymmdd-handson2-vpc) を選択します。追加が終わりましたら、[変更を保存] をクリックします。


これでルートの追加が完了しましたので、疎通確認ができる状態となりました。

4. EC2 1にログインして、EC2 2にpingを実行します

CloudFormationで作成したEC2にログインし、別のVPCのEC2にpingを実行します。

画面上の検索窓で「EC2」と入力し、サービスの下に表示された [EC2] をクリックしEC2のコンソール画面を開きます。また今回のハンズオンは東京リージョンで実施しますので、右上のリージョンが東京になっていない場合は東京に変更しておきましょう。


ナビゲーションペイン(左メニュー)の [インスタンス] をクリックして、インスタンス一覧の画面を表示した後、CloudFormationで作成されたEC2インスタンス(handson2-ec2)にチェックを入れ、接続先のプライベートIPv4アドレスを控えます。


CloudFormationで作成されたEC2インスタンス(handson1-ec2)にチェックを入れ、右上の [接続] をクリックします。


インスタンスに接続の画面で、以下を設定して、右下の [接続] をクリックします。

EC2 Instance Connect タブを選択
・接続タイプは、 EC2 Instance Connect を使用して接続する を選択
・ユーザー名は、ec2-user


接続をクリックするとEC2インスタンスにログインできます。
プロンプトで ping <プライベートIPv4アドレス> を実行して、疎通できることを確認します。

以下のようなメッセージが1秒おきに表示されれば疎通できています。コマンドを停止するときは、キーボードの ctrl + c を押します。
64 bytes from 10.0.2.38: icmp_seq=1 ttl=126 time=1.67 ms


これでVPC間をTransit Gateway経由で通信できることが確認できました。

5. 後片付け

AWSのリソースは従量課金のため、作ったまま放置しておくとお金がかかってしまいます。そのため、ハンズオンが終わったら不要なリソースは削除しておきましょう。

Transit Gatewayアタッチメントを削除します。
VPCのコンソール画面を開き、ナビゲーションペイン(左メニュー)の [Transit Gatewayアタッチメント] をクリックし、Transit Gatewayアタッチメント一覧の画面を表示します。作成したTransit Gatewayアタッチメント (yyyymmdd-handson1-vpc) にチェックを入れ、[アクション] - [Transit Gateway アタッチメントを削除] をクリックします。まとめて削除はできませんので、1つずつ削除します。


削除の確認画面がでますので、入力フィールドに 削除 と入力し、[削除] をクリックします。


もう一つ (yyyymmdd-handson2-vpc) も同様の手順で削除します。Transit Gatewayアタッチメントの削除が完了しないと次のTransit Gatewayの削除ができないので、状態が Deleted になるまで待ちます。

次にTransit Gatewayを削除します。 ナビゲーションペイン(左メニュー)の [Transit Gateway] をクリックし、Transit Gateway一覧の画面を表示します。作成したTransit Gateway (yyyymmdd-handson-tgw) にチェックを入れ、[アクション] - [Transit Gateway を削除]をクリックします。


削除の確認画面がでますので、入力フィールドに 削除 と入力し、[削除] をクリックします。


最後にCloudFormationでスタックの削除をします。
CloudFormationでまとめて作成したリソース(VPC、EC2)は、まとめて削除できます。

CloudFormationのコンソール画面を開き、ナビゲーションペイン(左メニュー)の [スタック] をクリックしてスタック一覧を開きます。ハンズオン環境構築のスタック(tgw-handson) を選択し、 [削除] をクリックします。


確認画面が表示されますので、右下の [削除] をクリックします。


5分ほど経つと削除が完了します。
これで今回のハンズオンは以上となります。

まとめ

今回はTransit Gatewayを使ってVPC間通信をしてみました。Transit Gatewayに接続するだけで複数の宛先に通信できるようになります。複数のVPCやオンプレミスを接続している環境であればTransit Gatewayを利用することで運用負荷を軽減できますので、このハンズオンを通して使い方の基本的を習得しましょう。

参考資料

docs.aws.amazon.com

小倉 大(記事一覧)

アプリケーションサービス部ラーニングエクスペリエンス課 札幌在住

AWSトレーニングの講師をしています。

最近は5歳の息子と遊ぶのが楽しいです!

Twitter: @MasaruOgura