Deploy Docker Container To Aws

Deploy Docker Container To Aws

Reading time1 min
#Cloud#Containers#DevOps#AWS#Docker#Fargate

Optimizing Cost and Performance: Deploying Docker Containers on AWS with ECS and Fargate

High AWS bills from over-provisioned compute—far too common. Unexpected throttling on peak load—equally annoying. The actual challenge isn’t running Docker containers on AWS, it’s finding the balance between operational reliability and minimizing spend. Here’s an engineer’s approach to deploying containers on AWS ECS with Fargate, with detail on resource tuning and cost controls that make a difference.


Docker on AWS: Practical Context

Running containers on AWS via ECS is standard for stateless services, batch workloads, or microservices. But the difference between a functional POC and a robust, efficient deployment boils down to two questions:

  • How do you avoid paying for idle CPU and memory?
  • How do you ensure scaling works under variable demand?

ECS with Fargate answers both—for most use cases, it’s now more flexible than managing your own EC2s. Yet, trade-offs remain: Fargate simplifies ops but constrains network and storage customization.


ECS vs. Fargate: Which, When?

FeatureECS (EC2)Fargate
Node ControlFull (OS, agents, patching)None, all abstracted
PricingPer-instance (potentially lower)Per-task, precise
Task Start TimeSlower (spin-up EC2)Fast (less than 60s typical)
Use CaseLarge, steady clustersVariable, unpredictable load

Key trade-off: EC2-based ECS offers fast networking options (ENIs per host), GPU access, and persistent storage tuning. Fargate is practically maintenance-free, but runs on what AWS offers—custom AMIs aren’t available.


Deployment: Realistic Walkthrough

1. Build and Push Image to ECR

You can’t deploy anything without a registry. AWS ECR integrates IAM and lifecycle policies—no-brainer over public Docker Hub for production.

Here’s a typical build-and-push sequence (Docker v24+, AWS CLI v2):

REGION=us-east-1
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REPO="${AWS_ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/my-app"

aws ecr create-repository --repository-name my-app 2>/dev/null

# Authenticate
aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin $REPO

docker build --platform linux/amd64 -t my-app:2024-06-13 .
docker tag my-app:2024-06-13 $REPO:2024-06-13
docker push $REPO:2024-06-13

Note: Multi-arch builds may be required (e.g., for ARM64 on Graviton). Image size impacts cold start and transfer time.


2. Define a Fargate Task Definition

Task definitions are versioned. Make sure to increment revisions and keep old ones for rollback.

Minimal viable Fargate task (task-definition-v5.json):

{
  "family": "my-app-task",
  "networkMode": "awsvpc",
  "cpu": "256",
  "memory": "512",
  "requiresCompatibilities": ["FARGATE"],
  "containerDefinitions": [{
    "name": "my-app",
    "image": "${REPO}:2024-06-13",
    "portMappings": [
      { "containerPort": 8080, "protocol": "tcp" }
    ],
    "essential": true,
    "logConfiguration": {
      "logDriver": "awslogs",
      "options": {
        "awslogs-group": "/ecs/my-app",
        "awslogs-region": "us-east-1",
        "awslogs-stream-prefix": "fargate"
      }
    }
  }]
}

Register:

aws ecs register-task-definition --cli-input-json file://task-definition-v5.json

Gotcha: Fargate task min sizes are 0.25 vCPU/0.5GB. For anything JVM-based, 512MB is typically too low; start at 1024MB for reliability.


3. Create ECS Cluster and Run Task

Every Fargate task must be launched inside a cluster and tied to a VPC subnet with a reachable route. Be explicit about network configuration.

aws ecs create-cluster --cluster-name myapp-fargate

aws ecs run-task \
  --cluster myapp-fargate \
  --launch-type FARGATE \
  --task-definition my-app-task \
  --count 1 \
  --network-configuration 'awsvpcConfiguration={subnets=["subnet-0fxxxx"],securityGroups=["sg-0yyyy"],assignPublicIp="ENABLED"}'

Note: For production, deploy an ECS Service NOT single run-task. ECS Services support auto-scaling, ALB integration, and rolling deployment.


4. Application Load Balancer Integration

For zero-downtime rolling deploys and scaling, connect Fargate services to an ALB. Target groups must match the container’s port. Add health checks (e.g. /healthz endpoint, 200 response).

Sample error when hostPort mismatches:

service arn:xxx failed to register targets in target group: Invalid request provided: port 0 is not allowed

Fix: Ensure port mapping in task matches ALB target group.


5. Cost and Performance Tuning: Key Details

a. Right-size Resources Early and Iterate

Monitor via CloudWatch:
CPUUtilization > 80%? MemoryUtilization spikes > 90%? Scale up.

  • Start with minimums, increase in 256/512MB (memory) or 0.25 vCPU steps.
  • Fargate billing is per second with 1-minute minimum—avoid excessive over-provisioning.

b. Fargate Spot: Use with Caution

Spot tasks are preemptible, ~70% cheaper, sometimes interrupted (~2 minutes notice in practice). Configure Capacity Providers:

aws ecs put-cluster-capacity-providers \
  --cluster myapp-fargate \
  --capacity-providers FARGATE FARGATE_SPOT \
  --default-capacity-provider-strategy capacityProvider=FARGATE,weight=1

Good for queue-driven workloads, not mission-critical APIs.

c. Leverage Smaller Docker Images

Switch all base images to alpine, multi-stage for prod builds. E.g., docker build --target production ...

  • Large images cause ECS deployment delays (“Cannot pull container ... error: image pull failed”).
  • Remove build tools, docs, caches.

d. Auto Scaling Strategy

Define Service Auto Scaling with sensible thresholds:

  • Track: ECSServiceAverageCPUUtilization, ECSServiceAverageMemoryUtilization
  • Policy: Scale out at >75%, in at <40%
  • Set max task count based on expected traffic spikes (plus margin for headroom).

e. Monitoring—ignore at your peril

Enable CloudWatch Container Insights. Key metrics: MemoryUtilized, NetworkRxBytes, CpuReserved.
Unexpected task exit? Review ECS task logs for OOMKilled or CannotStartContainerError.


Conclusion: Efficient Cloud Containers Aren’t Accidental

ECS with Fargate allows rapid, low-maintenance container deployments. Yet, poorly tuned resource boundaries and neglected scaling or monitoring waste both budget and reliability. Continuous adjustment—CPU/memory limits, scheduling strategy, image optimization, logging configuration—turns ECS from a proof-of-concept to real infrastructure.

Known issue: Fargate networking can complicate large-scale deployments; ENI scaling limits per VPC apply. Plan accordingly or segment workloads.


References:

For code-backed, production-ready Terraform or CDK templates, review the AWS samples via GitHub—real-world repos flag VPC/subnet misconfigurations not always covered in docs.


Note: For highly stateful, persistent workloads, ECS and Fargate remain suboptimal—consider EKS with managed nodegroups or Kubernetes-native operators.


No one deployment fits all. Tuning is ongoing.