Docker To Aws

Docker To Aws

Reading time1 min
#Cloud#DevOps#Containers#ECS#Fargate#DockerAWS

Deploying Docker Containers on AWS: Practical Engineering Guide

Consider this scenario—a new Node.js microservice is passing CI, but the staging environment constantly diverges from local Docker Compose runs. Sound familiar? Tight containerization solves half the battle, but frictionless and repeatable deployment on AWS remains a sticking point for many teams. The culprit: fragmented workflows between Docker and AWS-native services. Integrating these efficiently is foundational for resilient, scalable production systems.


Selecting AWS Container Runtimes

AWS supports several container scheduling and orchestration platforms:

ServiceUse CaseNotes
ECSManaged container orchestrationNative AWS; JSON task definitions; lower complexity
FargateServerless compute for containersRuns ECS/EKS tasks without managing EC2
EKSManaged KubernetesBest for K8s-centric, hybrid, or multi-cloud needs

In this walkthrough, ECS with Fargate is the focus—minimal ops overhead, reliable, and aligns well with most stateless web workloads.


Rapid Pipeline: Docker to AWS, No Surprises

Assumed:

  • AWS CLI v2
  • Docker v24+
  • Access to an AWS account with appropriate IAM permissions
  • At least one public subnet (Fargate requirement)

1. Build a Versioned Docker Image

Packaging is more than convenience—lock your OS version and Node.js base image to prevent silent breaking changes.

# Dockerfile
FROM node:14.21.3-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]

Build the image with a unique tag:
(Failure to use a Git commit or CI build number will bite you during rollbacks.)

docker build -t my-node-app:20240609 .

Test Locally

docker run --rm -p 3000:3000 my-node-app:20240609

If you see Error: Cannot find module './index.js'—your COPY context or build path is off. Don’t skip this step; it avoids “works locally” illusions.


2. Push to Amazon ECR

ECR provides image hosting regionally—key for both cost and latency.

aws ecr create-repository --repository-name my-node-app --region us-east-1

ECR Login:

aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

Tag and push:
(NOTE: AWS will block images >10GB; keep it lean.)

docker tag my-node-app:20240609 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-node-app:20240609
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-node-app:20240609

3. Define the ECS Compute Environment

Create an ECS Cluster

aws ecs create-cluster --cluster-name my-node-cluster

Write a Secure Task Definition

task-definition.json:

{
  "family": "my-node-app-task-20240609",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "containerDefinitions": [
    {
      "name": "my-node-app",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-node-app:20240609",
      "portMappings": [
        { "containerPort": 3000, "protocol": "tcp" }
      ],
      "essential": true,
      "environment": [
        { "name": "NODE_ENV", "value": "production" }
      ]
    }
  ]
}

Register the Task:

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

Gotcha: If you forget executionRoleArn, tasks will fail with
CannotPullContainerError: pull access denied for ...


4. Launch a Task or Deploy a Service

Here’s where misconfiguration is common. Ensure the subnet is public for testing (private/bastion for production) and the security group permits inbound 3000/tcp.

aws ecs run-task \
  --cluster my-node-cluster \
  --launch-type FARGATE \
  --task-definition my-node-app-task-20240609 \
  --network-configuration \
    "awsvpcConfiguration={subnets=[subnet-01234567],assignPublicIp=ENABLED,securityGroups=[sg-0aaaaaaa]}"

Keep It Running?
Define a service:

aws ecs create-service \
  --cluster my-node-cluster \
  --service-name my-node-service \
  --task-definition my-node-app-task-20240609 \
  --desired-count 2 \
  --launch-type FARGATE \
  --network-configuration \
    "awsvpcConfiguration={subnets=[subnet-01234567],assignPublicIp=ENABLED,securityGroups=[sg-0aaaaaaa]}"

Auto-recovery: ECS will restart failed tasks automatically.


5. (Optional but Critical in Prod) Attach a Load Balancer

Without an Application Load Balancer (ALB), terminating on public IP works for a demo but won’t scale or support blue-green deploys.
Attaching an ALB places your containers behind a managed HTTP(S) endpoint with health checks, TLS termination, and sticky sessions.

Diagram:

[Client] -> [ALB:80/443] -> [ECS Service] -> [Fargate Task:3000]

DevOps Pipeline Integration & Non-Obvious Tips

  • Full automation: Use CodePipeline + CodeBuild to drive docker build and image push steps from GitHub/GitLab commits.
    You must handle ECR login as a build step to avoid transient auth errors.
  • IaC best practice: Use AWS CloudFormation or Terraform to manage ECS clusters, task definitions, and associated IAM roles. Drift sneaks in fast otherwise.
  • Rolling deploys: Specify deployment configuration for zero-downtime updates.
  • CloudWatch logs: Wire up the container’s logs in the task definition:
"logConfiguration": {
  "logDriver": "awslogs",
  "options": {
    "awslogs-group": "/ecs/my-node-app",
    "awslogs-region": "us-east-1",
    "awslogs-stream-prefix": "ecs"
  }
}

This helps diagnose subtle crash loops and perf issues.


Takeaway

Pushing Docker containers to AWS ECS (using Fargate) closes the gap between dev and prod environments—no custom AMIs, no manual server patching, no snowflake infrastructure. Teams spend less time firefighting, more time shipping features. Still, this setup is not bulletproof: be meticulous with IAM permissions and network boundaries, especially during early iterations.

Alternative: Using EKS (Kubernetes) offers more flexibility for complex workloads but adds operational complexity. For 80% of web services, ECS+Fargate with IaC and a load balancer is the pragmatic baseline.


Need examples of production-ready CloudFormation stacks, or want a walkthrough of ECS blue/green deployments with CodeDeploy? Leave details and your use case.