プライベートサブネット内のFargateコンテナをALBにアタッチするための構成
以下のページで、ALBの3種類のターゲットタイプを確認しました。
具体的には、instance, ip, lambdaです。
今回はFargateをALBにアタッチする方法を確認します。
ポイントはターゲットタイプをipに設定する必要があるという点です。
構築する環境
FargateはAuto Scalingの設定を行います。
デフォルトのタスク数は1ですが、CPUの使用率に応じて、最大3つまでスケールアウトするように設定します。
環境構築用のCloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置してます。
https://github.com/awstut-an-r/awstut-fa/tree/main/019
テンプレートファイルのポイント解説
プライベートサブネット内のリソースを、ALBにアタッチする方法については、以下のページをご確認ください。
Fargateの基本については、以下のページをご確認ください。
本ページでは、上記の2ページとは異なる点と、FargateをALBにアタッチする際の、ALBターゲットグループの設定にフォーカスします。
プライベートサブネットからECRにアクセスするためには、3つのVPCエンドポイントが必要
ポイントは、プライベートサブネット内のFargateが、ECRリポジトリにアクセスするための経路としてのVPCエンドポイントを作成する必要があるという点です。
Resources:
ECRDkrEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref EndpointSecurityGroup
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ecr.dkr"
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
VpcEndpointType: Interface
VpcId: !Ref VPC
ECRApiEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref EndpointSecurityGroup
ServiceName: !Sub "com.amazonaws.${AWS::Region}.ecr.api"
SubnetIds:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
VpcEndpointType: Interface
VpcId: !Ref VPC
S3Endpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal: "*"
Action:
- s3:*
Resource:
- !Sub "arn:aws:s3:::prod-${AWS::Region}-starport-layer-bucket/*"
RouteTableIds:
- !Ref PrivateRouteTable
ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
VpcId: !Ref VPC
Code language: YAML (yaml)
プライベートサブネットのFargateがECRにアクセスするためには、3種類のVPCエンドポイントを作成する必要があります。
ECRに関するエンドポイントが2つ、S3に関するエンドポイントが1つです。
詳細は以下のページをご確認ください。
ALBにFargateをアタッチするためには、TargetGroupのTargetTypeをipにする
ポイントは、TargetGroupです。
Resources:
ALBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Name: !Sub ${Prefix}-ALBTargetGroup
Protocol: HTTP
Port: !Ref HTTPPort
HealthCheckProtocol: HTTP
HealthCheckPath: /
HealthCheckPort: traffic-port
HealthyThresholdCount: !Ref HealthyThresholdCount
UnhealthyThresholdCount: !Ref UnhealthyThresholdCount
HealthCheckTimeoutSeconds: !Ref HealthCheckTimeoutSeconds
HealthCheckIntervalSeconds: !Ref HealthCheckIntervalSeconds
Matcher:
HttpCode: !Ref HttpCode
TargetType: ip
Code language: YAML (yaml)
TargetTypeプロパティが重要です。
「ip」に設定する必要があります。
本プロパティのデフォルト値は「instance」ですが、この値は、以下の引用の通り、ALBにFargateをアタッチする際の条件を満たしません。
[Target type] (ターゲットタイプ) で、[Instance] (インスタンス) または [IP] を選択します。
重要: サービスのタスク定義で awsvpc ネットワークモード (AWS Fargate 起動タイプで必須) を使用している場合は、ターゲットタイプとして [IP] を選択する必要があります。これは、awsvpc ネットワークモードを使用するタスクが Elastic Network Interface に関連付けられているためです。
Application Load Balancer を作成し、Amazon ECS タスクを自動的に登録する方法を教えてください。
ECSサービスでアタッチするALBを指定する
コンテナ用のサービス、タスクおよびAutoScalingグループを定義します。
本テンプレートのポイントの1つは、ALBにFargateをアタッチする方法に関する設定です。
アタッチはECSサービスリソース側の設定で行います。
Resources:
Service:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref Cluster
DesiredCount: 1
LaunchType: FARGATE
LoadBalancers:
- ContainerName: !Sub "${Prefix}-${ServiceName}-container"
ContainerPort: !Ref HTTPPort
TargetGroupArn: !Ref ALBTargetGroup
NetworkConfiguration:
AwsvpcConfiguration:
SecurityGroups:
- !Ref ServiceSecurityGroup
Subnets:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
ServiceName: !Sub "${Prefix}-${ServiceName}-service"
TaskDefinition: !Ref TaskDefinition
Code language: YAML (yaml)
LoadBalancersプロパティで、本サービスに関連付けるELBを指定します。
ALBおよびFargateのポート番号まとめ
ALBのTargetGroupのPortプロパティ、ECSサービスのContainerPortプロパティに加えて、ECSタスク定義にもポート情報の設定項目があります。
Resources:
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/${MyRepository}:latest"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref LogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: !Ref Prefix
Name: !Sub "${Prefix}-${ServiceName}-container"
PortMappings:
- ContainerPort: !Ref HTTPPort
HostPort: !Ref HTTPPort
Cpu: !Ref ServiceCpu
ExecutionRoleArn: !Ref FargateTaskExecutionRole
Memory: !Ref ServiceMemory
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
TaskRoleArn: !Ref TaskRole
Code language: YAML (yaml)
PortMappingsプロパティです。
配下の2つのパラメータがあります。
このように複数のリソースでポート番号に関するパタメータが存在します。
これらの値を統一的に設定しなければ、正常に通信することはできません。
以下に今回登場したパラメータを整理します。
- AWS::ElasticLoadBalancingV2::TargetGroupのPortプロパティ:ALBがターゲット(ECSサービス)にトラフィックを送る際の送信先ポート番号
- AWS::ECS::Service LoadBalancersのContainerPortプロパティ:ECSがALBからトラフィックを受け取る際のリッスンするポート番号
- AWS::ECS::TaskDefinition PortMappingのContainerPortプロパティ:コンテナに割り当てるポート番号。AWS::ECS::Service LoadBalancersのContainerPortプロパティと同じ値に設定する必要がある。
- AWS::ECS::TaskDefinition PortMappingのHostPortプロパティ:コンテナを起動するホスト側に割り当てるポート番号。Fargateの場合(ネットワークモードがawsvpc場合)、AWS::ECS::TaskDefinition PortMappingのContainerPortプロパティと同じ値に設定する必要がある。
加えて実行するコンテナ内のポート設定も関係してきます。
今回実行するNginxは、デフォルトで80番ポートでリッスンする設定ですので、上記の値を全て80に統一します。
Fargateタスク用のAutoScalingグループ
最後にFargateタスクのスケーリングさせるためのリソースを確認します。
まずスケーリングする対象をターゲットとして定義します。
Resources:
ServiceScalableTarget:
Type: AWS::ApplicationAutoScaling::ScalableTarget
DependsOn:
- Service
Properties:
MaxCapacity: 3
MinCapacity: 1
ResourceId: !Select [5, !Split [":", !Ref Service]]
RoleARN: !GetAtt ServiceTaskScalingRole.Arn
ScalableDimension: ecs:service:DesiredCount
ServiceNamespace: ecs
Code language: YAML (yaml)
FarateタスクのスケーリングはECSサービスに対して設定します。これはECSサービスがタスク数を調整する働きを行なっているためです。ResourceIdプロパティで対象のサービスを指定し、ScalableDimensionプロパティでタスクの希望数を意味する「ecs:service:DesiredCount」を指定します。今回はデフォルトで1つのタスクが動作し、CPUの使用率に応じてスケールアウトさせる予定ですので、MinCapacityプロパティに「1」、MaxCapacityプロパティに「3」を指定します。
次にスケーリングの条件などをまとめたポリシーを定義します。
Resources:
ServiceScalingPolicy:
Type: AWS::ApplicationAutoScaling::ScalingPolicy
DependsOn:
- Service
- ServiceScalableTarget
Properties:
PolicyName: ServiceScalingPolicy
PolicyType: TargetTrackingScaling
ScalingTargetId: !Ref ServiceScalableTarget
TargetTrackingScalingPolicyConfiguration:
DisableScaleIn: false
PredefinedMetricSpecification:
PredefinedMetricType: ECSServiceAverageCPUUtilization
ScaleInCooldown: 0
ScaleOutCooldown: 0
TargetValue: !Ref ServiceScalingTargetValue
Code language: YAML (yaml)
CPUの使用率を条件としますので、PolicyTypeプロパティにターゲット追跡スケーリングポリシーを意味する「TargetTrackingScaling」を指定します。TargetTrackingScalingPolicyConfigurationプロパティにて、ターゲットや追跡するメトリクスを定義します。ECSサービスのCPU使用率に関するメトリックはAWS側で事前に用意されているため、PredefinedMetricTypeプロパティに「ECSServiceAverageCPUUtilization」を指定することができます。
最後にスケーリングを実行するために必要な権限を、IAMロールとして用意します。
Resources:
ServiceTaskScalingRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole
Code language: YAML (yaml)
AWS管理ポリシーには、ECSのスケーリングを実行するため必要な最低限の権限をまとめた「AmazonEC2ContainerServiceAutoscaleRole」が用意されてあります。今回はこちらを使用します。ちなみに本ポリシーでは、以下のアクションが許可されます。
- ecs:DescribeServices
- ecs:UpdateService
- cloudwatch:DescribeAlarms
- cloudwatch:PutMetricAlarm
サービスの更新や、スケーリングのためのCloudWatchアラームの作成に関するアクションが許可されます。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
今回は2回に分けてCloudFormationスタックを作成します。
ECRリポジトリを作成する
まずECRリポジトリを作成します。詳細は別ページをご確認ください。
残りのCloudFormationスタックを作成する
CloudFormationスタックを作成します。引き続きスタックの作成および各スタックの確認方法については、以下のページをご確認ください。
各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。
- ECSクラスター:fa-019-cluster
- ECSサービス名:fa-018-container1-service
- ALB名:fa-019-ALB
作成されたリソースをAWS Management Consoleから確認します。まずクラスターを確認します。
確かにクラスターが作成されていることがわかります。クラスターの詳細を確認します。
クラスター内にサービスが1つ動作していることがわかります。それぞれのサービス上で動作しているタスクの詳細を確認します。
現時点では、1つのタスクが実行されていることがわかります。次にALBの詳細を確認します。
ALBに設定されたパブリックDNS名がわかりました。今回は「fa-019-ALB-1804817577.ap-northeast-1.elb.amazonaws.com」でした。ALBのTargetGroupも確認します。
1つのタスクがターゲットとして登録されていることがわかります。
検証1:プライベートサブネット内のFargateにALBからアクセスする
準備が整いましたので、実際にブラウザからALBにアクセスします。
正常に表示されました。プライベートサブネット内のFargateがALBにアタッチされていることが確認できました。CloudWatch Logsにもアクセスログが書き込まれます。
検証2:Fargateをスケールアウトさせる
スケールアウトを確認します。今回の構成では、CPUの使用率の増加がトリガーとなりますので、ページを繰り返しリロードし、ECSサービスの負荷を高めます。しばらく待つと、CPU使用率が閾値(0.01%)を超えてきます。
するとスケーリングが開始されます。Eventsタブで詳細を確認することができます。
タスク数が3つにスケールアウトされました。アクティブなタスク数を確認します。
確かにタスク数が3つに増えています。正常にスケールされました。最後にCloudWatch Logsを確認します。
ご覧の通り、タスクごとにログストリームが作成されています。ログはタスクごとに保存されるということです。
まとめ
プライベートサブネット内のFargateをALBにアタッチすることができました。
Fargateのスケールアウトの設定方法や挙動を確認しました。