Overview
The ECS Cluster resource deploys containerised applications on AWS ECS with a multi-service architecture. A single cluster hosts one or more services that share a load balancer. Each service declares its own capacity provider ("FARGATE", "FARGATE_SPOT" or "EC2"), containers, CPU/memory, scaling rules and alarms.
Resource Class
EcsCluster is the default export from the module. The deep lib/... path is a published subpath of the package and is the only import that resolves for this construct, because the package root barrel re-exports networking, storage, CDN, messaging, organisation and the EC2 compute construct, but not the ECS or Lambda constructs.
The scaffolded
fjall/<app>/infrastructure.ts that the CLI maintains never
imports a construct class directly. It imports App and the *Factory
symbols from the package root, and the factory builds this construct for you.
Reach for the class directly only when you are writing infrastructure by hand.Basic Usage
Single Service
Multi-Service with Routing
Worker Cluster (No Load Balancer)
Cluster Props
Cluster Configuration
Custom Domains
A custom domain needs a hosted zone that already exists. Fjall never creates a hosted zone inside an application stack: such a zone would be undelegated, so ACM DNS validation hangs until CloudFormation rolls back, and destroying the stack would delete the zone. Name the zone source one of three ways.domainConfig.domainName takes precedence over cluster.domain, so set the name once in domainConfig and drop cluster.domain entirely. The domain must sit inside the zone, checked on a dot boundary, otherwise synth fails.
Other domainConfig fields:
Service Props
Each entry in theservices array carries these properties.
Routing Configuration
Container Configuration
Each entry in a service’scontainers array carries these properties.
The first container with a
port is the primary container and receives load balancer traffic. Every other container acts as a sidecar.
dependsOn is resolved at synth time against the container names in the same service, so a typo fails the synth rather than the deploy.
Capacity Providers
FARGATE
Serverless containers with no instances to manage.FARGATE_SPOT
Up to 70% cheaper than standard Fargate. Tasks may be interrupted.EC2
Run containers on EC2 instances you control. Task sizing moves toec2Config: service-level cpu always throws on EC2 capacity, and service-level memoryLimitMiB throws unless it exactly mirrors ec2Config.memoryLimitMiB.
EC2 Capacity Configuration
Slot Semantics
Every CloudFormation identity surface for the ASG (logical-ID prefixes, physical service name, launch-template name) derives from the slot anchor, never from the hardware config. ChanginginstanceType, memoryLimitMiB or any other property updates the ASG in place instead of replacing it.
Services that declare the same slot share one ASG and must agree on every property field, checked at synth. Give a service its own slot when it needs different hardware, and always when it declares a persistentDataVolume, since a single-attach EBS volume implies a singleton service.
Auto-Scaling
OmitscalingType to disable auto-scaling entirely. No scalable target is registered and minCapacity / maxCapacity have no effect.
CPU-Based Scaling
Memory-Based Scaling
Queue-Depth Scaling
ScalingType.QUEUE drives a step-scaling policy on SQS backlog. It is the only mode that wakes a service from desiredCount: 0, because CPU and memory target-tracking publish no datapoint at zero running tasks.
Three synth-time guards keep the shapes honest:
desiredCount: 0withScalingType.CPUorScalingType.MEMORYthrows, because nothing could ever wake the service.ScalingType.QUEUEwith noqueueScaling.queuesthrows.queueScalingset on any other scaling mode throws.
Secrets and Environment Variables
Environment Variables
SSM Parameter Store Secrets
Secrets Manager Imports
id is required by SecretImport, and you supply exactly one of name or arn. Use name for a secret in the deploy account and region: Fjall resolves it to a complete ARN at deploy time. Use arn for a cross-account or cross-region secret the deploy identity cannot DescribeSecret. field is optional and pulls a single JSON key out of the secret rather than the whole value.
Multi-Container Tasks
The first container with aport is the primary container. Additional containers run as sidecars.
Building From a Dockerfile
Setdocker to build the service image instead of pulling a pre-built URI. The two are mutually exclusive: docker builds, image pulls.
target is set, the content-hash image tag becomes <service>-<target>-sha-<12 hex>.
buildArgs are public: they are baked into the image and recorded in docker history and provenance, which is what makes them the only channel that reaches a Vite client bundle. buildSecrets are references resolved just in time and mounted by BuildKit, so the value never lands in a layer or the manifest. Put credentials in buildSecrets, never in buildArgs.
Connections
Services declare the resources they reach. The construct creates security group rules for network resources and IAM grants for storage resources.remoteConnections. Each spec resolves at synth time into ${PREFIX}_HOST and ${PREFIX}_PORT environment variables merged into every container in the service.
Alarms
Alarms are created only when the cluster carries analertsTopic. Each service then gets CPU, memory and running-task alarms, plus 5xx error-rate and p99 response-time alarms when it sits behind the ALB.
TargetResponseTime without any request being slow.
Methods
Get Load Balancer
Get Service
Get All Services
Get Cluster
Get URL
Complete Example
Best Practices
- Pick FARGATE for production workloads that need task-level isolation.
- Pick FARGATE_SPOT for batch processing and fault-tolerant workloads.
- Pick EC2 when you need specific hardware, and size the container through
ec2Config.memoryLimitMiB. - Scale production services from at least 2 tasks, and use
ScalingType.QUEUEfor anything that should idle at zero. - Put sensitive values in
secretsorsecretsImport, never inenvironmentordocker.buildArgs. - Declare
routingwhenever a cluster runs more than one service with a port. - Declare a container
healthCheckfor services with no ALB target group, so the circuit breaker can see post-start exits. - Set
alertsTopicon every production cluster, andcontainerInsights: truewhen you want the running-tasks alarm. - Give each hardware profile its own
slotso instance-type changes update the ASG in place.
Next Steps
Compute Factory
Provision an ECS cluster through the higher-level compute factory pattern.
Deployment Safety
Tune the circuit breaker, schema gate and task-stop watchdog.
Application Load Balancer
Configure the ALB that fronts your cluster services.
ECR Repository
Store the container images your services pull at deploy time.