HOW-TO: Deploy Containerized Apps with AWS ECS Express Mode
Complete guide to AWS ECS Express Mode β the simplified way to deploy production containerized applications. Learn the architecture, auto-provisioned resources, networking, scaling, and cost optimization.
HOW-TO: Deploy Containerized Apps with AWS ECS Express Mode
Overview
Amazon ECS Express Mode reduces the complexity of deploying containerized applications by providing sensible defaults and automating the configuration of supporting AWS services. Instead of managing hundreds of configuration parameters across multiple services, an Express Mode service requires only a container image, a task execution role, and an infrastructure role to get started.
What you'll learn:
- Express Mode architecture and auto-provisioned resources
- Cluster, task definition, and container defaults
- Networking: VPC, subnets, security groups, load balancers
- Auto scaling configuration and policies
- IAM roles and permissions
- Resource sharing and cost optimization
- Customization options beyond defaults
Why Express Mode matters:
- Zero infrastructure management β no EC2 instances to provision
- Production-ready defaults (HTTPS, canary deployments, auto scaling)
- Cost optimization through automatic load balancer sharing
- Operational best practices built in (health checks, logging, graceful shutdown)
- Ideal for web applications, APIs, and microservices
Architecture Overview
Express Mode automatically creates and wires together a complete production stack. The following diagram shows the high-level architecture:
Resource Creation Flow
When you create an Express Mode service, the following resources are automatically provisioned:
Cluster Defaults
Express Mode uses the ECS default cluster with Fargate capacity providers.
| Setting | Default | Configurable? |
|---|---|---|
clusterName | default | β
Yes (console or CLI --cluster) |
capacityProviders | ["FARGATE"] | β Set by Express Mode |
# Customize cluster name via CLI
aws ecs create-express-gateway-service \
--cluster my-custom-cluster \
--image my-repo/my-app:latest \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
Task Definition Defaults
Express Mode creates a task definition with production-ready defaults:
Configurable Parameters
| Parameter | Default | Description |
|---|---|---|
cpu | 1024 (1 vCPU) | CPU units allocated to the task |
memory | 2048 (2 GB) | Memory allocated to the task |
port | 80 | Default container traffic port |
Fixed Defaults (set by Express Mode)
| Parameter | Value |
|---|---|
networkMode | awsvpc |
operatingSystemFamily | LINUX |
cpuArchitecture | X86_64 |
requiresCompatibilities | ["FARGATE"] |
platformVersion | LATEST |
essential | true |
protocol | tcp |
name | Main |
versionConsistency | enabled |
initProcessEnabled | true |
stopTimeout | 30 seconds |
# Customize CPU and memory via CLI
aws ecs create-express-gateway-service \
--image my-repo/my-app:latest \
--cpu 2048 \
--memory 4096 \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
Container Definition Defaults
The primary container is configured with these defaults:
| Setting | Default | Notes |
|---|---|---|
name | Main | β οΈ Changing this may break Express Mode updates |
essential | true | Container is required for task health |
protocol | tcp | Load balancer communication protocol |
versionConsistency | enabled | Resolves image tags to digest IDs |
initProcessEnabled | true | Docker init process support |
stopTimeout | 30s | Time between SIGTERM and SIGKILL |
Logging Defaults
All container logs are sent to CloudWatch Logs with non-blocking mode:
| Setting | Default | Configurable? |
|---|---|---|
logDriver | awslogs | β |
awslogs-group | /aws/ecs/<cluster>/<name>-#### | β |
awslogs-stream-prefix | ecs | β |
awslogs-region | Current region | β |
mode | non-blocking | β |
max-buffer-size | 25m | β |
# Customize log group and stream prefix
aws ecs create-express-gateway-service \
--image my-repo/my-app:latest \
--primary-container 'awsLogsConfiguration=[{logGroup="/my/custom/logs",logStreamPrefix="myprefix"}]' \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
Service Defaults
The ECS service is created with canary deployments and auto scaling:
| Setting | Default | Notes |
|---|---|---|
serviceName | Customer-provided or derived from image | Create-only |
cluster | default (or custom) | Create-only |
desiredCount | 1 (MinTasks) | Configurable |
availabilityZoneRebalancing | true | |
deploymentConfiguration | Canary | Cannot be changed after creation |
healthCheckGracePeriodSeconds | 300 | Aligns with ELB defaults |
schedulingStrategy | REPLICA | |
propagateTags | SERVICE | Propagates tags to tasks |
Network Configuration
Subnets and VPC
Express Mode handles networking intelligently based on your subnet choices:
Requirements for default VPC:
- At least 2 public subnets
- At least 2 availability zones
- At least 8 free IPs per CIDR block per subnet
Security Groups
Express Mode creates two security groups automatically:
| Security Group | Inbound Rules | Outbound Rules |
|---|---|---|
| Load Balancer SG | HTTPS (443) from internet | Traffic to Service SG on container port (default 80) |
| Service SG | From Load Balancer SG only | Outbound to public internet |
# Provide custom security group (adds additional ingress path)
aws ecs create-express-gateway-service \
--image my-repo/my-app:latest \
--network-configuration '{"securityGroup": ["sg-xxxxxxx"]}' \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
Networking Architecture Diagram
IAM Roles
Express Mode requires two mandatory roles and supports one optional role:
Required Roles
| Role | Purpose | Managed Policy |
|---|---|---|
| Task Execution Role | Allows ECS to pull images, push logs | AmazonECSTaskExecutionRolePolicy |
| Infrastructure Role | Allows Express Mode to create resources | AmazonECSInfrastructureRoleforExpressGatewayServices |
Optional Role
| Role | Purpose |
|---|---|
| Task Role | Allows your application code to call AWS APIs from within the container |
Auto-Created Service Linked Roles
| Role | Purpose |
|---|---|
ecsServiceRoleForECS | Allows ECS to manage your cluster |
AWSServiceRoleForElasticLoadBalancing | Allows ELB to manage load balancing |
AWSServiceRoleForApplicationAutoScaling_ECSService | Allows Auto Scaling to manage task count |
# Include optional task role
aws ecs create-express-gateway-service \
--image my-repo/my-app:latest \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole \
--task-role-arn arn:aws:iam::123456789:role/MyAppTaskRole
Auto Scaling
Scaling Configuration
Express Mode uses Target Tracking Scaling to maintain optimal CPU utilization:
| Setting | Default | Configurable? |
|---|---|---|
autoScalingTargetValue | 60 (% CPU) | β |
autoScalingMetric | CPUUtilization | β (CPU, Memory, Request Count) |
desiredMinTaskCount | 1 | β |
desiredMaxTaskCount | 20 | β |
policyType | TargetTrackingScaling | β |
disableScaleIn | false | β |
Available Scaling Metrics
| Metric | Source | Max Capacity |
|---|---|---|
ECSServiceAverageCPUUtilization | CloudWatch | β |
ECSServiceAverageMemoryUtilization | CloudWatch | β |
ALBRequestCountPerTarget | Application Load Balancer | 65,536 requests/target/second |
# Customize scaling configuration
aws ecs create-express-gateway-service \
--image my-repo/my-app:latest \
--scaling-target '{"minTaskCount":3,"maxTaskCount":50}' \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
Auto Scaling Flow
Application Load Balancer Defaults
ALB Configuration
| Setting | Default | Notes |
|---|---|---|
scheme | Depends on subnets | Internet-facing (public) or Internal (private) |
ip-address-type | Depends on subnets | IPv4 or dual-stack (IPv4+IPv6) |
desync-mitigation-mode | Off | |
access-logs.enabled | false | |
listener.protocol | https | |
listener.port | 443 | |
listener.rule-type | host-header | Routes by host header |
Target Group Configuration
| Setting | Default |
|---|---|
health-check-path | / |
port | 80 (container port) |
health-check-port | 80 |
protocol | HTTP |
protocol-version | HTTP1 |
health-check-interval | 30s |
health-check-timeout | 5s |
healthy-threshold | 5 consecutive |
unhealthy-threshold | 2 consecutive |
target-type | ip |
ip-address-type | ipv4 |
Resource Sharing and Cost Optimization
Express Mode automatically optimizes costs by sharing resources across services:
Load Balancer Sharing
Key sharing behaviors:
- Up to 25 services in the same VPC share one Application Load Balancer
- Additional ALBs are provisioned automatically when you exceed 25 services
- When services are deleted, unused ALBs are automatically deprovisioned
- Cluster sharing β Express Mode services can share clusters with non-Express Mode services
Cost impact: Deploying more services in the same VPC reduces the effective cost per application due to ALB sharing.
Complete Deployment Example
Prerequisites
# Verify AWS CLI is configured
aws sts get-caller-identity
# Verify you have the required IAM roles created
aws iam get-role --role-name ECSExecutionRole
aws iam get-role --role-name ECSInfrastructureRole
# Verify default VPC has required subnets
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-default" "Name=map-public-ip-on-launch,Values=true"
Deploy a Service
# Minimal deployment (uses all defaults)
aws ecs create-express-gateway-service \
--image public.ecr.aws/nginx/nginx:latest \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole
# Full deployment with customizations
aws ecs create-express-gateway-service \
--image my-repo/my-app:v1.0 \
--service-name my-production-app \
--cluster production-cluster \
--cpu 2048 \
--memory 4096 \
--scaling-target '{"minTaskCount":2,"maxTaskCount":10}' \
--primary-container 'awsLogsConfiguration=[{logGroup="/apps/my-app",logStreamPrefix="prod"}]' \
--tags '{"Environment":"production","Team":"backend"}' \
--execution-role-arn arn:aws:iam::123456789:role/ECSExecutionRole \
--infrastructure-role-arn arn:aws:iam::123456789:role/ECSInfrastructureRole \
--task-role-arn arn:aws:iam::123456789:role/MyAppTaskRole
Verify Deployment
# Check service status
aws ecs describe-services \
--cluster default \
--services my-production-app
# Check load balancer DNS
aws elbv2 describe-load-balancers --query "LoadBalancers[].DNSName"
# Check auto scaling configuration
aws application-autoscaling describe-scalable-targets \
--service-name ecs \
--resource-id "service/default/my-production-app"
# View logs
aws logs describe-log-groups --log-group-name-prefix "/aws/ecs/"
Best Practices
β Do:
- Use Express Mode for standard web apps β fastest path to production
- Deploy multiple services in one VPC β leverage ALB sharing for cost savings
- Customize scaling limits β adjust min/max tasks based on your traffic patterns
- Use private subnets for sensitive workloads β internal ALB + NAT Gateway
- Add tags on creation β tags cannot be added after resource creation
- Monitor CloudWatch alarms β faulty deployment detection is built in
- Use custom log groups β organize logs by application for easier debugging
β Don't:
- Rename the default container β may break Express Mode update capability
- Mix subnet types in the same VPC β first service defines ALB type for all subsequent services
- Ignore the 25-service ALB limit β plan VPC strategy for large deployments
- Set min tasks to 0 β always maintain at least 1 task for availability
- Skip the infrastructure role β it is required for resource provisioning
Verification Checklist
After deploying your Express Mode service, verify:
# β Service is running with expected task count
aws ecs describe-services --cluster default --services <service-name> \
--query "services[0].runningCount"
# β Load balancer is active
aws elbv2 describe-load-balancers --query "LoadBalancers[].State.Code"
# β HTTPS is working
curl -I https://<alb-dns-name>
# β Auto scaling is configured
aws application-autoscaling describe-scaling-policies \
--service-name ecs \
--resource-id "service/default/<service-name>"
# β Logs are flowing to CloudWatch
aws logs describe-log-streams --log-group-name "/aws/ecs/default/<service-name>-####"
# β Health checks are passing
aws elbv2 describe-target-health --target-group-arn <tg-arn>
All checks pass = your Express Mode service is production-ready! β
Resources
- AWS ECS Express Mode Docs: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/express-service-work.html
- ECS Express Mode Overview: https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-express.html
- ECS Task Execution Role Policy: https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonECSTaskExecutionRolePolicy.html
- ECS Infrastructure Role Policy: https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonECSInfrastructureRoleforExpressGatewayServices.html
- Application Auto Scaling: https://docs.aws.amazon.com/autoscaling/application/userguide/what-is-application-auto-scaling.html
See Also
- Openclaw Ubuntu Setup Guide β Setting up Linux infrastructure for development
- Github Actions Docker Ecr β Building and pushing container images to ECR
- Cogvideox 2b Ubuntu Setup Guide β GPU container deployment on Ubuntu
π Referenced by
- πHOW-TO: Build a Multi-Model Routing Layer for AI Applications2026-06-17T00:00:00.000Z
- πWiki Index2026-06-17T00:00:00.000Z
- πHOW-TO: Set Up Claude Fable 5 for Agentic Coding Workflows2026-06-10T00:00:00.000Z
- π Journal Entry - June 9, 20262026-06-09T00:00:00.000Z
- π Journal Entry - June 8, 20262026-06-08T00:00:00.000Z
- π¬AI News Weekly: June 2 β June 8, 20262026-06-08T00:00:00.000Z
- πHOW-TO: AWS App Runner vs. ECS Express Mode β Comparison and Migration Guide2026-06-08T00:00:00.000Z