Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 81

Dockerizing ML Applications

Recommended resources

Hello! Welcome to the first lesson in our module on MLOps and Model Deployment.

In our previous module, we focused on building and refining powerful AI models, culminating in implementing safety guardrails. But a model sitting in a notebook is like a brilliant blueprint that never becomes a building. The crucial next step is to get your model out into the world where it can provide real value. This is the domain of MLOps (Machine Learning Operations).

This lesson marks our first step into MLOps. We'll tackle one of the most fundamental challenges in software deployment: ensuring that an application that works on your machine also works reliably everywhere else. To do this, we'll learn how to containerize ML applications using Docker.

By the end of this lesson, you will be able to:

  • Explain what containerization is and why it's essential for deploying ML applications.
  • Understand the key Docker concepts: images and containers.
  • Write a Dockerfile to package a Python ML application.
  • Build, run, and manage your containerized application.
  • Share your application with the world using Docker Hub.

1. The Deployment Problem and the Container Solution

Imagine you've built a fantastic ML model served via a Flask API. It works perfectly on your Windows machine with Python 3.9 and scikit-learn version 1.3.0. Now, you hand it over to a colleague who uses a Mac with Python 3.10, or you try to deploy it to a Linux server in the cloud. Suddenly, nothing works. This is the "it works on my machine" problem, a classic headache in software development caused by differences in operating systems, library versions, and environment configurations.

Containerization solves this problem by packaging your application, along with all its dependencies, libraries, and configuration files, into a single, isolated, and portable unit called a container.

Complete Dockers For Data Science Tutorial In One Shot

To understand the core problem that containers solve, let's watch this explanation from Krish Naik. He clearly illustrates the chaos of managing dependencies across different developer and server environments.

Watch the segment from 01:23 to 07:10. Focus on how inconsistencies in libraries and configurations between development, QA, and production environments can cause applications to fail, and how containers are presented as the solution.

As the video explains, a container acts like a standardized shipping container for your software. It ensures that your application runs the same way, no matter where it's deployed.

Containers vs. Virtual Machines (VMs)

You might have heard of Virtual Machines (VMs), which also provide isolated environments. However, they work very differently. A VM emulates an entire computer, including a full guest operating system, making it very large and slow to start.

Containers are much more lightweight. They share the host system's operating system kernel, only packaging the application and its specific dependencies.

How to Containerize an Application Using Docker - DataCamp

This article from DataCamp provides a concise comparison between containers and virtual machines. The table is particularly helpful for a quick overview.

Read the first part of the article, up to and including the table under the heading 'Containers vs virtual machines'. This will clarify the architectural and performance differences.

For ML applications, the lightweight and fast nature of containers is a huge advantage, allowing for rapid scaling and efficient resource use.


2. Docker: Images and Containers

Docker is the leading platform for creating and managing containers. To work with Docker, you need to understand two fundamental concepts: Images and Containers.

  • Docker Image: A static, read-only blueprint that contains everything needed to run an application: the code, a runtime (like Python), libraries, and environment variables. Think of it as a class in object-oriented programming.
  • Docker Container: A running instance of a Docker image. It's the live, executing environment where your application runs. Think of it as an object or an instance of a class.

You build an image once, and you can use it to create and run many identical containers.

Packaging and Running ML Models with Docker
This diagram shows the fundamental Docker workflow. A developer writes a `Dockerfile` (a set of instructions), uses it to `build` a Docker Image (a static blueprint), and then `runs` that image to create one or more Docker Containers (the live application).

Complete Dockers For Data Science Tutorial In One Shot

Let's reinforce the distinction between an image and a container. This video provides a clear explanation.

Watch from 12:57 to 16:30. Pay attention to the analogy: the Docker image is the entire package of dependencies, and the container is the running environment created from that package.


3. Setting Up Your Docker Environment

Before we can build anything, you need to install Docker on your machine. The most common way to do this is by installing Docker Desktop.

How to Containerize an Application Using Docker - DataCamp

This DataCamp article provides straightforward installation instructions for Windows, macOS, and Linux.

Follow the instructions in the sections 'Step 1: Installing Docker' and 'Step 2: Verify Docker installation'. Make sure you can successfully run docker run hello-world.

Important Note: As mentioned in the video from Krish Naik (at 00:29:45), on some systems (especially Windows), you may need to enable virtualization in your computer's BIOS/UEFI settings. If you encounter errors during installation, this is the first thing to check.


4. Hands-On: Containerizing an ML API

Now for the practical part. We'll take a simple ML model, wrap it in a Flask API, and then containerize it with Docker.

Step 1: Prepare the ML Application

First, create a new project directory. Inside this directory, create two files: app.py and requirements.txt.

app.py:
This script loads the Iris dataset from scikit-learn, trains a simple Random Forest model, and exposes a /predict endpoint using Flask.




# app.py
from flask import Flask, request, jsonify
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
import numpy as np




# Initialize Flask app
app = Flask(__name__)




# Load and prepare the model
iris = load_iris()
X, y = iris.data, iris.target
X_train, _, y_train, _ = train_test_split(X, y, test_size=0.2, random_state=42)

model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

@app.route('/predict', methods=['POST'])
def predict():



    # Get features from the JSON request
    data = request.get_json()
    features = data['features']
    



    # Make prediction
    prediction = model.predict([features])
    



    # Return the prediction as JSON
    return jsonify({
        'prediction': int(prediction[0]),
        'class_name': iris.target_names[prediction[0]]
    })

if __name__ == '__main__':



    # Run the app, accessible from outside the container
    app.run(host='0.0.0.0', port=5000)

Note the host='0.0.0.0'. This is crucial for making the Flask app accessible from outside the Docker container.

requirements.txt:
This file lists the Python libraries our application needs. Pinning versions is a best practice for ensuring reproducibility.




# requirements.txt
scikit-learn==1.3.0
numpy==1.24.3
Flask==2.2.2

Step 2: Write the Dockerfile

The Dockerfile is a script that contains the step-by-step instructions for building our Docker image. In your project directory, create a file named Dockerfile (with no file extension).




# 1. Use an official Python runtime as a parent image
FROM python:3.9-slim




# 2. Set the working directory in the container
WORKDIR /app




# 3. Copy the dependencies file first to leverage Docker cache
COPY requirements.txt .




# 4. Install any needed packages specified in requirements.txt
RUN pip install --no-cache-dir -r requirements.txt




# 5. Copy the application code into the container
COPY . .




# 6. Make port 5000 available to the world outside this container
EXPOSE 5000




# 7. Define the command to run the application
CMD ["python", "app.py"]

Let's break this down:

  1. FROM python:3.9-slim: Every Docker image starts from a base image. We're using a lightweight ("slim") official Python 3.9 image.
  2. WORKDIR /app: Sets the default directory for all subsequent commands inside the container.
  3. COPY requirements.txt .: Copies only the requirements.txt file into the container. We do this first to take advantage of Docker's layer caching. Since dependencies rarely change, this layer won't need to be rebuilt often, speeding up future builds.
  4. RUN pip install ...: Executes the command to install our Python libraries. --no-cache-dir keeps the image size smaller.
  5. COPY . .: Copies the rest of our application code (like app.py) into the container.
  6. EXPOSE 5000: Informs Docker that the container listens on port 5000. This is documentation; it doesn't actually publish the port.
  7. CMD ["python", "app.py"]: Specifies the default command to run when the container starts.
Deploying a Machine Learning Model with FastAPI and Docker
This image visualizes our goal: packaging the API (built with Flask, which is similar to FastAPI in this context) and the ML model into a deployable Docker container.

Step 3: Build the Docker Image

Now, open your terminal in the project directory and run the docker build command.




# The -t flag "tags" (names) our image as 'ml-iris-app'.
# The '.' at the end specifies the build context (the current directory).
docker build -t ml-iris-app .

You'll see Docker execute each step from your Dockerfile.

Step 4: Run the Docker Container

Once the image is built, run it as a container with the docker run command.




# The -p flag "publishes" a port, mapping port 5000 on your host machine 
# to port 5000 inside the container.
docker run -p 5000:5000 ml-iris-app

Your terminal will now show the output from the Flask server, indicating that your containerized application is running!

Step 5: Test the Containerized Application

Open a new terminal window (leave the container running in the first one) and use curl to send a POST request to your API. We'll send the features for an Iris setosa flower.

curl -X POST -H "Content-Type: application/json" \
-d '{"features": [5.1, 3.5, 1.4, 0.2]}' \
http://localhost:5000/predict

You should receive a successful JSON response:

{"class_name":"setosa","prediction":0}

Congratulations! You've successfully containerized and run your first ML application.


5. Managing and Sharing Your Containers

Your work with Docker doesn't stop after you run a container. You also need to know how to manage it.

Essential Management Commands

Here are a few commands you'll use all the time. Run these in your terminal.

  • List running containers:

    docker ps
    
  • Stop a container (use the CONTAINER ID from docker ps):

    docker stop <your-container-id>
    
  • View logs from a container (extremely useful for debugging):

    docker logs <your-container-id>
    
  • List all containers (including stopped ones):

    docker ps -a
    
  • List all images on your machine:

    docker images
    

Sharing Your Image on Docker Hub

Docker Hub is a public registry for Docker images, like GitHub for code. Pushing your image there allows anyone to pull and run your containerized application.

Complete Dockers For Data Science Tutorial In One Shot

This video provides a clear, step-by-step guide on how to push your custom image to Docker Hub.

Watch from 52:43 to 58:20. Follow the process: Log in using docker login. Tag your local image with your Docker Hub username (docker tag local-image:tag username/repo-name:tag). This step is crucial. Push the image using docker push username/repo-name:tag.

By following these steps, you can share your ml-iris-app with colleagues or deploy it to any cloud provider that supports Docker containers.


Conclusion

In this lesson, you've taken a massive step from being a model developer to becoming a deployment-ready engineer. You learned how to solve the "it works on my machine" problem by packaging an ML application into a portable, reproducible container with Docker.

Key Takeaways:

  • Containerization bundles an application with its dependencies, ensuring it runs consistently across any environment.
  • Docker Images are the static blueprints, while Docker Containers are the live, running instances of those images.
  • The Dockerfile is the recipe for building an image, with commands like FROM, WORKDIR, COPY, RUN, and CMD.
  • Optimizing your Dockerfile (e.g., copying requirements.txt first) can significantly speed up build times.
  • The docker build, docker run, and docker push commands are the core workflow for building, running, and sharing containerized applications.

Preview of the Next Lesson:
Now that we can package our applications, a new set of questions arises. How do we track which version of a model is inside a container? How do we compare the performance of different models we've trained? In our next lesson, you will learn to track experiments and model versions using MLflow, another cornerstone tool in the MLOps toolkit.