All articles

Container Operations

Choose ECS Fargate or EC2 for a Docker Web Service on AWS

Decide between ECS Fargate and EC2, then plan a load-balanced Docker web service with versioned images and the right capacity settings.

By Niko Minadze6 min read

Editorial illustration for Choose ECS Fargate or EC2 for a Docker Web Service on AWS

For a Docker web service on AWS, choose ECS with Fargate if avoiding EC2 instance and host OS management matters most. Choose ECS on EC2 if you need to control how containers are distributed across hosts or packed onto shared hosts. Make that choice before following a deployment example: a working container image does not settle who supplies capacity when the task count changes. AWS’s ECS getting-started guide describes both paths.

Make the host decision first

ECS path Choose it when Capacity consequence
Fargate You do not want to manage EC2 instances or the host OS. Plan the number of tasks and any task autoscaling without an EC2 host-capacity plan.
EC2 Host distribution or binpacking matters to the workload. Plan both the number of tasks and the EC2 capacity available to run them.

For the EC2 path, ECS Cluster Auto Scaling can manage scaling an EC2 Auto Scaling Group. AWS also describes a capacity-provider pattern that starts with no EC2 instances, adds them as needed, and scales down to zero after all container tasks stop. That last condition matters for a web service expected to keep tasks running: the documented scale-to-zero pattern is not a promise that its hosts disappear while those tasks remain. Fargate avoids this host-capacity decision; EC2 gives you placement choices in exchange for making it.

Map the service to AWS resources

Think of the deployment as three connected ECS resources: a cluster holds the capacity context, a task definition describes what runs, and a service runs the web workload at the chosen task count. The application also needs its surrounding AWS configuration. An AWS ECS deployment example provisions a VPC, subnets, security groups, IAM roles and policies, an ECS cluster, task definitions and services, and an Application Load Balancer (ALB) for incoming traffic. That example uses an AI-assisted deployment tool; it is evidence for the resources to plan, not a claim that the Copilot command below uses the same provisioning workflow.

Use this checklist before deploying either host path:

  • Network and access: select the VPC and subnets, identify the needed security groups, and decide which IAM roles and policies the deployment requires.
  • Incoming traffic: configure the ALB for the web service and choose the container port it must serve. In the Copilot example below, that port is 80.
  • Task and service: decide task CPU and memory, task count, any autoscaling options, environment variables, and the health-check path. Specify a path that is meaningful for this application; choosing a path alone does not establish readiness.
  • Capacity: record Fargate or EC2 as the intended path. For EC2, decide whether an EC2 Auto Scaling Group and ECS capacity provider should grow host capacity as tasks need it.
  • Image: decide which image version the deployment is meant to run rather than relying on :latest.

These are deployment choices, not a manifest to paste. The cited AWS example lists VPC and subnet settings, CPU and memory, task count, autoscaling, ports, environment variables, and health-check paths as configurable parameters, but it does not provide Copilot manifest syntax for this checklist.

Deploy a load-balanced Fargate example

For the Fargate route, AWS’s Copilot tutorial gives this initialization command for a Dockerfile-based, load-balanced web service on port 80:

copilot init --app myapp \
  --name myapp-service \
  --type 'Load Balanced Web Service' \
  --dockerfile './Dockerfile' \
  --port 80 \
  --deploy

Run it only after you have a suitable ./Dockerfile and have settled the AWS settings your deployment needs. The --deploy option makes this an initialization and deployment example, not just a way to generate local files. The tutorial uses ECS with Fargate; do not treat this command as instructions for selecting EC2 hosts. The command names a load-balanced service, but it does not show the ALB configuration. Check that the resulting service is configured for the intended incoming traffic.

The same tutorial recommends specifying an image version instead of using the :latest tag. Its Dockerfile example uses a versioned NGINX base image. Keep that recommendation separate from any assumption about a Copilot-generated application-image tag: the supplied command does not specify one. Record the image version you intend to deploy and check what the deployed task actually references.

Update the image, then check capacity

For the tutorial’s update flow, AWS shows:

copilot deploy

The tutorial describes Copilot building the updated image, pushing the locally built image to Amazon ECR, converting the changed manifest to CloudFormation, and updating the deployment. That describes the documented workflow, not an update performed here. Before using it, confirm that the image version and changed manifest represent the release you intend to run. Afterward, check the deployed task’s image reference rather than treating a completed build as proof that the desired version is running.

An increased task count has a different capacity implication on the two paths. With Fargate, there is no EC2 instance fleet for you to scale. With ECS on EC2, account for the hosts that will run the additional tasks; ECS Cluster Auto Scaling can scale an EC2 Auto Scaling Group, and the cited capacity-provider pattern can add EC2 capacity as needed. Choose that capacity behavior deliberately rather than assuming a task-count change also establishes your preferred host-placement policy.

Check the result against the decision

Compare the deployed configuration with the checklist, not merely with the Dockerfile. Confirm the service follows the intended Fargate or EC2 path; the selected VPC, subnets, security groups, IAM roles and policies are present; and the ALB is configured for incoming service traffic. Then compare the deployed task and service settings with your chosen CPU and memory, task count, autoscaling options, port, environment variables, and health-check path. Finally, check the deployed image version. On EC2, also check that the capacity-provider and EC2 Auto Scaling Group configuration matches the scaling behavior you chose. Those checks catch a consequential mismatch: the web service may be deployed, but not on the hosts, network, or image version you meant to operate.

All articles