インターネットを経由せずに分散負荷テストをFargateに実行する

AWS分散負荷テストは、テスト対象のサービスに大量のリクエストを発生させて、パフォーマンスにどのような影響が起きるかを検証できるツールです。

このツールを使用してfargateで作成したWebサイトへ負荷テストをかける際に、PrivateLinkを使って、負荷テストのVPCからテスト対象のVPCへインターネットを経由せずに実行してみます。

## 概要

- [AWS分散負荷テスト環境の作成](#aws分散負荷テスト環境の作成)
- [Fargateでテスト対象となるWEBサイトの作成](#fargateでテスト対象となるwebサイトの作成)
- [VPCエンドポイントサービスの作成](#vpcエンドポイントサービスの作成)
- [負荷テストの実行](#負荷テストの実行)
- [通信費は抑えられるのか？](#通信費は抑えられるのか)
  - [PrivateLinkを使用した場合](#privatelinkを使用した場合)
  - [インターネットを経由した場合](#インターネットを経由した場合)
- [まとめ](#まとめ)

## AWS分散負荷テスト環境の作成

負荷テスト環境の作成はCloudformationで簡単に作成可能です。
<https://aws.amazon.com/jp/solutions/implementations/distributed-load-testing-on-aws/>

上記リンクの「AWSコンソールで起動する」をクリックし、AWSコンソールへログインすると、Cloudformationの画面に飛びます。
必要に応じてリージョンの変更などを行います。
![cfn1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/ef21ad23-79b3-fceb-3f5c-9227fcde42e0.png)


Console Administrator Emailは、**受信可能なメールアドレスを入力します。**
入力したメールアドレスに負荷テストのフロントエンド画面へのログイン初期パスワードが送られます。
![cfn2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/03e35804-a521-b066-5dee-846ffbadfe29.png)


既存のVPCに負荷テストツールの環境を作成したい場合は
「Enter values here to use your own existing VPC」に入力します。

新規にVPCを作成する場合は下段の
「Or have the solution create a new AWS Fargate VPC」に入力します。
作成するVPCのCIDRブロックは適当な内部IPでよい場合はそのまま次へ進みます。
![cfn3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/8e041c9c-2267-605f-a713-0f6b44474fea.png)


スタックの作成を行い、10分から15分ほど待ちますと入力したメールアドレスでAWSからメール受信するので、ログインできることを確認します。

以上で、AWS分散負荷テスト環境の構築ができました。

## Fargateでテスト対象となるWEBサイトの作成

とくにFargateではなくEC2なサーバ群でもよいのですが、ポイントとしてはロードバランサにNLBを使うところです。後述のVPCエンドポイントサービスに指定できるのは2021年12月現在、NLBだけです。

あとで簡単に削除しやすいようにCloudformationで作成してみます。

なお、VPCとSubnetは作成済みとします。

Fargateで作成する都合上、VPCにはインターネットゲートウェイを紐づけておいてください。WebサーバはNginxイメージを使用してみます。

~~~
AWSTemplateFormatVersion: '2010-09-09'
Description: Create NLB and Faragate

Parameters:
  VpcId:
    Type: AWS::EC2::VPC::Id
    Default: <VPCID>  
  SubnetIds:
    Type: List<AWS::EC2::Subnet::Id>
    Default: <SubnetID>,<SubnetID>
  Port:
    Type: Number
    Default: 80

Resources:
  ECSCluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: Test-Cluster
  ECSTaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      ContainerDefinitions:
        - Name: Test-Container
          Image: nginx:latest
          PortMappings:
            - ContainerPort: !Ref Port
              HostPort: !Ref Port
              Protocol: tcp
          Essential: true
      Cpu: 256
      ExecutionRoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/ecsTaskExecutionRole
      Family: Test-Task
      Memory: 512
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
  ECSService:
    Type: AWS::ECS::Service
    DependsOn:
      - ECSCluster
      - ECSTaskDefinition
      - SecurityGroup
      - TargetGroup
      - LoadBalancerListener
    Properties:
      Cluster: !Ref ECSCluster
      DesiredCount: 1
      LaunchType: FARGATE
      LoadBalancers:
        - ContainerName: Test-Container
          ContainerPort: !Ref Port
          TargetGroupArn: !Ref TargetGroup
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
            - !Ref SecurityGroup
          Subnets: !Ref SubnetIds
      ServiceName: Test-Service
      TaskDefinition: !Ref ECSTaskDefinition
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: Test-SecurityGroup
      GroupDescription: Test-SecurityGroup
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: !Ref Port
          ToPort: !Ref Port
          CidrIp: 0.0.0.0/0
      VpcId: !Ref VpcId
  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: Test-NLB
      Subnets: !Ref SubnetIds
      Scheme: internet-facing
      Type: network
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    DependsOn:
      - LoadBalancer
      - TargetGroup
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: !Ref Port
      Protocol: TCP
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: Test-targetgroup
      VpcId: !Ref VpcId
      Port: !Ref Port
      Protocol: TCP
      TargetType: ip

~~~

Cloudformationでスタックの作成が完了したら、NLBのDNS名を確認しアクセスできるか確認してみます。
![nlb1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/7b0c3d09-8f58-2d0c-609a-a9155110c141.png)


無事に表示できました。
![nlb2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/2d187b18-3e9b-d26f-ecd0-bc7d3f59f29d.png)


## VPCエンドポイントサービスの作成

AWS分散負荷テストのVPCから、インターネットを経由せずWEBサイトのVPCへ接続（AWS Private Link)するためNLBのVPCエンドポイントサービスを作成します。

既に作成されているNLBが選択できます。
![ep1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/06761b71-8608-1b2e-e53e-fb87772141db.png)

そのまま作成をクリックします。
![ep2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/ccfafcc1-a20a-0f49-a239-8cce2b402b31.png)



エンドポイントサービスの作成が成功したら、サービス名をコピーしておきます。
![ep3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/1e3757c2-753f-e3ae-32e2-c61de4d23540.png)


次にAWS分散負荷テストのVPC内に、エンドポイントを作成します。

「サービス名を名前で検索」を選択し、先ほどコピーしたサービス名を貼り付けて、検証します。

VPCはAWS分散負荷テストのVPCを選択し、エンドポイントの作成を行います。
![ep4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/a331ddea-cfee-2627-b04e-1e13bc5c5141.png)


作成されたエンドポイントをメモします。
![ep5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/b3d02dab-4644-f013-7d3c-5031ce381c64.png)


## 負荷テストの実行

受信したメールのURLへログインし、「CREATE TEST」をクリックします。
![loadtest1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2600759/2c5d29bd-d628-c209-11ed-032f044eb9f1.png)


- Name : 任意の名前
- Description : 任意の説明
- Task Count : 負荷をかける側のコンテナ数
- Concurrency : コンテナ毎の同時接続数
- Ramp Up : Concurrency 数に達するまでの時間（分）
- Hold for : Concurrency 数を保持する時間（分）
- HTTP endpoint under test : メモしたエンドポイントをドメインに設定したURL

「Ramp Up」の時間に達するまでにエラーが発生する場合は、その時点が限界点付近ということがわかります。また、オートスケーリングを設定している場合はオートスケーリングが正しく動作するかを確認します。

「Hold for」は、最大接続数の状態でWebサイトのリソースがどのように変化するのか（リソースリーク、メモリリークなど）を確認する意味もあります。

## 通信費は抑えられるのか？

例として転送量1TB（1カ月）で考えてみます。

### PrivateLinkを使用した場合

VPCエンドポイントは、作成するだけで0.014USD/時間の費用が掛かります。1ヵ月で約10USD（0.014USD×720時間）くらいです。

通信料金は最初の1 PBまで0.01 USD/GBなので、約10USDとなります。

10USD+10USD=20USD

### インターネットを経由した場合

10TB未満までは$0.114/GBとなるので

114USD

## まとめ

ロードバランサーにNLBを使用することで、PrivateLinkを使用してVPC間通信で負荷分散テストを実行できることがわかりました。  
通信費は約1/5程度になります。  
利用例としては、インターネット公開しないWebサービスなどへの負荷テストが考えられます。  
負荷テストの具体的なノウハウは、別の機会にまとめてみたいと思います。