Skip to content

ECS clusters in AWS provide compute capacity for running containerized applications. Stackattack’s cluster component provides an easy way to set up working ECS clusters for running applications on EC2 instances with auto-scaling and private inter-service communication.

Stackattack creates ECS clusters with:

  • EC2 instances used for compute. By default, the configuration will use spot instances. Pass noSpot: true to disable spot instances, or onDemandPercentage with a percentage value to split your EC2 instances between on demand and spot. The number of instances will always match the requirements of your cluster (within the constraints you set via minSize (default 0) and maxSize (default 1)). Currently Fargate is not supported.
  • A private DNS namespace is created so that your services can communicate internally via ECS service discovery. ECS service connect is currently not supported.
import * as saws from "@stackattack/aws";
const ctx = saws.context();
const vpc = saws.vpc(ctx);
const compute = saws.cluster(ctx, { network: vpc.network("private") });
export const clusterName = compute.cluster.name;

After deploying a cluster, you can deploy services into it to run code in docker containers.

SSH Access to EC2 Instances: NOTE: if your instances are within a private subnet (as is likely the case), you need a way to access your instances. If you created your vpc with the vpc component, an EC2 instance connect endpoint is set up automatically.

Terminal window
# Connect to an instance using Instance Connect (no key pairs needed)
aws ec2-instance-connect ssh --instance-id i-1234567890abcdef0 --region us-east-1
# If you do not have an EC2 instance connect endpoint but have direct access to your instance (e.g. via a VPN), pass --connection-type direct
aws ec2-instance-connect ssh --instance-id i-1234567890abcdef0 --region us-east-1 --connection-type direct

Clusters work together with other Stackattack components:

  • vpc - Provides networking foundation with private/public subnets
  • service - Runs containerized applications on the cluster
  • load-balancer - Routes external traffic to services on the cluster

ECS cluster costs depend on the underlying EC2 instances and are usage-based:

  • EC2 instances - This will depend on your configuration. Your auto-scaling cluster will scale up and down based on the desired capacity of the services you have deployed, meaning instances will be terminated if they are unused and created as you deploy and scale your services. By default Stackattack will use spot instances with an ARM architecture, 1-2 CPUs, 2-4 GB of memory, and a 2:1 memory:cpu ratio (this uses a mixed instances policy so the specific instance type(s) that will be launched is not known. This allows for greater availability of spot instances, as it does not rely as much on the capacity of any one specific instance type ). This can be configured with the instances parameter. See the Spot Instance Pricing documentation for specific figures.

  • EBS storage - Each instance gets 25GB of storage by default (~$2/month per instance). Block devices are deleted when instances are terminated.

  • Data transfer - Service-to-service communication within the VPC is free. External data transfer follows standard AWS rates (~$0.09/GB out).

  • Service Discovery - The private DNS namespace is free.

Cost optimization strategies:

  • Use spot instances for non-critical workloads (up to 90% savings)
  • Enable cluster auto-scaling to scale to zero during low usage
  • Monitor instance utilization and rightsize instance types
  • Use service placement strategies to maximize instance utilization

See EC2 Pricing for current rates.

Creates a complete ECS cluster with capacity provider, auto scaling group, and private namespace.

function cluster(ctx: Context, args: ClusterArgs): ClusterOutput
  • ctx (Context) - The context for resource naming and tagging
  • args (ClusterArgs) - Arguments for cluster configuration
  • (ClusterOutput) - Creates a complete ECS cluster with capacity provider, auto scaling group, and private namespace.

Creates ECS cluster capacity including auto scaling group and capacity provider.

function clusterCapacity(ctx: Context, args: ClusterCapacityArgs): { autoScalingGroup: Group; capacityProvider: CapacityProvider }
  • ({ autoScalingGroup: Group; capacityProvider: CapacityProvider }) - Creates ECS cluster capacity including auto scaling group and capacity provider.

Generates a bash initialization script for ECS cluster instances.

function clusterInstanceInitScript(args: ClusterInstanceInitScriptArgs): Output<string>
  • (Output<string>) - Generates a bash initialization script for ECS cluster instances.

Creates an IAM role for ECS cluster instances with necessary policies attached.

function clusterInstanceRole(ctx: Context, args?: ClusterInstanceRoleArgs): Role
  • (Role) - Creates an IAM role for ECS cluster instances with necessary policies attached.

Creates a security group for cluster instances with SSH access and full egress.

function clusterSecurityGroup(ctx: Context, args: ClusterSecurityGroupArgs): SecurityGroup
  • (SecurityGroup) - Creates a security group for cluster instances with SSH access and full egress.

Converts a ClusterOutput to ClusterIds by extracting resource identifiers.

function clusterToIds(cluster: ClusterOutput): ClusterIds
  • cluster (ClusterOutput) - The cluster output containing all resources
  • (ClusterIds) - Converts a ClusterOutput to ClusterIds by extracting resource identifiers.

Extracts the capacity provider ID from a CapacityProviderInput.

function getCapacityProviderId(input: Input<CapacityProviderInput>): Output<string>
  • (Output<string>) - Extracts the capacity provider ID from a CapacityProviderInput.

Retrieves the full cluster attributes from a ClusterInput.

function getClusterAttributes(input: Input<ClusterInput>): Output<Cluster | GetClusterResult>
  • input (Input<ClusterInput>) - The cluster input to get attributes from
  • (Output<Cluster | GetClusterResult>) - Retrieves the full cluster attributes from a ClusterInput.

Extracts the cluster ID from a ClusterInput.

function getClusterId(input: Input<ClusterInput>): Output<string>
  • input (Input<ClusterInput>) - The cluster input to extract the ID from
  • (Output<string>) - Extracts the cluster ID from a ClusterInput.

Extracts the HTTP namespace ID from an HttpNamespaceInput.

function getHttpNamespaceId(input: Input<HttpNamespaceInput>): Output<string>
  • (Output<string>) - Extracts the HTTP namespace ID from an HttpNamespaceInput.

Gets the architecture (e.g., x86_64, arm64) for a given EC2 instance type.

function getInstanceTypeArchitecture(instanceType: Input<string>): Output<string>
  • instanceType (Input<string>) - The EC2 instance type to get the architecture for
  • (Output<string>) - Gets the architecture (e.g., x86_64, arm64) for a given EC2 instance type.

Retrieves the full private DNS namespace attributes from a PrivateDnsNamespaceInput.

function getPrivateDnsNamespaceAttributes(input: Input<PrivateDnsNamespaceInput>): Output<PrivateDnsNamespace | GetDnsNamespaceResult>
  • (Output<PrivateDnsNamespace | GetDnsNamespaceResult>) - Retrieves the full private DNS namespace attributes from a PrivateDnsNamespaceInput.

Extracts the private DNS namespace ID from a PrivateDnsNamespaceInput.

function getPrivateDnsNamespaceId(input: Input<PrivateDnsNamespaceInput>): Output<string>
  • (Output<string>) - Extracts the private DNS namespace ID from a PrivateDnsNamespaceInput.

Arguments for creating a complete ECS cluster with capacity.

  • diskSize? (number) - Size of the root disk in GB
  • instances? (ClusterInstancesConfig) - Instance configuration (type or requirements)
  • maxSize? (Input<number>) - Maximum number of instances in the auto scaling group; defaults to minSize unless minSize is 0, then it defaults to 1
  • minSize? (Input<number>) - Minimum number of instances in the auto scaling group; defaults to 0
  • network (NetworkInput) - Network configuration for the cluster
  • noPrefix? (boolean) - Whether to skip adding a prefix to resource names
  • noSpot? (boolean) - Whether to disable spot instances
  • onDemandBase? (number) - Number of on-demand instances to maintain as base capacity
  • onDemandPercentage? (number) - Percentage of on-demand instances above base capacity
  • sourceSecurityGroupId? (Input<string>) - Security group ID that should be allowed SSH access to the instances
  • spotAllocationStrategy? (string) - Strategy for allocating spot instances

Arguments for creating cluster capacity including network and cluster references.

  • cluster (Input<ClusterInput>) - The ECS cluster to create capacity for
  • diskSize? (number) - Size of the root disk in GB
  • instances? (ClusterInstancesConfig) - Instance configuration (type or requirements)
  • maxSize? (Input<number>) - Maximum number of instances in the auto scaling group; defaults to minSize unless minSize is 0, then it defaults to 1
  • minSize? (Input<number>) - Minimum number of instances in the auto scaling group; defaults to 0
  • network (NetworkInput) - Network configuration for the cluster
  • noPrefix? (boolean) - Whether to skip adding a prefix to resource names
  • noSpot? (boolean) - Whether to disable spot instances
  • onDemandBase? (number) - Number of on-demand instances to maintain as base capacity
  • onDemandPercentage? (number) - Percentage of on-demand instances above base capacity
  • sourceSecurityGroupId? (Input<string>) - Security group ID that should be allowed SSH access to the instances
  • spotAllocationStrategy? (string) - Strategy for allocating spot instances

Configuration for cluster capacity and scaling behavior.

  • diskSize? (number) - Size of the root disk in GB
  • instances? (ClusterInstancesConfig) - Instance configuration (type or requirements)
  • maxSize? (Input<number>) - Maximum number of instances in the auto scaling group; defaults to minSize unless minSize is 0, then it defaults to 1
  • minSize? (Input<number>) - Minimum number of instances in the auto scaling group; defaults to 0
  • noPrefix? (boolean) - Whether to skip adding a prefix to resource names
  • noSpot? (boolean) - Whether to disable spot instances
  • onDemandBase? (number) - Number of on-demand instances to maintain as base capacity
  • onDemandPercentage? (number) - Percentage of on-demand instances above base capacity
  • sourceSecurityGroupId? (Input<string>) - Security group ID that should be allowed SSH access to the instances
  • spotAllocationStrategy? (string) - Strategy for allocating spot instances

Interface containing the IDs of all cluster-related resources.

  • autoScalingGroup (Output<string>) - The auto scaling group ID
  • capacityProvider (Output<string>) - The capacity provider name
  • cluster (Output<string>) - The cluster ID
  • privateNamespace (Output<string>) - The private namespace name

Arguments for generating a cluster instance initialization script.

  • cluster (Input<ClusterInput>) - The ECS cluster to join
  • paramName (Input<string>) - Name of the SSM parameter containing CloudWatch agent configuration

Arguments for creating a cluster instance role.

  • noPrefix? (boolean) - Whether to skip adding a prefix to the resource name

Configuration for using a specific EC2 instance type.

  • type (Input<string>) - The specific EC2 instance type to use

Output interface containing all cluster-related resources.

  • autoScalingGroup (Group) - The auto scaling group resource
  • capacityProvider (CapacityProvider) - The capacity provider resource
  • cluster (Cluster) - The ECS cluster resource
  • privateNamespace (PrivateDnsNamespace) - The private DNS namespace resource

Configuration for using instance requirements instead of specific instance types.

  • allowNoEniTrunking? (boolean) - Whether to allow instance types that don’t support ENI trunking
  • architecture (Input<string>) - The CPU architecture (e.g., x86_64, arm64)

Input interface for cluster resources.

Arguments for creating a cluster security group.

  • noInstanceConnect? (boolean) - Indicate whether the instances should be configured to allow SSH traffic from EC2 instance connect
  • noPrefix? (boolean) - Whether to skip adding a prefix to the resource name
  • sourceSecurityGroupId? (Input<string>) - Source security group ID to allow access from (defaults to VPC default security group)
  • vpc (Input<VpcInput>) - The VPC to create the security group in

Union type representing different ways to specify an ECS capacity provider. Can be a capacity provider name (string) or an actual CapacityProvider resource.

type CapacityProviderInput = string | aws.ecs.CapacityProvider

Union type representing different ways to specify an ECS cluster. Can be a cluster name (string), an actual Cluster resource, cluster data, or cluster output.

type ClusterInput = string | aws.ecs.Cluster | aws.ecs.GetClusterResult | ClusterOutput

Union type representing different ways to specify an HTTP namespace. Can be a namespace name (string), an actual HttpNamespace resource, or namespace data.

type HttpNamespaceInput = string | aws.servicediscovery.HttpNamespace | aws.servicediscovery.GetHttpNamespaceResult

Union type representing different ways to specify a private DNS namespace. Can be a namespace name (string) or an actual PrivateDnsNamespace resource.

type PrivateDnsNamespaceInput = string | aws.servicediscovery.PrivateDnsNamespace