-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
355: Containerizing a Python Application with Docker
A few years ago, I was mentoring a developer who spent an entire Friday night chasing a bug that only existed on our staging server. Locally, his data processing script ran perfectly. On the server, it crashed with a cryptic ImportError related to a C-extension in the pandas library. It turned out the server was running an older version of Debian with a different glibc version than his macOS machine. He had the right Python version, the right requirements file, and the right code—but the underlying operating system was sabotaging him. This is the "it works on my machine" trap, and it's exactly why we use Docker.
At its core, Docker lets us package the application code, the runtime, the system libraries, and the configuration into a single immutable artifact called an image. When you run that image, it becomes a container. Because the container carries its own environment, it doesn't matter if your server is running Ubuntu, CentOS, or Alpine; the code inside the container sees the exact same environment every single time.
Building a Reproducible Environment via the Dockerfile
To containerize a Python app, we write a Dockerfile. Think of this as a recipe. I'll use a Flask-based API that calculates portfolio risk as our example, as it requires a few specific dependencies. Instead of using the default python:3.11 image—which is massive because it includes build tools you rarely need in production—I always recommend starting with python:3.11-slim. It keeps your image size down and reduces the attack surface for security vulnerabilities.
FROM python:3.11-slim
# Set the working directory inside the container
WORKDIR /app
# Install system dependencies required for some Python packages (like psycopg2 or pandas)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Copy only the requirements first to leverage Docker's layer caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code
COPY . .
# Tell Docker which port the app listens on
EXPOSE 5000
# The command to run the app
CMD ["python", "app.py"]
You'll notice I copied requirements.txt and ran pip install before copying the rest of the code. This is a crucial optimization. Docker caches each line (layer). If you change a line of code in app.py but don't change your dependencies, Docker will skip the expensive pip install step and jump straight to copying the updated code. It turns a three-minute build into a three-second build.
Pruning the Build with .dockerignore
One mistake I see constantly is developers copying their entire project folder into the image without a filter. If you have a .git folder, __pycache__ directories, or a .env file containing secret API keys, you don't want those inside your image. Not only does it bloat the image size, but it's a massive security risk to bake secrets into an image that might be stored in a shared registry.
Create a .dockerignore file in your root directory. It works exactly like a .gitignore. I usually keep mine simple:
__pycache__/
*.pyc
.git/
.env
venv/
.vscode/
Once your files are ready, you build the image using docker build -t portfolio-api . and run it with docker run -p 5000:5000 portfolio-api. The -p flag maps your machine's port 5000 to the container's port 5000, allowing you to hit the API in your browser while the actual process remains isolated inside the container.
📋 Practical Task
Exercise: Containerizing the "Weather-Aggregator" Service
You have been handed a small Python project called weather-aggregator. It is a Flask app that uses the requests library to pull data from an external API. Your goal is to create a production-ready Docker configuration for it.
Project Structure:
app.py(The Flask application)requirements.txt(Containsflaskandrequests).env(Contains a secretAPI_KEY)tests/(A folder containing local Pytest files)
Requirements:
- Write a
Dockerfileusing a slim Python 3.11 base image. - Ensure the
requirements.txtis installed in a way that leverages layer caching (install dependencies before copying the rest of the source code). - Use
--no-cache-dirduring the pip installation to keep the image lean. - Create a
.dockerignorefile that prevents the.envfile and thetests/folder from being baked into the final image. - Set the
WORKDIRto/usr/src/app.
Validation: Your solution is successful if the image builds without errors and the final image does not contain the .env file or the tests directory when inspected via docker run -it [image_name] ls -R /usr/src/app.
There are no comments for now.