aws-cloudformation-ecs

AWS CloudFormation ECS

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "aws-cloudformation-ecs" with this command: npx skills add giuseppe-trisciuoglio/developer-kit/giuseppe-trisciuoglio-developer-kit-aws-cloudformation-ecs

AWS CloudFormation ECS

Create production-ready container infrastructure using AWS CloudFormation templates. This skill covers ECS clusters, services, task definitions, container configurations, scaling, service discovery, load balancing, and blue/green deployments with CodeDeploy.

When to Use

Use this skill when:

  • Creating new ECS clusters with CloudFormation

  • Defining task definitions for container workloads

  • Configuring ECS services with deployment strategies

  • Integrating ECS with Application Load Balancer

  • Implementing auto scaling for ECS services

  • Configuring service discovery with Cloud Map

  • Implementing blue/green deployments with CodeDeploy

  • Organizing templates with Parameters, Outputs, Mappings, Conditions

  • Implementing cross-stack references with export/import

  • Using Transform for macro and reuse

Template Structure

Base Template with Standard Format

AWSTemplateFormatVersion: 2010-09-09 Description: ECS cluster with service and load balancer

Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Cluster Configuration Parameters: - ClusterName - InstanceType - DesiredCapacity - Label: default: Container Configuration Parameters: - ContainerName - ContainerImage - ContainerPort

Parameters: ClusterName: Type: String Default: production-ecs-cluster Description: Name of the ECS cluster

InstanceType: Type: String Default: t3.medium AllowedValues: - t3.small - t3.medium - t3.large - m5.large

DesiredCapacity: Type: Number Default: 2 MinValue: 1 MaxValue: 20 Description: Initial number of EC2 instances

ContainerName: Type: String Default: web-app Description: Name of the container

ContainerImage: Type: String Default: nginx:latest Description: Docker image for the container

ContainerPort: Type: Number Default: 80 Description: Port the container listens on

Mappings: EnvironmentConfig: dev: InstanceType: t3.small DesiredCapacity: 1 ContainerMemoryHardLimit: 256 ContainerMemorySoftLimit: 128 staging: InstanceType: t3.medium DesiredCapacity: 2 ContainerMemoryHardLimit: 512 ContainerMemorySoftLimit: 256 production: InstanceType: t3.large DesiredCapacity: 3 ContainerMemoryHardLimit: 1024 ContainerMemorySoftLimit: 512

Conditions: IsProduction: !Equals [!Ref Environment, production] UseSpotInstances: !Equals [!Ref SpotInstances, true]

Transform:

  • AWS::Serverless-2016-10-31

Resources:

ECS Cluster

ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Ref ClusterName ClusterSettings: - Name: containerInsights Value: enabled

EC2 Instance Configuration

InstanceCapacity: Type: AWS::AutoScaling::LaunchConfiguration Properties: ImageId: !Ref AmiId InstanceType: !Ref InstanceType IamInstanceProfile: !Ref EcsInstanceProfile SecurityGroups: - !Ref EcsSecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash echo "ECS_CLUSTER=${ECSCluster.Name}" >> /etc/ecs/ecs.config echo "ECS_BACKEND_HOST=${ECSBackendHost}" >> /etc/ecs/ecs.config BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: 30 VolumeType: gp3

AutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Sub "${ClusterName}-asg" LaunchConfigurationName: !Ref InstanceCapacity MinSize: !Ref DesiredCapacity MaxSize: !Ref MaxCapacity DesiredCapacity: !Ref DesiredCapacity VPCZoneIdentifier: !Ref SubnetIds Tags: - Key: Name Value: !Sub "${ClusterName}-instance" PropagateAtLaunch: true - Key: Environment Value: !Ref Environment PropagateAtLaunch: true

Outputs: ClusterName: Description: Name of the ECS cluster Value: !Ref ECSCluster Export: Name: !Sub "${AWS::StackName}-ClusterName"

ClusterArn: Description: ARN of the ECS cluster Value: !GetAtt ECSCluster.Arn Export: Name: !Sub "${AWS::StackName}-ClusterArn"

Parameters Best Practices

AWS-Specific Parameter Types

Parameters:

AWS-specific types for validation

VpcId: Type: AWS::EC2::VPC::Id Description: VPC where ECS cluster will be created

SubnetIds: Type: List<AWS::EC2::Subnet::Id> Description: Subnets for ECS instances

SecurityGroupIds: Type: List<AWS::EC2::SecurityGroup::Id> Description: Security groups for ECS service

ClusterArn: Type: AWS::ECS::Cluster::Arn Description: ARN of existing ECS cluster

TaskDefinitionArn: Type: AWS::ECS::TaskDefinition::Arn Description: ARN of ECS task definition

ServiceArn: Type: AWS::ECS::Service::Arn Description: ARN of ECS service

LoadBalancerArn: Type: AWS::ElasticLoadBalancingV2::LoadBalancer::Arn Description: ARN of Application Load Balancer

TargetGroupArn: Type: AWS::ElasticLoadBalancingV2::TargetGroup::Arn Description: ARN of Target Group

Parameter Constraints

Parameters: ContainerName: Type: String Default: web-app Description: Container name ConstraintDescription: Must be 1-256 characters, alphanumeric and hyphens MinLength: 1 MaxLength: 256 AllowedPattern: "[a-zA-Z0-9-]+"

DesiredCount: Type: Number Default: 2 Description: Desired number of tasks MinValue: 0 MaxValue: 1000 ConstraintDescription: Must be between 0 and 1000

Cpu: Type: String Default: 256 Description: CPU units for container AllowedValues: - 128 - 256 - 512 - 1024 - 2048 - 4096 ConstraintDescription: Must be a valid CPU value

Memory: Type: Number Default: 512 Description: Memory limit in MiB MinValue: 4 MaxValue: 15000 ConstraintDescription: Must be between 4 and 15000 MiB

SSM Parameter References

Parameters: ContainerImage: Type: AWS::SSM::Parameter::Value<String> Default: /ecs/app/container-image Description: Container image from SSM Parameter Store

DatabaseConnectionString: Type: AWS::SSM::Parameter::Value<SecureString> Default: /ecs/app/database/connection Description: Database connection from SSM

Outputs and Cross-Stack References

Export/Import Patterns

Stack A - Network Stack

AWSTemplateFormatVersion: 2010-09-09 Description: Network infrastructure stack for ECS

Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true Tags: - Key: Name Value: !Sub "${AWS::StackName}-vpc"

PublicSubnets: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true

PrivateSubnets: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: !Select [0, !GetAZs ""] CidrBlock: 10.0.2.0/24

Outputs: VpcId: Description: VPC ID Value: !Ref VPC Export: Name: !Sub "${AWS::StackName}-VpcId"

PublicSubnetIds: Description: Public subnet IDs Value: !Join [",", [!Ref PublicSubnet1, !Ref PublicSubnet2]] Export: Name: !Sub "${AWS::StackName}-PublicSubnetIds"

PrivateSubnetIds: Description: Private subnet IDs Value: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]] Export: Name: !Sub "${AWS::StackName}-PrivateSubnetIds"

EcsSecurityGroupId: Description: Security group ID for ECS Value: !Ref EcsSecurityGroup Export: Name: !Sub "${AWS::StackName}-EcsSecurityGroupId"

Stack B - ECS Stack (imports from Stack A)

AWSTemplateFormatVersion: 2010-09-09 Description: ECS application stack

Parameters: NetworkStackName: Type: String Default: network-stack Description: Name of the network stack

Resources: ECSService: Type: AWS::ECS::Service Properties: ServiceName: !Sub "${AWS::StackName}-service" Cluster: !ImportValue !Sub "${NetworkStackName}-ClusterArn" TaskDefinition: !Ref TaskDefinition DesiredCount: 2 LaunchType: EC2 NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !ImportValue !Sub "${NetworkStackName}-EcsSecurityGroupId" Subnets: - !Select [0, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]] - !Select [1, !Split [",", !ImportValue !Sub "${NetworkStackName}-PrivateSubnetIds"]]

Nested Stacks for Modularity

AWSTemplateFormatVersion: 2010-09-09 Description: Main stack with nested ECS stacks

Resources:

Nested stack for cluster

ClusterStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://s3.amazonaws.com/bucket/ecs-cluster.yaml TimeoutInMinutes: 30 Parameters: ClusterName: !Ref ClusterName Environment: !Ref Environment

Nested stack for services

ServicesStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://s3.amazonaws.com/bucket/ecs-services.yaml TimeoutInMinutes: 30 Parameters: ClusterArn: !GetAtt ClusterStack.Outputs.ClusterArn Environment: !Ref Environment

Nested stack for load balancer

LoadBalancerStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: https://s3.amazonaws.com/bucket/ecs-alb.yaml TimeoutInMinutes: 30 Parameters: VpcId: !Ref VpcId Subnets: !Ref Subnets

ECS Task Definitions

Basic Task Definition

AWSTemplateFormatVersion: 2010-09-09 Description: ECS task definition

Resources: TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: web-app-task Cpu: "512" Memory: "1024" NetworkMode: awsvpc RequiresCompatibilities: - EC2 - FARGATE ExecutionRoleArn: !Ref TaskExecutionRole TaskRoleArn: !Ref TaskRole ContainerDefinitions: - Name: web-app Image: !Ref ContainerImage Cpu: 256 Memory: 512 PortMappings: - ContainerPort: !Ref ContainerPort Protocol: tcp Environment: - Name: ENVIRONMENT Value: !Ref Environment - Name: LOG_LEVEL Value: INFO Secrets: - Name: DATABASE_URL ValueFrom: !Ref DatabaseSecretArn 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:8080/health || exit 1 Interval: 30 Timeout: 5 Retries: 3 StartPeriod: 60

TaskExecutionRole: 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 Policies: - PolicyName: EcsSecretsPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - secretsmanager:GetSecretValue Resource: !Ref DatabaseSecretArn - PolicyName: EcsLogsPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: !GetAtt LogGroup.Arn

LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/ecs/${AWS::StackName}" RetentionInDays: 30

Multi-Container Task Definition

Resources: TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: multi-container-task Cpu: "1024" Memory: "2048" NetworkMode: awsvpc ContainerDefinitions: - Name: web Image: nginx:latest Cpu: 256 Memory: 512 PortMappings: - ContainerPort: 80 Protocol: tcp DependsOn: - ContainerName: app Condition: HEALTHY Environment: - Name: BACKEND_URL Value: !Sub "http://localhost:${AppPort}" LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: web

    - Name: app
      Image: !Ref AppImage
      Cpu: 512
      Memory: 1024
      PortMappings:
        - ContainerPort: !Ref AppPort
          Protocol: tcp
      Environment:
        - Name: DATABASE_URL
          ValueFrom: !Ref DatabaseSecretArn
        - Name: REDIS_URL
          ValueFrom: !Ref RedisSecretArn
      LogConfiguration:
        LogDriver: awslogs
        Options:
          awslogs-group: !Ref LogGroup
          awslogs-region: !Ref AWS::Region
          awslogs-stream-prefix: app

    - Name: redis
      Image: redis:alpine
      Cpu: 128
      Memory: 256
      PortMappings:
        - ContainerPort: 6379
          Protocol: tcp
      HealthCheck:
        Command:
          - CMD-SHELL
          - redis-cli ping | grep -q PONG
        Interval: 10
        Timeout: 5
        Retries: 3

ECS Services

Service with Application Load Balancer

AWSTemplateFormatVersion: 2010-09-09 Description: ECS service with ALB

Resources:

Application Load Balancer

ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub "${AWS::StackName}-alb" Scheme: internet-facing SecurityGroups: - !Ref AlbSecurityGroup Subnets: !Ref PublicSubnets Type: application

AlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub "${AWS::StackName}-alb-sg" GroupDescription: Security group for ALB VpcId: !Ref VpcId SecurityGroupIngress: # HTTP from anywhere - public-facing ALB requires this # For production, use AWS WAF or restrict to known CIDR ranges - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: HTTP for public web traffic # HTTPS from anywhere - public-facing ALB requires this # For production, use AWS WAF or restrict to known CIDR ranges - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 Description: HTTPS for secure public web traffic

Target Groups

BlueTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub "${AWS::StackName}-blue-tg" Port: 80 Protocol: HTTP VpcId: !Ref VpcId Matcher: HttpCode: 200-499 HealthCheckPath: /health HealthCheckIntervalSeconds: 30 HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 3 TargetType: ip IpAddressType: ipv4

GreenTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub "${AWS::StackName}-green-tg" Port: 80 Protocol: HTTP VpcId: !Ref VpcId Matcher: HttpCode: 200-499 HealthCheckPath: /health HealthCheckIntervalSeconds: 30 HealthCheckTimeoutSeconds: 5 HealthyThresholdCount: 2 UnhealthyThresholdCount: 3 TargetType: ip IpAddressType: ipv4

Listener

AlbListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward ForwardConfig: TargetGroupStickinessConfig: Enabled: false DurationSeconds: 3600 TargetGroups: - TargetGroupArn: !Ref BlueTargetGroup Weight: 100 LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP

ECS Service

EcsService: Type: AWS::ECS::Service DependsOn: AlbListener Properties: ServiceName: !Sub "${AWS::StackName}-service" Cluster: !Ref ECSClusterArn TaskDefinition: !Ref TaskDefinitionArn DesiredCount: 2 LaunchType: FARGATE DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 50 DeploymentCircuitBreaker: Enable: true Rollback: true NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref EcsSecurityGroup Subnets: !Ref PrivateSubnets LoadBalancers: - ContainerName: web ContainerPort: 80 TargetGroupArn: !Ref BlueTargetGroup PropagateTags: SERVICE ServiceRegistries: - RegistryArn: !GetAtt ServiceDiscoveryService.Arn

EcsSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub "${AWS::StackName}-ecs-sg" GroupDescription: Security group for ECS service VpcId: !Ref VpcId SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref AlbSecurityGroup

Service Discovery

ServiceDiscoveryService: Type: AWS::ServiceDiscovery::Service Properties: Name: web-app DnsConfig: NamespaceId: !Ref ServiceDiscoveryNamespace DnsRecords: - Type: A TTL: 60 HealthCheckConfig: Type: HTTP ResourcePath: /health

ServiceDiscoveryNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Name: !Sub "${Environment}.internal" VpcId: !Ref VpcId

Auto Scaling

Service Auto Scaling

AWSTemplateFormatVersion: 2010-09-09 Description: ECS service with auto scaling

Resources:

Scalable Target

ScalableTarget: Type: AWS::ApplicationAutoScaling::ScalableTarget Properties: MaxCapacity: 10 MinCapacity: 2 ResourceId: !Sub "service/${ECSClusterName}/${ECSServiceName}" RoleARN: !Ref AutoScalingRoleArn ScalableDimension: ecs:service:DesiredCount ServiceNamespace: ecs

Scaling Policy - CPU Utilization

CpuScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub "${AWS::StackName}-cpu-scaling" PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ScalableTarget TargetTrackingScalingPolicyConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ECSServiceAverageCPUUtilization TargetValue: 70 ScaleInCooldown: 300 ScaleOutCooldown: 60

Scaling Policy - Memory Utilization

MemoryScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub "${AWS::StackName}-memory-scaling" PolicyType: TargetTrackingScaling ScalingTargetId: !Ref ScalableTarget TargetTrackingScalingPolicyConfiguration: PredefinedMetricSpecification: PredefinedMetricType: ECSServiceAverageMemoryUtilization TargetValue: 80 ScaleInCooldown: 300 ScaleOutCooldown: 60

Step Scaling Policy

RequestCountScalingPolicy: Type: AWS::ApplicationAutoScaling::ScalingPolicy Properties: PolicyName: !Sub "${AWS::StackName}-request-scaling" PolicyType: StepScaling ScalingTargetId: !Ref ScalableTarget StepScalingPolicyConfiguration: AdjustmentType: ChangeInCapacity Cooldown: 60 MetricAggregationType: Average StepAdjustments: - MetricIntervalLowerBound: 0 ScalingAdjustment: 1 - MetricIntervalLowerBound: 1000 ScalingAdjustment: 2 - MetricIntervalLowerBound: 5000 ScalingAdjustment: 4

CloudWatch Alarm

HighCpuAlarm: Type: AWS::CloudWatch::Alarm Properties: AlarmName: !Sub "${AWS::StackName}-high-cpu" AlarmDescription: CPU utilization above threshold MetricName: CPUUtilization Namespace: AWS/ECS Dimensions: - Name: ClusterName Value: !Ref ECSClusterName - Name: ServiceName Value: !Ref ECSServiceName Statistic: Average Period: 60 EvaluationPeriods: 2 Threshold: 80 ComparisonOperator: GreaterThanThreshold AlarmActions: - !Ref RequestCountScalingPolicy

AutoScalingRoleArn: Type: AWS::IAM::Role Properties: RoleName: !Sub "${AWS::StackName}-autoscaling-role" AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: application-autoscaling.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceAutoscaleRole

Blue/Green Deployments with CodeDeploy

AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::CodeDeployBlueGreen

Description: ECS blue/green deployment with CodeDeploy

Parameters: Environment: Type: String Default: production AllowedValues: - staging - production

Resources:

ECS Cluster

ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub "${AWS::StackName}-cluster"

Task Definition (Blue)

TaskDefinitionBlue: Type: AWS::ECS::TaskDefinition Properties: Family: blue-task Cpu: "512" Memory: "1024" NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ContainerDefinitions: - Name: web Image: !Ref BlueImage Cpu: 256 Memory: 512 PortMappings: - ContainerPort: 80 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: blue

Task Definition (Green)

TaskDefinitionGreen: Type: AWS::ECS::TaskDefinition Properties: Family: green-task Cpu: "512" Memory: "1024" NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ContainerDefinitions: - Name: web Image: !Ref GreenImage Cpu: 256 Memory: 512 PortMappings: - ContainerPort: 80 LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref LogGroup awslogs-region: !Ref AWS::Region awslogs-stream-prefix: green

Task Set (Blue)

TaskSetBlue: Type: AWS::ECS::TaskSet Properties: Cluster: !Ref ECSCluster Service: !Ref ECSService TaskDefinition: !Ref TaskDefinitionBlue Scale: Unit: PERCENT Value: 100

Task Set (Green)

TaskSetGreen: Type: AWS::ECS::TaskSet Properties: Cluster: !Ref ECSCluster Service: !Ref ECSService TaskDefinition: !Ref TaskDefinitionGreen Scale: Unit: PERCENT Value: 0

ECS Service

ECSService: Type: AWS::ECS::Service Properties: ServiceName: !Sub "${AWS::StackName}-service" Cluster: !Ref ECSCluster TaskDefinition: !Ref TaskDefinitionBlue DesiredCount: 2 LaunchType: FARGATE LoadBalancers: - ContainerName: web ContainerPort: 80 TargetGroupArn: !Ref BlueTargetGroup

Target Groups

BlueTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub "${AWS::StackName}-blue-tg" Port: 80 Protocol: HTTP VpcId: !Ref VpcId HealthCheckPath: /health TargetType: ip

GreenTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub "${AWS::StackName}-green-tg" Port: 80 Protocol: HTTP VpcId: !Ref VpcId HealthCheckPath: /health TargetType: ip

Listener

ProductionListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref BlueTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 80 Protocol: HTTP

TestListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref BlueTargetGroup LoadBalancerArn: !Ref ApplicationLoadBalancer Port: 8080 Protocol: HTTP

ApplicationLoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub "${AWS::StackName}-alb" Scheme: internet-facing Subnets: !Ref PublicSubnets SecurityGroups: - !Ref AlbSecurityGroup

AlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub "${AWS::StackName}-alb-sg" GroupDescription: ALB security group VpcId: !Ref VpcId SecurityGroupIngress: # HTTP from anywhere - public-facing ALB requires this - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: HTTP for public web traffic # Test traffic from internal network only - IpProtocol: tcp FromPort: 8080 ToPort: 8080 CidrIp: 10.0.0.0/16 Description: Test traffic from internal VPC

LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "/ecs/${AWS::StackName}" RetentionInDays: 30

Hooks: BlueGreenHook: Type: AWS::CodeDeploy::BlueGreen Properties: TrafficRoutingConfig: Type: TimeBasedCanary TimeBasedCanary: StepPercentage: 15 BakeTimeMins: 5 AdditionalOptions: TerminationWaitTimeInMinutes: 5 ServiceRole: !Ref CodeDeployRoleArn Applications: - Target: Type: AWS::ECS::Service LogicalID: ECSService ECSAttributes: TaskDefinitions: - TaskDefinitionBlue - TaskDefinitionGreen TaskSets: - TaskSetBlue - TaskSetGreen TrafficRouting: ProdTrafficRoute: Type: AWS::ElasticLoadBalancingV2::Listener LogicalID: ProductionListener TestTrafficRoute: Type: AWS::ElasticLoadBalancingV2::Listener LogicalID: TestListener TargetGroups: - BlueTargetGroup - GreenTargetGroup

CodeDeployRoleArn: Value: !Sub "arn:aws:iam::${AWS::AccountId}:role/service-role/AmazonCodeDeployRoleForECS"

Conditions and Transforms

Conditions for Environment-Specific Resources

AWSTemplateFormatVersion: 2010-09-09 Description: ECS with conditional resources

Parameters: Environment: Type: String Default: dev AllowedValues: - dev - staging - production

EnableServiceDiscovery: Type: String Default: true AllowedValues: - true - false

EnableSpotInstances: Type: String Default: false AllowedValues: - true - false

Conditions: IsProduction: !Equals [!Ref Environment, production] IsStaging: !Equals [!Ref Environment, staging] UseServiceDiscovery: !Equals [!Ref EnableServiceDiscovery, true] UseSpotInstances: !And - !Equals [!Ref EnableSpotInstances, true] - !Not [!Equals [!Ref Environment, production]]

Resources:

Always created

ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub "${AWS::StackName}-${Environment}"

Conditionally created service discovery

ServiceDiscoveryNamespace: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Condition: UseServiceDiscovery Properties: Name: !Sub "${Environment}.internal" VpcId: !Ref VpcId

Conditionally created DLQ

DeadLetterQueue: Type: AWS::SQS::Queue Condition: IsProduction Properties: QueueName: !Sub "${AWS::StackName}-dlq"

Transforms for Code Reuse

AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31

Description: Using SAM Transform for ECS

Globals: Function: Timeout: 30 Runtime: python3.11 Tracing: Active

Resources: TaskFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub "${AWS::StackName}-task-processor" Handler: task_handler.handler Policies: - ECSFullAccess Events: TaskQueue: Type: SQS Properties: Queue: !GetAtt TaskQueue.Arn BatchSize: 10

TaskQueue: Type: AWS::SQS::Queue Properties: QueueName: !Sub "${AWS::StackName}-tasks" VisibilityTimeout: 360

CloudFormation Best Practices

Stack Policies

Stack Policies prevent accidental updates to critical infrastructure resources. Use them to protect ECS clusters, task definitions, and production services from unintended modifications.

AWSTemplateFormatVersion: 2010-09-09 Description: ECS stack with protective policy

Resources: ECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub "${AWS::StackName}-cluster"

EcsService: Type: AWS::ECS::Service Properties: ServiceName: !Sub "${AWS::StackName}-service" Cluster: !Ref ECSCluster TaskDefinition: !Ref TaskDefinition DesiredCount: 2

TaskDefinition: Type: AWS::ECS::TaskDefinition Properties: Family: web-app-task Cpu: "512" Memory: "1024" NetworkMode: awsvpc RequiresCompatibilities: - FARGATE ContainerDefinitions: - Name: web Image: !Ref ContainerImage Cpu: 256 Memory: 512 PortMappings: - ContainerPort: 80

Stack Policy JSON (apply via AWS Console or CLI)

StackPolicy: Statement: # Allow all updates to task definitions (needed for deployments) - Effect: Allow Action: Update:Modify Resource: "*"

# Prevent modifications to the ECS cluster
- Effect: Deny
  Action:
    - Update:Modify
    - Update:Replace
    - Delete
  Resource: "*"
  Condition:
    StringEquals:
      ResourceType:
        - AWS::ECS::Cluster

# Prevent deletion of the ECS service in production
- Effect: Deny
  Action: Delete
  Resource: "*"
  Condition:
    StringEquals:
      ResourceType:
        - AWS::ECS::Service
    StringEqualsIfExists:
      Environment: production

Apply stack policy using CLI:

aws cloudformation set-stack-policy
--stack-name my-ecs-stack
--stack-policy-body file://stack-policy.json

Termination Protection

Enable termination protection to prevent accidental deletion of production stacks. This is critical for ECS infrastructure that handles production workloads.

Enable termination protection when creating a stack

aws cloudformation create-stack
--stack-name production-ecs
--template-body file://ecs-template.yaml
--enable-termination-protection

Enable termination protection on existing stack

aws cloudformation update-termination-protection
--stack-name production-ecs
--enable-termination-protection

Disable termination protection (requires explicit confirmation)

aws cloudformation update-termination-protection
--stack-name production-ecs
--no-enable-termination-protection

In templates, add to resources that should be preserved:

Resources: ProductionECSService: Type: AWS::ECS::Service DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: # ... service configuration

Drift Detection

CloudFormation drift detection identifies when infrastructure has been modified outside of CloudFormation. Regular drift checks ensure your ECS infrastructure remains consistent with your templates.

Detect drift on a stack

aws cloudformation detect-stack-drift
--stack-name my-ecs-stack

Get drift detection status

aws cloudformation describe-stack-drift-detection-status
--stack-drift-detection-id <detection-id>

Get stack resources with drift status

aws cloudformation describe-stack-resource-drifts
--stack-name my-ecs-stack

Check specific resource drift

aws cloudformation detect-stack-resource-drift
--stack-name my-ecs-stack
--logical-resource-id EcsService

Drift status values:

  • IN_SYNC: Resource matches template

  • MODIFIED: Resource has been changed outside CloudFormation

  • DELETED: Resource exists in template but not in AWS

  • NOT_CHECKED: Resource not included in drift detection

Automated drift detection schedule:

Use AWS Config rules for continuous drift monitoring

Resources: CloudFormationStackDriftDetectionConfigRule: Type: AWS::Config::ConfigRule Properties: ConfigRuleName: cf-drift-detection Description: Detect CloudFormation stack drift Source: Owner: AWS SourceIdentifier: CFN_STACK_DRIFT_DETECTION_CHECK Scope: ComplianceResourceTypes: - AWS::CloudFormation::Stack

Change Sets

Change Sets provide a preview of stack changes before execution. Always use change sets for production deployments to review and validate modifications.

1. Create a change set (dry-run)

aws cloudformation create-change-set
--stack-name production-ecs
--template-body file://ecs-template.yaml
--change-set-name production-ecs-changeset
--capabilities CAPABILITY_IAM
--parameters ParameterKey=Environment,ParameterValue=production

2. Wait for change set creation

aws cloudformation wait change-set-create-complete
--stack-name production-ecs
--change-set-name production-ecs-changeset

3. View change set (review changes)

aws cloudformation describe-change-set
--stack-name production-ecs
--change-set-name production-ecs-changeset
--output table

4. Execute change set (if changes are correct)

aws cloudformation execute-change-set
--stack-name production-ecs
--change-set-name production-ecs-changeset

5. Delete change set (if not executing)

aws cloudformation delete-change-set
--stack-name production-ecs
--change-set-name production-ecs-changeset

Change Set for nested stacks:

aws cloudformation create-change-set
--stack-name parent-stack
--template-body file://parent-template.yaml
--change-set-name parent-changeset
--nested-stack-resolution TEMPLATE

Change Set Template Review

When reviewing change sets, examine:

  • Resource modifications: Changes to ECS services may cause service disruptions

  • Deletions: Ensure no critical resources are marked for deletion

  • IAM changes: New or modified roles require manual approval

  • Parameter changes: Verify parameter overrides are correct

  • Replace operations: Resources marked for replacement may cause downtime

Security Best Practices

Security

  • Use IAM roles with minimum required permissions (Task Execution Role, Task Role)

  • Encrypt container images with ECR

  • Use Secrets Manager for sensitive data (passwords, API keys)

  • Configure security groups with restrictive rules

  • Use private subnets for ECS services

  • Enable Container Insights for monitoring

  • Implement task execution role with specific permissions

Security Group Best Practices

For public-facing ALBs, HTTP/HTTPS from 0.0.0.0/0 is often necessary. However, enhance security with:

AlbSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupName: !Sub "${AWS::StackName}-alb-sg" GroupDescription: ALB security group - restrict in production VpcId: !Ref VpcId SecurityGroupIngress: # HTTP from anywhere - required for public ALB - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 Description: HTTP for public web traffic # HTTPS from anywhere - required for public ALB - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 Description: HTTPS for secure public web traffic

Security enhancements for production:

1. Use AWS WAF to filter malicious traffic

2. Place ALB behind CloudFront for additional protection

3. Use AWS Shield for DDoS protection

4. Implement rate limiting

5. Use AWS Network Firewall for advanced filtering

Performance

  • Choose CPU and memory based on container profiling

  • Use right-sizing for EC2 instances or Fargate

  • Implement auto scaling based on metrics (CPU, Memory, Request count)

  • Optimize container startup with appropriate health checks

  • Use task placement strategies for optimization

  • Consider Spot instances for non-critical workloads

Monitoring

  • Enable Container Insights for detailed metrics

  • Configure CloudWatch alarms for CPU, memory, and error rates

  • Implement structured logging with awslogs driver

  • Use X-Ray for distributed tracing

  • Configure task-level monitoring

Deployment

  • Use blue/green deployments with CodeDeploy for production

  • Implement deployment circuit breaker

  • Use change sets before deployment

  • Organize stacks by lifecycle and ownership

  • Test task definitions locally before deployment

Related Resources

  • ECS Documentation

  • ECS Task Definitions

  • ECS Services

  • AWS CloudFormation User Guide

  • ECS Blue/Green Deployments

  • CloudFormation Stack Policies

  • CloudFormation Drift Detection

  • CloudFormation Change Sets

Additional Files

For complete details on resources and their properties, see:

  • REFERENCE.md - Detailed reference guide for all CloudFormation resources

  • EXAMPLES.md - Complete production-ready examples

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

shadcn-ui

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tailwind-css-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

unit-test-bean-validation

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

react-patterns

No summary provided by upstream source.

Repository SourceNeeds Review