CloudFormation 콘솔을 사용한 Amazon ECS 리소스 생성
CloudFormation 콘솔을 사용한 Amazon ECS 리소스 생성
Amazon ECS를 CloudFormation과 함께 사용하는 한 가지 방법은 AWS Management Console을 이용하는 것입니다. 이 글에서는 템플릿을 사용해 CloudFormation 콘솔에서 Amazon ECS 리소스를 만드는 튜토리얼을 알아봅니다.
출처: 문서
본문
Amazon ECS를 CloudFormation과 함께 사용하는 한 가지 방법은 AWS Management Console을 이용하는 것입니다. 여기서 태스크 정의, 클러스터, 서비스 같은 Amazon ECS 구성 요소에 대한 CloudFormation 스택을 만들고 콘솔에서 직접 배포할 수 있어요. 다음 튜토리얼은 CloudFormation 콘솔을 사용해 템플릿으로 Amazon ECS 리소스를 만드는 방법을 보여줍니다.
사전 요구 사항 (Prerequisites)
이 튜토리얼은 다음 사전 요구 사항이 완료되었음을 가정합니다.
- Set up to use Amazon ECS의 단계가 완료되었습니다.
- IAM 사용자가 AmazonECS_FullAccess IAM 정책 예시에 명시된 필수 권한을 가지고 있습니다.
1단계: 스택 템플릿 생성 (Step 1: Create a stack template)
다음 단계에 따라 Amazon ECS 서비스와 관련 리소스를 위한 CloudFormation 스택 템플릿을 만듭니다.
- 원하는 텍스트 편집기를 사용해
ecs-tutorial-template.yaml이라는 파일을 만듭니다. 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'
이 튜토리얼에서 사용하는 템플릿은 Fargate에서 실행되는 두 개의 태스크를 가진 Amazon ECS 서비스를 생성합니다. 각 태스크는 샘플 Amazon ECS 애플리케이션을 실행합니다. 템플릿은 사용자에게도 애플리케이션 트래픽을 분산하는 Application Load Balancer와 CPU 사용률에 따라 애플리케이션을 확장하는 Application Auto Scaling 정책을 생성합니다. 또한 애플리케이션을 배포하는 데 필요한 네트워킹 리소스, 컨테이너 로그용 로깅 리소스, Amazon ECS 태스크 실행 IAM 역할도 생성합니다.
더 알아보기 (Learn more)
- CloudFormation을 사용한 Amazon ECS 리소스 배포에 대한 자세한 내용은 AWS 개발자 가이드의 관련 문서를 참고하세요.