3. Provision an ECS Cluster
Goal
Deploy a containerized nginx application on AWS ECS Fargate to learn container orchestration fundamentals.
What you’ll learn:
- How to create ECS clusters, task definitions, and services
- When to use Fargate for serverless container workloads
- How IAM roles, security groups, and CloudWatch logging work together
- How to configure public network access for containers
Table of Contents
Prerequisites
Before starting, ensure you have:
- ✓ AWS account with administrative access
- ✓ AWS region selected (e.g., us-east-1 or eu-west-1)
- ✓ Default VPC exists in your region (AWS creates this automatically)
- ✓ Web browser for AWS Console access
Exercise Steps
Overview
- Create IAM Roles
- Create CloudWatch Log Group
- Create Security Group
- Create ECS Cluster
- Create Task Definition
- Create ECS Service
- Verify Deployment
Step 1: Create IAM Roles
ECS requires two IAM roles: a task execution role (for pulling images and writing logs) and a task role (for your application to access AWS services).
Create Task Execution Role
Navigate to IAM → Roles → Create role
Select “AWS service” → “Elastic Container Service” → “Elastic Container Service Task”
Click Next
Select the policy:
AmazonECSTaskExecutionRolePolicyClick Next
Enter role name:
dev-ecs-task-execution-roleClick Create role
Create Task Role
Click Create role again
Select “AWS service” → “Elastic Container Service” → “Elastic Container Service Task”
Click Next
Skip adding policies (nginx doesn’t need AWS API access)
Click Next
Enter role name:
dev-ecs-task-roleClick Create role
ℹ Concept Deep Dive
Task Execution Role is used by ECS infrastructure to pull container images from Docker Hub/ECR and write logs to CloudWatch. It needs the
AmazonECSTaskExecutionRolePolicymanaged policy.Task Role is used by your application code inside the container to access AWS services like S3, DynamoDB, etc. For nginx (a web server), we don’t need any AWS permissions, so this role has no policies attached.
âš Common Mistakes
- Selecting “Elastic Container Service” instead of “Elastic Container Service Task” as the use case
- Forgetting to attach
AmazonECSTaskExecutionRolePolicyto the execution role- Confusing which role does what (execution = infrastructure, task = application)
✓ Quick check: Two roles created with names
dev-ecs-task-execution-roleanddev-ecs-task-role
Step 2: Create CloudWatch Log Group
CloudWatch Logs captures container stdout/stderr for debugging and monitoring.
Navigate to CloudWatch → Log groups
Click Create log group
Enter log group name:
/ecs/dev/nginxSelect retention: “7 days”
Click Create
ℹ Concept Deep Dive
The naming pattern
/ecs/environment/serviceorganizes logs hierarchically. ECS automatically creates log streams within this group namedecs/nginx/<task-id>when containers start.âš Common Mistakes
- Missing the leading slash - must be
/ecs/dev/nginxnotecs/dev/nginx- Typos in the log group name - it must match exactly in the task definition
✓ Quick check: Log group
/ecs/dev/nginxvisible with 7-day retention
Step 3: Create Security Group
Security groups control network traffic to your containers. You need to allow HTTP (port 80) from the internet.
Navigate to EC2 → Security Groups
Click Create security group
Enter security group name:
dev-ecs-tasks-sgEnter description: “Security group for ECS tasks - allows HTTP from internet”
Select your default VPC
Under Inbound rules, click Add rule:
- Type:
HTTP - Source:
0.0.0.0/0 - Description:
Allow HTTP from internet
- Type:
Verify Outbound rules has:
- Type:
All traffic - Destination:
0.0.0.0/0
- Type:
Click Create security group
ℹ Concept Deep Dive
Inbound rules allow HTTP traffic (port 80) from anywhere (
0.0.0.0/0). For production, you’d restrict this or use a load balancer.Outbound rules allow all traffic so the container can pull images from Docker Hub and make any HTTP requests.
âš Common Mistakes
- Selecting the wrong VPC - it won’t appear during ECS service creation
- Forgetting the inbound rule for port 80 - nginx will be unreachable
✓ Quick check: Security group has HTTP inbound rule and all-traffic outbound rule
Step 4: Create ECS Cluster
An ECS cluster is a logical grouping of container resources. With Fargate, there are no servers to manage.
Navigate to Elastic Container Service → Clusters
Click Create cluster
Enter cluster name:
dev-clusterVerify no infrastructure is selected (Fargate is serverless)
Check “Use Container Insights”
Click Create
ℹ Concept Deep Dive
Fargate is serverless - AWS manages all infrastructure. You only define CPU, memory, and networking for your containers.
Container Insights provides CloudWatch metrics for CPU, memory, and network usage (~$0.30/month but valuable for learning).
âš Common Mistakes
- Trying to select EC2 infrastructure - leave it empty for Fargate-only
✓ Quick check: Cluster shows “ACTIVE” status
Step 5: Create Task Definition
A task definition is the blueprint for your container - it defines the image, CPU, memory, ports, and logging.
Navigate to Task definitions → Create new task definition
Enter task definition family:
dev-nginxUnder Infrastructure:
- Launch type:
AWS Fargate - OS/Architecture:
Linux/X86_64 - CPU:
.25 vCPU - Memory:
0.5 GB
- Launch type:
Under Task roles:
- Task execution role:
dev-ecs-task-execution-role - Task role:
dev-ecs-task-role
- Task execution role:
Under Container - 1:
- Name:
nginx - Image URI:
nginx:latest
- Name:
Under Port mappings, click Add:
- Container port:
80 - Protocol:
TCP - App protocol:
HTTP
- Container port:
Expand Log collection:
- Check “Use log collection”
- Log driver:
AWS CloudWatch - awslogs-group:
/ecs/dev/nginx - awslogs-region: (your region, auto-filled)
- awslogs-stream-prefix:
ecs
Click Create
ℹ Concept Deep Dive
CPU and Memory: Fargate has specific valid combinations. We use the minimum (0.25 vCPU, 0.5 GB) because nginx is lightweight and this is the cheapest option (~$10/month for 24/7).
Network mode: Fargate uses
awsvpcautomatically - each task gets its own elastic network interface (ENI) with a unique IP address.Log configuration: The awslogs driver sends container stdout/stderr directly to CloudWatch. The stream prefix creates streams as
ecs/nginx/<task-id>.âš Common Mistakes
- Invalid CPU/memory combination - must use 0.25 vCPU with 0.5 GB
- Typo in log group name - logs won’t appear
- Wrong port number - nginx listens on port 80 by default
- Not enabling log collection - you won’t see any logs
✓ Quick check: Task definition
dev-nginx:1shows ACTIVE with Fargate compatibility
Step 6: Create ECS Service
An ECS service maintains your desired number of running tasks and handles deployments.
Navigate to Clusters →
dev-cluster→ Services tabClick Create
Under Environment:
- Compute options:
Launch type - Launch type:
FARGATE
- Compute options:
Under Deployment configuration:
- Application type:
Service - Task definition family:
dev-nginx - Revision:
1 (latest) - Service name:
dev-nginx-service - Desired tasks:
1
- Application type:
Under Networking:
- VPC: Select your default VPC
- Subnets: Select all available subnets
- Security group: Select “Use an existing security group”
- Choose
dev-ecs-tasks-sg - Remove any default security groups
- Public IP: Turn ON (CRITICAL!)
Verify Load balancing is set to “None”
Verify Service auto scaling is “Do not use”
Click Create
ℹ Concept Deep Dive
Desired count of 1 means ECS will always try to keep 1 task running. If it crashes, ECS automatically starts a new one.
Public IP assignment is CRITICAL - without it, your container cannot be accessed from the internet even with the correct security group. This is the most common mistake.
Multiple subnets allow ECS to distribute tasks across availability zones for better reliability.
âš Common Mistakes
- Forgetting to enable Public IP - #1 reason services are unreachable
- Selecting only one subnet - limits availability
- Not removing default security groups - may conflict with your custom one
✓ Quick check: Service shows “ACTIVE” with “Running count: 1”
Step 7: Verify Deployment
Verify your nginx container is running and accessible.
Find Task Public IP
Navigate to your cluster → Tasks tab
Wait for task status to become
RUNNING(1-2 minutes)Click the task ID
Find the “Public IP” in the Configuration section
Copy the IP address
Test Nginx
Open a browser tab
Navigate to
http://<your-public-ip>Verify you see “Welcome to nginx!” page
Check Logs
Navigate to CloudWatch → Log groups →
/ecs/dev/nginxClick the log stream (named
ecs/nginx/<task-id>)Verify you see nginx access logs from your browser requests
ℹ Concept Deep Dive
Task lifecycle: PROVISIONING → PENDING (pulling image) → RUNNING. The PENDING phase can take 1-2 minutes for Docker Hub to deliver the image.
Public IP changes on every task restart since there’s no load balancer. This is temporary infrastructure for learning.
âš Common Mistakes
- Testing before task reaches RUNNING state
- Using
https://instead ofhttp://- we haven’t configured SSL- Checking logs immediately - wait 30 seconds for them to appear
✓ Success indicators:
- ✓ Task status is RUNNING
- ✓ Task has a public IP assigned
- ✓ Browser shows “Welcome to nginx!” page
- ✓ CloudWatch logs show HTTP 200 access logs
Common Issues
“Task failed to start” or keeps restarting:
- Check ECS service Events tab for error messages
- Verify CPU/memory is 0.25 vCPU with 0.5 GB
- Ensure task execution role has
AmazonECSTaskExecutionRolePolicy- Check CloudWatch logs for container errors
“Cannot pull container image”:
- Docker Hub rate limits (100 pulls per 6 hours for anonymous users)
- Wait 30 minutes and force a new deployment
- Verify outbound security group rules allow all traffic
“Task has no public IP”:
- Update service: Clusters → Services → Update
- Under Networking, enable “Auto-assign public IP”
- Force new deployment
“Cannot access nginx” (connection timeout):
- Verify security group allows port 80 from 0.0.0.0/0
- Ensure using
http://nothttps://- Confirm task is in RUNNING state
- Try from different network (mobile hotspot) to rule out firewall
“No logs in CloudWatch”:
- Verify log group name matches exactly:
/ecs/dev/nginx- Check task execution role has log writing permissions
- Wait 1-2 minutes for logs to appear
- Verify “Use log collection” was enabled in task definition
Summary
You’ve successfully deployed nginx on ECS Fargate using the AWS Console. Your infrastructure includes:
- ✓ ECS Cluster (serverless, Fargate-based)
- ✓ IAM Roles (task execution and task role)
- ✓ CloudWatch Logs (centralized logging)
- ✓ Security Group (HTTP access control)
- ✓ Task Definition (container blueprint)
- ✓ ECS Service (maintains running tasks)
Key takeaway:
ECS with Fargate provides serverless container orchestration - you define what to run (task definition) and how many instances (service desired count), and AWS handles all infrastructure management, scaling, and health monitoring.
Done! 🎉
You’ve learned how to deploy containerized applications on ECS Fargate using the AWS Console. This foundation prepares you for production deployments with load balancers, auto-scaling, and custom VPCs.
To clean up resources:
- Delete the ECS service (Clusters → Services → Delete)
- Delete the ECS cluster (Clusters → Delete)
- Delete the task definition (Task definitions → Deregister)
- Delete the security group (EC2 → Security Groups → Delete)
- Delete the log group (CloudWatch → Log groups → Delete)
- Delete the IAM roles (IAM → Roles → Delete)