PyTorch

Model Deployment and Inference

Demo Introduction to Docker

In this lesson, we guide you through using Docker to deploy a Flask application as part of a model deployment process. You will learn how to install Docker on an Ubuntu server, build a container image for your Flask app, verify the installation, run the container, test the application, and finally push the image to Docker Hub.


Installing Docker on Ubuntu

Docker runs on Linux, Windows, and macOS, but in this example we focus on an Ubuntu server. The following instructions are adapted from the official Docker documentation.

Update Your Package List

Before starting the installation, update your package index to ensure you have the latest information from the repositories.

Step 1: Prerequisites

Update your package index and install the required packages:

apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

Step 2: Add the Docker Repository

Add the Docker repository to your system. This command automatically determines your system’s version codename:

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

Step 3: Install Docker Engine

Update the package list again and install the Docker Engine, CLI, containerd, and additional required packages. This process may take a few moments:

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

You should see output similar to the following, indicating that Docker and its dependencies have been installed:

Get:2 https://download.docker.com/linux/ubuntu lunar/stable amd64 Packages [16.1 kB]
Hit:3 http://old-releases.ubuntu.com/ubuntu lunar InRelease
...
Fetched 64.9 kB in 1s (96.1 kB)
...
The following NEW packages will be installed: apparmor, containerd.io, docker-ce, docker-ce-cli, docker-buildx-plugin, docker-compose-plugin, ...

After installation, open a terminal to start and enable the Docker service.


Verifying the Docker Installation

To confirm that Docker has been installed correctly, check the version:

docker version

Next, run Docker’s official "Hello World" container to verify that both the client and daemon are functioning properly:

docker run hello-world

A successful run will produce output like:

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
...
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

Building a Docker Image for the Flask App

This section walks you through containerizing a Flask application by creating a Dockerfile that outlines the necessary build steps.

Dockerfile Explanation

The Dockerfile below uses a slim official Python image and installs the CPU version of PyTorch to minimize the image size. It then installs Python dependencies, copies your Flask app, and sets up a non-root user for enhanced security.

# Use the official Python base image
FROM python:3.11-slim

# Set the working directory
WORKDIR /opt/app

# Install CPU version of PyTorch
RUN pip install torch==2.4.1 --index-url https://download.pytorch.org/whl/cpu

# Copy requirements and install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy the Flask app code
COPY ./flask_app .

# Create a user and group for running the app
RUN groupadd -r pytorch && useradd --no-log-init -r -g pytorch pytorch

# Change ownership of the app directory
RUN chown -R pytorch:pytorch /opt/app

# Switch to the created user
USER pytorch

# Expose the port that our Flask app is listening on
EXPOSE 8000

# Command to run the Flask app
CMD ["flask", "run", "--host=0.0.0.0", "--port=8000"]

Place this Dockerfile in the same directory as your requirements.txt file and your Flask app. Then, build your Docker image with the following command:

docker build -t mobilenetv3lg-flask:v1.0 .

During the build process, you will see steps that include loading the base image, copying files, installing Python packages via pip, and setting up a non-root user. After the build completes, verify the new image with:

docker images

A sample output might look like this:

REPOSITORY              TAG       IMAGE ID       CREATED               SIZE
mobilenetv3lg-flask     v1.0      1734db15a849   About a minute ago    5.39GB
hello-world             latest    d2c94e258dc9   20 months ago         13.3kB

Image Size Optimization

After optimizing the image by including only CPU dependencies, you may notice a reduction in image size (e.g., from 5.39GB to 1.34GB).


Running the Docker Container

Now that your Docker image is ready, you can run it as a container. The command below maps port 8000 in the container to port 8000 on your local machine:

docker run -p 8000:8000 mobilenetv3lg-flask:v1.0

When the container starts, you may see log messages similar to the following:

2025-01-16 19:05:41,363 - INFO - Loading MobileNetV3 Large pre-trained model...
Downloading: "https://download.pytorch.org/models/mobilenet_v3_large-5c1a4163.pth" to /home/pytorch/.cache/torch/hub/checkpoints/mobilenet_v3_large-5c1a4163.pth
100.0%
2025-01-16 19:05:41,827 - INFO - Model loaded successfully.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8000
...

For deploying the container in detached mode (running in the background), use the -d flag:

docker run -d -p 8000:8000 mobilenetv3lg-flask:v1.0

You can monitor your containers with:

docker ps

And view container logs with:

docker logs <container_id>

Testing the Flask Application Inside Docker

With your container running, test the Flask endpoint by sending a POST request with an image payload. The following Python script encodes an image in Base64, constructs a JSON payload, and sends it to the /predict endpoint:

import requests
import base64

# Open the image file and encode it to Base64
with open('dog-1.jpg', 'rb') as img_file:
    base64_string = base64.b64encode(img_file.read()).decode('utf-8')

# Construct the JSON payload
payload = { "image": base64_string }

# Specify the headers
headers = { "Content-Type": "application/json" }

# Send the POST request
response = requests.post("http://127.0.0.1:8000/predict", headers=headers, json=payload)

# Print the response from the server
print("Response JSON:", response.json())

A successful response might show:

Response JSON: {'prediction': 207}

This indicates that the inference request was processed correctly by your Flask application.


Tagging and Pushing the Docker Image to Docker Hub

To share your Docker image, start by tagging it with your Docker Hub username:

docker tag mobilenetv3lg-flask:v1.0 username/mobilenetv3lg-flask:v1.0

Next, log in to Docker Hub:

docker login -u username

Enter your password when prompted. After logging in, push the tagged image to Docker Hub:

docker push username/mobilenetv3lg-flask:v1.0

Once pushed, you can pull and run the image on another system with:

docker pull username/mobilenetv3lg-flask:v1.0
docker run -p 8000:8000 username/mobilenetv3lg-flask:v1.0

The output during the push confirms that Docker has uploaded the image layers and generated a digest.


Conclusion

In this lesson, you learned how to:

  • Install Docker on an Ubuntu server.
  • Build a Docker image using a Dockerfile that packages a Flask application along with CPU-based PyTorch dependencies.
  • Run a Docker container and verify its operation by sending a test inference request.
  • Tag and push the Docker image to Docker Hub for easy distribution and deployment.

With your Docker image now hosted on Docker Hub, you can seamlessly deploy and share your application across different environments. Next, we will explore containerizing a best-trained model in a lab exercise.

Happy containerizing!

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Introduction to Docker