1. はじめに
今回は、ECS FargateをCloudformationで構築する方法を説明していきます。
ECSについて、興味があったのですが、学習できていませんでした。最近時間ができたので、ECS Fargateを構築したので、構築手順をまとめました。
2. ECSとは
ECS(Amazon Elastic Container)とは、コンテナ化されたアプリケーションをデプロイ、管理、スケーリングするためのコンテナ管理サービスです。
2.1 ECSを構成する構成要素
2.1.1 クラスター
クラスターは、サービスとタスクをグループ化する要素です。
2.1.2 サービス
サービスは、コンテナ化されたアプリケーションの実行とスケーリングを容易にする、フルマネージド型のコンテナオーケストレーションサービスです。
- サービスで設定できる項目
- クラスター
- サービスやタスクを実行するクラスターを設定する
- タスク定義
- 実行するコンテナのリソースや環境変数など
- デプロイメント
- ローリングアップデートやCode
- ターゲット数
- サービスが維持するタスク数を設定。
- ロードバランサ
- タスクのトラフィックを分散する
- ヘルスチェック
- タスクの健全性を監視する
- AutoScaling
- タスク数を自動で増減。CPU使用率やメモリの使用率に基づいて増減する。
- ローンチタイプ
- ECS2かFargateを設定する
- クラスター
2.1.3 タスク
タスクは、1つ以上のコンテナをまとめて実行する単位です。ECSでは、アプリケーションをデプロイ・実行する最小単位です。
タスクの実行内容は、タスク定義に基づきます。
- タスクで設定できる項目
- 使用するDockerイメージ
- コンテナごとのCPU/メモリ割当て
- ポートマッピング
- 環境変数
- ログ設定
4. 構成図
5. 構築手順
プライベートサブネットにECSを作成する方法です。
5.1 VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 192.168.0.0/20
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: 'vpc'
EcsPrivateSubnetAZ:
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref VPC
AvailabilityZone: !Select [0, !GetAZs '']
CidrBlock: 192.168.0.0/24
MapPublicIpOnLaunch: false
Tags:
- Key: Name
Value: 'ecs-private-subnet'
SgEcsSecurityGroup:
Type: AWS::EC2::SecurityGroup
DependsOn: AlbSecurityGroup
Properties:
GroupDescription: 'sg-ecs-security-group'
GroupName: 'sg-ecs-security-group'
SecurityGroupEgress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: 'sg-ecs'
VpcId: !Ref VPC
EcrVpcEndpointSg:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTPS for VPC Endpoints
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
CloudWatchVpcEndpointSg:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow HTTPS for VPC Endpoints
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
SourceSecurityGroupId: !Ref SgEcsSecurityGroup
#---------------------------------------------#
# VPC Endpoint #
#---------------------------------------------#
# プライベートサブネットのECSからECRからイメージ取得するために必要
ECRApiEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api'
VpcId: !Ref VPC
VpcEndpointType: Interface
SubnetIds:
- !Ref EcsPrivateSubnetAZ
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref EcrVpcEndpointSg
Tags:
- Key: Name
Value: 'ecr-api-endpoint'
# プライベートサブネットのECSからECRからイメージ取得するために必要
ECRDockerEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr'
VpcId: !Ref VPC
VpcEndpointType: Interface
SubnetIds:
- !Ref EcsPrivateSubnetAZ
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref EcrVpcEndpointSg
Tags:
- Key: Name
Value: 'dcr-endpoint'
# プライベートサブネットのECSからCloudwatchにログ出力するために必要
CloudWatchEndpoint:
Type: AWS::EC2::VPCEndpoint
Properties:
ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs'
VpcId: !Ref VPC
VpcEndpointType: Interface
SubnetIds:
- !Ref EcsPrivateSubnetAZ
PrivateDnsEnabled: true
SecurityGroupIds:
- !Ref CloudWatchVpcEndpointSg
Tags:
- Key: Name
Value: 'logs-vpc-endpoint'
5.2 クラスター作成
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: cluster
CapacityProviders:
- FARGATE
ClusterSettings:
- Name: containerInsights
Value: enabled
5.3 サービス作成
ECSService:
Type: 'AWS::ECS::Service'
Properties:
ServiceName: ecs-service
Cluster: !Ref ECSCluster
TaskDefinition: !Ref FargateTaskDefinition
DesiredCount: 1
LaunchType: FARGATE
DeploymentController:
Type: CODE_DEPLOY
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: DISABLED
SecurityGroups:
- !Ref SgEcsSecurityGroup
Subnets:
- !Ref EcsPrivateSubnetAZ
LoadBalancers:
- ContainerName: dynamo
ContainerPort: 8080
TargetGroupArn: !Ref TargetGroup
5.4 タスク定義作成
FargateTaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
# ECRのリポジトリを指定する
- Name: test
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/xxxxxxx'
Cpu: 0
PortMappings:
- Name: test
ContainerPort: 8080
HostPort: 8080
Protocol: tcp
AppProtocol: http
Essential: true
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: /ecs/tests
awslogs-region: !Sub ${AWS::Region}
awslogs-stream-prefix: ecs
Family: ecs-family-name
ExecutionRoleArn: !Sub 'arn:aws:iam::${AWS::AccountId}:role/ecs-task-execution-role'
NetworkMode: awsvpc
Cpu: 1024
Memory: 3072
5.5 ECSロール作成
EcsTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: 'ecs-task-execution-role'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
Policies:
- PolicyName: AllowCloudWatchLogsAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogStreams
- logs:CreateLogGroup
Resource: '*'
6. まとめ
ECSをCloudFormationで構築してみました。以前、AWSマネジメントコンソールで作成したことがありました。
その時は、ハンズオンのカリキュラム通りに構築しただけなので、苦戦はしませんでした。
CloudFormationで構築したところ、多くのエラーを解決したところより一層理解が進んだとおもいます。
また、AWS構築では、CloudFormationなどで構築することが多いので、IaCで構築しておいて損はしないと思います。