Containerize Python with Docker on ECR

Containerize a Python app with Docker on ECR — AWS Cloud & DevOps with Python.

Focus: containerize a python app with docker on ecr

Sponsored

Your Python app runs perfectly on your laptop. Push it to a server, and suddenly it crashes because someone installed the wrong version of a library, or the OS is missing a system dependency. This "works on my machine" problem is the #1 cause of deployment failures in real-world DevOps. Docker solves that by packaging your app, its dependencies, and its runtime into a single, immutable artifact — a container image. In this lesson, you'll learn how to containerize a Python app with Docker on ECR, the AWS container registry, so you can deploy that image anywhere on AWS with total consistency.

The problem this lesson solves

Imagine you're a DevOps engineer. You've just finished a Flask web app that uses Redis and a custom Python package. You hand it to the ops team, but their Linux box has Python 3.6, your app needs 3.11. The Redis client is missing, and someone installed a conflicting version of requests. Deployment becomes a nightmare of manual fixes.

Docker eliminates this entire class of problems. By containerizing your Python app, you create a self-contained image that includes your code, all Python dependencies (from pip), and the base OS layer. When you push that image to Amazon ECR (Elastic Container Registry), you have a single, versioned artifact that can be pulled and run on any Docker-compatible host — EC2, ECS, EKS, or even your local machine. This is the foundation of modern CI/CD pipelines, so mastering it is essential for any cloud developer.

Core concept / mental model

Think of a container image as a shipment box for your app. Inside the box, you have everything needed to run: a tiny Linux OS, Python interpreter, your source code, and all third-party libraries. Docker is the packing factory — it uses a Dockerfile as the instruction manual for exactly how to build that box.

ECR is the warehouse where you store these boxes. Instead of physically moving them, you push your image to ECR and later pull it on any server. Each image has a unique tag (like v1.0.0 or latest) so you can keep multiple versions and roll back instantly.

Here's the mental map:

  • Dockerfile → defines how to build the image (the recipe).
  • docker build → executes the recipe and produces an image.
  • docker push → uploads the image to ECR.
  • docker pull → downloads the image to a deployment target.
  • ECR → private or public registry that stores your images securely.

How it works step by step

Containerizing a Python app with Docker on ECR is a linear process. Here's the logical flow:

  1. Write a Dockerfile in your project root. This file defines the base image (e.g., python:3.11-slim), copies your code, installs dependencies, and sets the command to run your app.
  2. Build the image locally with docker build -t my-app . to verify it works.
  3. Create an ECR repository in your AWS account to hold your images.
  4. Authenticate Docker to your ECR registry using the aws ecr get-login-password command.
  5. Tag your image with the ECR repository URI.
  6. Push the image to ECR.
  7. Optionally test by pulling the image and running a container from it.

Each step has a cause-and-effect: a well-formed Dockerfile yields a reproducible build; correct authentication gives push access; a versioned tag enables rollbacks.

Hands-on walkthrough

Let's containerize a simple Python Flask app. You'll need Docker installed and the AWS CLI configured with credentials that have ECR permissions.

Step 1: Create a minimal Flask app

First, create a project folder and add these files:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello from containerized Python!'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
# requirements.txt
flask==3.0.0

Step 2: Write the Dockerfile

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

# Copy only requirements first to leverage Docker caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the rest of the application
COPY app.py .

EXPOSE 5000

CMD ["python", "app.py"]

Pro tip: Copy requirements.txt separately and run pip install before copying your code. This way, Docker can cache the dependency layer, so rebuilds are blazing fast when you only change app code.

Step 3: Build and test locally

docker build -t flask-hello .
docker run -d -p 5000:5000 --name test-app flask-hello
curl http://localhost:5000
# Output: Hello from containerized Python!

# Clean up if needed
docker stop test-app && docker rm test-app

Step 4: Create an ECR repository

aws ecr create-repository --repository-name flask-hello --region us-east-1
# Output includes the repositoryUri, e.g., 123456789012.dkr.ecr.us-east-1.amazonaws.com/flask-hello

Step 5: Authenticate and push

# Authenticate Docker to your ECR registry
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

# Tag your image with the ECR repository URI
 docker tag flask-hello:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/flask-hello:latest

# Push to ECR
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/flask-hello:latest

If you run docker images, you'll see your locally tagged image. The push output shows compressed layer uploads — that's ECR storing your image in AWS.

Step 6: Verify by pulling and running

# Optionally test from a separate machine
docker pull 123456789012.dkr.ecr.us-east-1.amazonaws.com/flask-hello:latest
docker run -d -p 5000:5000 flask-hello

You've now containerized a Python app with Docker on ECR — a production-ready artifact that can be deployed to ECS, EKS, or EC2 with zero environment surprises.

Compare options / when to choose what

There are several ways to containerize and store a Python app. Here's how Docker+ECR stacks up:

Approach Pros Cons Best for
Docker + ECR Fully managed, secure, integrates with ECS/EKS Requires AWS CLI setup Production AWS deployments
Docker + Docker Hub Simpler, public/private options Extra cost for private repos, slower pull from AWS Local dev, open-source projects
VMs (EC2 without containers) Full control over OS Heavier, slower startup, env drift Legacy apps
AWS Elastic Beanstalk Abstracts Docker, auto-scaling Less control over image lifecycle Simple web apps

Choose ECR when you're all-in on AWS. Choose Docker Hub if you want a quick public demo. Use a VM if you're migrating a legacy monolith that can't be containerized.

Troubleshooting & edge cases

Here are common issues you'll hit:

  • denied: Your Authorization Token has expired: Re-run aws ecr get-login-password — tokens expire after 12 hours.
  • no space left on device during build: Docker cache and old images accumulate. Run docker system prune to clean up.
  • Port already in use (failure on docker run -p 5000:5000): Change the host port, e.g., -p 5001:5000.
  • exec: "python": executable file not found: Your Dockerfile's CMD uses a Python that isn't in the image base. Double-check your FROM base (e.g., python:3.11-slim includes python).
  • ECR push fails with retrying in X seconds: Network issue or large image. Check your internet connection and consider using a smaller base image.
  • Image size too large: Switch to python:3.11-slim or alpine variants, and use --no-cache-dir in pip.

What you learned & what's next

You now understand the core concept of containerize a Python app with Docker on ECR, from authoring a Dockerfile to pushing a versioned image to AWS. You applied the process hands-on with Flask, and you know how to troubleshoot common Docker and ECR errors.

This skill is the backbone of deploying Python services on AWS. The natural next step is learning to run your containerized app on Amazon ECS (Elastic Container Service) or EKS (Kubernetes) — that's where your image truly goes to work with auto-scaling and load balancing. You're ready to move from packaging to orchestration.

Practice recap

Now that you've containerized a Flask app, try containerizing a small Python CLI tool or a FastAPI service. Add a .dockerignore file to keep your image clean, and practice tagging with v1.0.0 before pushing. Then next lesson: we'll run that ECR image on ECS with a load balancer — see how it all glues together.

Common mistakes

  • Forgetting to run aws ecr get-login-password — you must re-authenticate Docker every 12 hours before pushing to ECR.
  • Copying the entire source code before installing dependencies — this breaks Docker layer caching and slows every rebuild.
  • Using latest as a tag for production — always use a versioned tag (e.g., v1.0.0) to enable rollbacks.
  • Using python:latest or python:alpine blindly — slim is more reliable with compiled dependencies then alpine if you're not comfortable with musl libc.
  • Not exposing the correct port — the EXPOSE in your Dockerfile must match the port your app listens on or containers won't be reachable.

Variations

  1. Alternative registry: Use Docker Hub or GitHub Container Registry (GHCR) if you prefer a non-AWS option.
  2. Multi-stage Dockerfiles: Build dependencies in a temp stage, then copy only the ready virtualenv to a slim runtime image — reduces final image size dramatically.
  3. Use docker-compose.yml for local multi-service Python apps (e.g., Flask + Redis) instead of running several docker run commands manually.

Real-world use cases

  • Deploy a Python Flask REST API to Amazon ECS with manual scaling — team uses ECR to version images and rollback in seconds.
  • Run a Python data processing job (e.g., using pandas) on AWS Batch — image is stored on ECR and pulled on-demand.
  • Ship a Python ML model (e.g., TensorFlow) served by FastAPI — model and dependencies packaged for GPU-enabled EC2 with Docker.

Key takeaways

  • Docker packages your Python app, dependencies, and runtime into a portable image — fixing the 'works on my machine' problem.
  • ECR is a fully managed registry that integrates naturally with ECS, EKS, and other AWS services.
  • The workflow is: Dockerfile → build → tag → authenticate → push → pull/run.
  • Use python:3.11-slim as a reliable base image and install dependencies before copying your code for faster rebuilds.
  • ECR login tokens expire after 12 hours — re-authenticate with aws ecr get-login-password before any push.
  • Tag images with semantic versions in production to enable rollbacks and traceability.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.