AWS CLI コマンドを使用した AWS CloudFormation の Amazon ECS リソースの作成 - Amazon Elastic Container Service

AWS CLI コマンドを使用した AWS CloudFormation の Amazon ECS リソースの作成

AWS CloudFormation を使用して Amazon ECS を AWS CLI と連携させる別の方法があります。コマンドを使用して、タスク定義、クラスター、サービスなどの Amazon ECS コンポーネントの AWS CloudFormation スタックを作成してデプロイできます。次のチュートリアルでは、AWS CLI を使用して AWS CloudFormation テンプレートを使用して Amazon ECS リソースを作成する方法を学習します。

前提条件

ステップ 1: スタックを作成する

ecs-tutorial-template.yaml というファイルに保存されている AWS CLI を使用してスタックを作成するには、次のコマンドを実行します。

cat << 'EOF' > ecs-tutorial-template.yaml AWSTemplateFormatVersion: '2010-09-09' Description: '[AWSDocs] ECS: load-balanced-web-application' Parameters: VpcCidr: Type: String Default: '10.0.0.0/16' Description: CIDR block for the VPC ContainerImage: Type: String Default: 'public.ecr.aws/ecs-sample-image/amazon-ecs-sample:latest' Description: Container image to use in task definition PublicSubnet1Cidr: Type: String Default: '10.0.1.0/24' Description: CIDR block for public subnet 1 PublicSubnet2Cidr: Type: String Default: '10.0.2.0/24' Description: CIDR block for public subnet 2 PrivateSubnet1Cidr: Type: String Default: '10.0.3.0/24' Description: CIDR block for private subnet 1 PrivateSubnet2Cidr: Type: String Default: '10.0.4.0/24' Description: CIDR block for private subnet 2 ServiceName: Type: String Default: 'tutorial-app' Description: Name of the ECS service ContainerPort: Type: Number Default: 80 Description: Port on which the container listens DesiredCount: Type: Number Default: 2 Description: Desired number of tasks MinCapacity: Type: Number Default: 1 Description: Minimum number of tasks for auto scaling MaxCapacity: Type: Number Default: 10 Description: Maximum number of tasks for auto scaling Resources: # VPC and Networking VPC: Type: AWS::EC2::VPC Properties: CidrBlock: !Ref VpcCidr EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-vpc' # Internet Gateway InternetGateway: Type: AWS::EC2::InternetGateway Properties: Tags: - Key: Name Value: !Sub '${AWS::StackName}-igw' InternetGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: InternetGatewayId: !Ref InternetGateway VpcId: !Ref VPC # Public Subnets for ALB PublicSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Ref PublicSubnet1Cidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-subnet-1' PublicSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Ref PublicSubnet2Cidr MapPublicIpOnLaunch: true Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-subnet-2' # Private Subnets for ECS Tasks PrivateSubnet1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ''] CidrBlock: !Ref PrivateSubnet1Cidr Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-subnet-1' PrivateSubnet2: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [1, !GetAZs ''] CidrBlock: !Ref PrivateSubnet2Cidr Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-subnet-2' # NAT Gateways for private subnet internet access NatGateway1EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-eip-1' NatGateway2EIP: Type: AWS::EC2::EIP DependsOn: InternetGatewayAttachment Properties: Domain: vpc Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-eip-2' NatGateway1: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway1EIP.AllocationId SubnetId: !Ref PublicSubnet1 Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-1' NatGateway2: Type: AWS::EC2::NatGateway Properties: AllocationId: !GetAtt NatGateway2EIP.AllocationId SubnetId: !Ref PublicSubnet2 Tags: - Key: Name Value: !Sub '${AWS::StackName}-nat-2' # Route Tables PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-public-routes' DefaultPublicRoute: Type: AWS::EC2::Route DependsOn: InternetGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet1 PublicSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PublicRouteTable SubnetId: !Ref PublicSubnet2 PrivateRouteTable1: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-routes-1' DefaultPrivateRoute1: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable1 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway1 PrivateSubnet1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable1 SubnetId: !Ref PrivateSubnet1 PrivateRouteTable2: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: !Sub '${AWS::StackName}-private-routes-2' DefaultPrivateRoute2: Type: AWS::EC2::Route Properties: RouteTableId: !Ref PrivateRouteTable2 DestinationCidrBlock: 0.0.0.0/0 NatGatewayId: !Ref NatGateway2 PrivateSubnet2RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: RouteTableId: !Ref PrivateRouteTable2 SubnetId: !Ref PrivateSubnet2 # Security Groups ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub '${AWS::StackName}-alb-sg' GroupDescription: Security group for Application Load Balancer VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: Allow HTTP traffic from internet SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic Tags: - Key: Name Value: !Sub '${AWS::StackName}-alb-sg' ECSSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub '${AWS::StackName}-ecs-sg' GroupDescription: Security group for ECS tasks VpcId: !Ref VPC SecurityGroupIngress: - IpProtocol: tcp FromPort: !Ref ContainerPort ToPort: !Ref ContainerPort SourceSecurityGroupId: !Ref ALBSecurityGroup Description: Allow traffic from ALB SecurityGroupEgress: - IpProtocol: -1 CidrIp: 0.0.0.0/0 Description: Allow all outbound traffic Tags: - Key: Name Value: !Sub '${AWS::StackName}-ecs-sg' # Application Load Balancer ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub '${AWS::StackName}-alb' Scheme: internet-facing Type: application Subnets: - !Ref PublicSubnet1 - !Ref PublicSubnet2 SecurityGroups: - !Ref ALBSecurityGroup Tags: - Key: Name Value: !Sub '${AWS::StackName}-alb' ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub '${AWS::StackName}-tg' Port: !Ref ContainerPort Protocol: HTTP VpcId: !Ref VPC TargetType: ip HealthCheckIntervalSeconds: 30 HealthCheckPath: / HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 5 Tags: - Key: Name Value: !Sub '${AWS::StackName}-tg' ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP # ECS Cluster ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub '${AWS::StackName}-cluster' CapacityProviders: - FARGATE - FARGATE_SPOT DefaultCapacityProviderStrategy: - CapacityProvider: FARGATE Weight: 1 - CapacityProvider: FARGATE_SPOT Weight: 4 ClusterSettings: - Name: containerInsights Value: enabled Tags: - Key: Name Value: !Sub '${AWS::StackName}-cluster' # IAM Roles ECSTaskExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub '${AWS::StackName}-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 Tags: - Key: Name Value: !Sub '${AWS::StackName}-task-execution-role' ECSTaskRole: Type: AWS::IAM::Role Properties: RoleName: !Sub '${AWS::StackName}-task-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Action: sts:AssumeRole Tags: - Key: Name Value: !Sub '${AWS::StackName}-task-role' # CloudWatch Log Group LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub '/ecs/${AWS::StackName}' RetentionInDays: 7 # ECS Task Definition TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: !Sub '${AWS::StackName}-task' Cpu: '256' Memory: '512' NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn TaskRoleArn: !GetAtt ECSTaskRole.Arn ContainerDefinitions: - Name: !Ref ServiceName Image: !Ref ContainerImage PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp Essential: true LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs HealthCheck: Command: - CMD-SHELL - curl -f http://localhost/ || exit 1 Interval: 30 Timeout: 5 Retries: 3 StartPeriod: 60 Tags: - Key: Name Value: !Sub '${AWS::StackName}-task' # ECS Service ECSService: Type: AWS::ECS::Service DependsOn: ALBListener Properties: ServiceName: !Sub '${AWS::StackName}-service' Cluster: !Ref ECSCluster TaskDefinition: !Ref TaskDefinition DesiredCount: !Ref DesiredCount LaunchType: FARGATE PlatformVersion: LATEST NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref ECSSecurityGroup Subnets: - !Ref PrivateSubnet1 - !Ref PrivateSubnet2 LoadBalancers: - ContainerName: !Ref ServiceName ContainerPort: !Ref ContainerPort TargetGroupArn: !Ref ALBTargetGroup DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 50 DeploymentCircuitBreaker: Enable: true Rollback: true EnableExecuteCommand: true # For debugging Tags: - Key: Name Value: !Sub '${AWS::StackName}-service' # Auto Scaling Target ServiceScalingTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: !Ref MaxCapacity MinCapacity: !Ref MinCapacity ResourceId: !Sub 'service/${ECSCluster}/${ECSService.Name}' RoleARN: !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService' ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs # Auto Scaling Policy - CPU Utilization ServiceScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub '${AWS::StackName}-cpu-scaling-policy' PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ServiceScalingTarget TargetTrackingScalingPolicyConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ECSServiceAverageCPUUtilization TargetValue: 70.0 ScaleOutCooldown: 300 ScaleInCooldown: 300 Outputs: VPCId: Description: VPC ID Value: !Ref VPC Export: Name: !Sub '${AWS::StackName}-VPC-ID' LoadBalancerURL: Description: URL of the Application Load Balancer Value: !Sub 'http://${ApplicationLoadBalancer.DNSName}' Export: Name: !Sub '${AWS::StackName}-ALB-URL' ECSClusterName: Description: Name of the ECS Cluster Value: !Ref ECSCluster Export: Name: !Sub '${AWS::StackName}-ECS-Cluster' ECSServiceName: Description: Name of the ECS Service Value: !GetAtt ECSService.Name Export: Name: !Sub '${AWS::StackName}-ECS-Service' PrivateSubnet1: Description: Private Subnet 1 ID Value: !Ref PrivateSubnet1 Export: Name: !Sub '${AWS::StackName}-Private-Subnet-1' PrivateSubnet2: Description: Private Subnet 2 ID Value: !Ref PrivateSubnet2 Export: Name: !Sub '${AWS::StackName}-Private-Subnet-2' EOF

このチュートリアルで使用するテンプレートは、Fargate で実行する 2 つのタスクを持つ Amazon ECS サービスを作成します。このチュートリアルで使用するテンプレートは、Fargate で実行する 2 つのタスクを持つ Amazon ECS サービスを作成します。テンプレートは、アプリケーショントラフィックを分散する Application Load Balancer と、CPU 使用率に基づいて、アプリケーションをスケーリングする Application Auto Scaling ポリシーも作成します。更に、テンプレートは、アプリケーションのデプロイに必要なネットワークリソース、コンテナログのログ記録リソース、および Amazon ECS タスク実行 IAM ロールも作成します。タスクの実行ロールの詳細については、「Amazon ECS タスク実行IAM ロール」を参照してください。自動スケーリングの詳細については、「Amazon ECS サービスを自動的にスケールする」を参照してください。

テンプレートファイルを作成したら、次のコマンドを使用してスタックを作成します。テンプレートで指定した Amazon ECS タスク実行ロールを作成するには、--capabilities フラグが必要です。--parameters フラグを指定して、テンプレートパラメータをカスタマイズすることもできます。

aws cloudformation create-stack \ --stack-name ecs-tutorial-stack \ --template-body file://ecs-tutorial-template.yaml \ --region aws-region \ --capabilities CAPABILITY_NAMED_IAM

create-stack コマンドを実行した後、 describe-stacks を使用してスタック作成のステータスを確認できます。

aws cloudformation describe-stacks \ --stack-name ecs-tutorial-stack \ --region aws-region

ステップ 2: Amazon ECS リソースの作成を検証する

Amazon ECS リソースが正しく作成されていることを確認するには、次の手順に従います。

  1. 次のコマンドを実行して、AWS リージョン 内のすべてのタスク定義を一覧表示します。

    aws ecs list-task-definitions

    コマンドは、タスク定義の Amazon リソースネーム (ARN) のリストを返します。テンプレートを使用して作成したタスク定義の ARN は、次の形式で表示されます。

    { "taskDefinitionArns": [ ..... "arn:aws:ecs:aws-region:111122223333:task-definition/ecs-tutorial-stack-task:1", ..... ] }
  2. 次のコマンドを実行して、AWS リージョン 内のすべてのクラスターを一覧表示します。

    aws ecs list-clusters

    コマンドはクラスター ARN のリストを返します。テンプレートを使用して作成したクラスターの ARN は、次の形式で表示されます。

    { "clusterArns": [ ..... "arn:aws:ecs:aws-region:111122223333:cluster/ecs-tutorial-stack-cluster", ..... ] }
  3. クラスター ecs-tutorial-stack-cluster 内のすべてのサービスを一覧表示するには、次のコマンドを実行します。

    aws ecs list-services \ --cluster ecs-tutorial-stack-cluster

    コマンドは、サービス ARN のリストを返します。テンプレートを使用して作成されたサービスの ARN は、次の形式で表示されます。

    { "serviceArns": [ "arn:aws:ecs:aws-region:111122223333:service/ecs-tutorial-stack-cluster/ecs-tutorial-stack-service" ] }

作成された Application Load Balancer の DNS 名を取得し、それを使用してリソースの作成を確認することもできます。DNS 名を取得するには、次のコマンドを実行します。

作成されたスタックの出力を取得するには、次のコマンドを実行します。

aws cloudformation describe-stacks \ --stack-name ecs-tutorial-stack \ --region aws-region \ --query 'Stacks[0].Outputs[?OutputKey==`LoadBalancerURL`].OutputValue' \ --output text

出力:

http://ecs-tutorial-stack-alb-0123456789.aws-region.elb.amazonaws.com

DNS 名をブラウザに貼り付けて、Amazon ECS アプリケーションのサンプルを表示するウェブページを表示します。

ステップ 3: クリーンアップする

作成したリソースをクリーンアップするには、以下のコマンドを実行します。

aws cloudformation delete-stack \ --stack-name ecs-stack

delete-stack コマンドは、このチュートリアルで作成した AWS CloudFormation スタックの削除を開始し、スタック内のすべてのリソースを削除します。削除を確認するには、ステップ 2: Amazon ECS リソースの作成を検証する で同じ手順を繰り返します。出力内の ARN のリストには、ecs-tutorial-stack-task というタスク定義や ecs-tutorial-stack-cluster という名前のクラスターが含まれなくなります。list-services 呼び出しは失敗します。