Table of Contents
- Getting Used to Docker for Machine Learning
- Introduction
- A Quick Recap
- Dockerfile > Docker Image > Docker Container
- Example: Deploying a Flask API Container from Scratch
- Python Code for Flask API to Sum 2 Numbers
- Breaking Down the Dockerfile, Step by Step
- Building an Image from the Dockerfile
- Creating a Container with the Docker Image
- Testing the Container
- Common Docker Commands
- Summary
Getting Used to Docker for Machine Learning
In this tutorial, you will learn about Docker containers for machine learning, how to make a Docker container, how to work with the Docker CLI (command line interface), and much more.
This lesson is the 2nd of a 3-part series on Docker for Machine Learning:
- Getting Started with Docker for Machine Learning
- Getting Used to Docker for Machine Learning (this tutorial)
- Lesson 3
To learn how to create a Docker Container for Machine Learning, just keep reading.
Getting Used to Docker for Machine Learning
Introduction
Docker is a powerful addition to any development environment, and this especially rings true for ML Engineers or enthusiasts who want to get started with experimentation without having to go through the hassle of setting up several drivers, packages, and more.
In today’s blog, we will look at how we can create and build our own containers with a Dockerfile, followed by the most commonly used Docker commands and the concepts behind them.
In short, we will see how we can leverage them to supercharge our development experience.
Let’s get started!
A Quick Recap
In the previous blog post of this series, we saw what containers are, what Docker is supposed to do, and how to set up the NVIDIA Container Toolkit to leverage NVIDIA containers for our workflow.
Containers are simple all-in-one packages that encapsulate everything you need to set up an environment, including files, dependencies, drivers, and more.
You can use Docker to create, handle, manipulate, and run containers on your system locally. It can also be used on Cloud-based providers (e.g., AWS, GCP, Azure, DigitalOcean, etc.) to set up containerized workflows.
With the NVIDIA Container Toolkit, you can use containers to simplify driver setup and experiment rapidly on any hardware, whether on your local machine or the cloud.
Dockerfile > Docker Image > Docker Container
We begin by taking a look at the Dockerfile. What is a Dockerfile, and what should we do with it?
Dockerfile
A Dockerfile can be considered a manifest, or a listed sequence of steps the Docker engine will take to recreate your desired environment. This would include steps related to downloading certain components, performing some commands, and anything that you would do on a simple command line to configure everything from scratch.
This manifest becomes the base on which you develop the next artifact in the chain (i.e., the image).
Docker Image
A Docker Image is the reproducible template that is created when you build the Dockerfile. Images tend to contain everything needed to run the environment. That includes the code, packages, drivers, system tools, etc. They are meant to be immutable, meaning an image will reflect the exact sequence and setup of the original Dockerfile. Another important thing to note is that images tend to have a layered filesystem, meaning you can make an image on top of other images. Images allow you to create multiple containers based on the same structure.
Docker Container
A Docker Container is an encapsulated runtime that gives you all packages, code, system libraries, and runtime tools in a single place. They are built on top of the Docker image and run the defined application. Often, containers are used as self-sufficient packages that can be made to work independently. An example of such a case would be deploying a simple Flask Web API (application programming interface), which would keep running in perpetuity (or until the container is shut down).
Now that we know what each component does, let’s start trying to build them from scratch with a random toy example. We will create a Dockerfile for an API that returns the sum of 2 numbers, create a Docker image for it, and run a container from that image. Let’s get started!
Example: Deploying a Flask API Container from Scratch
First, let’s get our API ready. This should be a fairly quick and straightforward task with the help of Flask! It allows us to start API development within a few lines of simple Python code.
Python Code for Flask API to Sum 2 Numbers
```python from flask import Flask, request app = Flask(__name__) @app.route('/add', methods=['POST']) def add(): numbers = request.get_json() number1 = numbers['number1'] number2 = numbers['number2'] result = number1 + number2 return {'result': result} if __name__ == '__main__': app.run(host='0.0.0.0', port=8000) ```
With that, we now have a boilerplate API ready to deploy. This piece of code allows us to deploy an API that listens on port 8000 for requests with 2 numbers as JSON arguments, sums them up, and returns them as a result.
Let’s look at the Dockerfile now and go line by line.
Breaking Down the Dockerfile, Step by Step
```Dockerfile FROM python:3.10
Using the FROM
command allows you to specify a template pre-existing Docker Image you would like to build your own image on top of. There are thousands of pre-existing images, with several being from official repository maintainers. For example, containers exist to configure NGINX, Redis, and many other popular tools. A common way to prototype with Python containers is to simply build on top of official Python images, available for several different versions.
RUN pip install flask
The RUN
command, allows you to run a shell command as part of the setup. This is useful in interacting with shell utilities and executing scripts. Here, we use it to install Flask as our only dependency. If you have more dependencies warranting the use of a requirements.txt
file, you can use that with the help of the pip install -r requirements.txt
command appended to RUN
.
WORKDIR /app
WORKDIR
tells Docker the directory that would be considered the main working directory for the application. This is where the shell would start and be available for use. It will create a new directory named /app
as specified.
COPY app.py /app/app.py
COPY
allows us to move files and directories from our local device into the image’s file structure. The container will have a parallel file structure from the local device, meaning we must copy the files to access them within the container.
EXPOSE 8000/tcp
EXPOSE
allows us to tell Docker that the container will listen to a certain port while it is running. This can be useful for controlling networking operations, allowing us to specify the protocol (TCP/UDP). For our purposes, we’ll stick to simple TCP.
ENTRYPOINT [ "python", "app.py" ]
ENTRYPOINT
allows us to define a command that will trigger an executable within the container. It also is meant to make the container behave as an executable. This command often starts an application to follow an event-driven loop that listens to incoming traffic. We use it to start our Flask API, which will now listen on Port 8000 for TCP traffic and return a result when the right parameters are passed in the right format.
Building an Image from the Dockerfile
Now, let’s look at building the container. We use the Docker CLI (command line interface) to do so. Navigate to your local working directory and use the following command.
```shell docker build . -t <your-dockerhub-username>/docker-trial-pyimagesearch ```
In this command, we executed the building operation. This will use the Dockerfile and generate an image. Additionally, the -t
(or --tag
) flag is used to give a nametag to your image.
Creating a Container with the Docker Image
Once the process to build is complete, your image is ready to use. Enter the command below to fire up a single container based on that image. We’ll look into this command in detail, too.
```shell docker run -p 8050:8000 <your-dockerhub-username>/docker-trial-pyimagesearch ```
This command will now create a single container with the image you specified. The flag -p
(or --publish
) performs port forwarding. It binds a port of the local machine to a specified port of the container, so all traffic for those ports is routed accordingly. There is no compulsion to have the same ports routed (i.e., you can have a map of type 8050:8000 where port 8000 of the container will bind to port 8050 of the local machine).
Testing the Container
With the container now up and running, let’s test a sample request with cURL (Client for URL). Feel free to use the cURL
command below.
```cURL Request curl -X POST -H "Accept: application/json" -H "Content-Type: application/json" 'http://127.0.0.1:8000/add' -d '{"number1":10, "number2":20}' ```
In this command, we pass 2 headers indicating that we will send JSON data in the request and finally use the -d
flag to pass the parameters. Note how the URL uses the localhost URL, while the actual application runs on the container!
So that’s it! We just went from having a simple Python Flask API on hand to making it a Docker image to be easily deployed. It can be replicated as much as we would like!
Common Docker Commands
Now, let’s look at some common commands for use in Docker so that you can get around the entire ecosystem well. The commands below will allow you to interact with your containers, manipulate them to your requirements, and execute content within them. Let’s get started!
docker ps
This command returns a list of containers that are currently active and running. It returns information about the Container ID and the base Image for the container.
Example: docker ps
Example output:
docker build
This command is used to start building your container from the Dockerfile present in your filesystem structure. Using the -t
flag allows you to tag your build with a name that can be used to reference it later.
Example: docker build . -t suvadityamuk/docker-trial-pyimagesearch
Example output:
docker start
This command starts up a container that may have been previously shut down or stopped. We pass the container ID as an argument.
Example: docker start f4d
Example output:
docker stop
This command shuts down a specific container. For this command, we need the container name or container ID (which can be taken from docker ps
!)
Example: docker stop f4d
Example output:
docker push
This command takes the image you created for a certain Dockerfile and pushes it to Docker Hub. This allows you to use this image from anywhere you log in, with Docker.
Example: docker push suvadityamuk/docker-trial-pyimagesearch
Example output:
docker pull
The inverse of the docker push
command will allow you to pull any Docker image you may have access to. This enables you to use the image and create containers.
Example: docker pull suvadityamuk/docker-trial-pyimagesearch
Example output:
docker login
This is a simple command to log into Docker Hub, to allow for push/pull operations. This is very similar to using GitHub with Git on a local machine.
Example: docker login
Example output:
docker run
This command creates a new container based on a certain image available locally. This highly configurable command has several options to allow for changes like port-forwarding, attaching/mounting data storage volumes, and more.
- Using the
-p
or--publish
flag allows you to bind a port of the container to a certain port on the local machine, such that any traffic to or from the container can be passed through that port on the local machine. - Using the
-d
or--detach
flag allows you to detach the container, such that the container runs in the background while allowing the use of the terminal as usual. - Using the
--cpus
flag allows you to pass how many CPU cores you’d like the container to use. - Using the
--memory
flag allows you to pass how much memory the container should be able to use. - Using the
--gpus
flag allows you to pass which GPUs on the local machine should be available to the container. One can pass the--gpus all
flag argument for allowing all GPUs. Note that, to make this work, we need the NVIDIA Container Runtime.
Example: docker run -p 8000:8000 -–cpus 1 -–gpus all suvadityamuk/docker-trial-pyimagesearch
Example output:
docker exec
This allows you to execute a certain command on a container. This is useful to open a terminal session inside a container or perform some kind of checks and so on. We must pass the container ID as an argument.
- The command passed can also be an executable (here, we actually use the
/bin/bash
executable to start a bash shell session).
Example: docker exec -it f412 /bin/bash
Example output:
docker attach
This lets us connect the container’s internal bash terminal directly with our current local machine’s terminal session. Any commands executed in this environment are executed within the container.
Example: docker attach f412
docker kill
This command allows us to kill a container’s internal process. The container is sent a SIGKILL signal, which normally tends to terminate the container itself.
Example: docker kill ae86
Example output:
docker commit
This command is used to commit changes made to a certain image in a git-like fashion. Changes internally made to an image (e.g., moving directories/files) can induce changes that require the image to be built again. If you wish to reflect this new image across Docker Hub, we can commit and push the changes ahead.
- The changes are reflected in the Dockerfile, so we can only write Dockerfile-compatible statements. In the example below, we create a dummy Environment variable called
test_env
and set its value toTrue
. The command returns a SHA hash reflecting the commit hash.
Example: docker commit -c "ENV test_env=true" d470 suvadityamuk/docker-trial-pyimagesearch:latest
Example output:
docker rm
This command is used to delete a certain container. It is important to ensure that the container is already shut down. If it is not, and you still wish to shut it down, we must use the -f
flag to force the removal.
Example: docker rm d470
Example output:
docker rmi
This command is used to delete a certain image from the local machine. Doing this means that we cannot use the image again to create containers until we download or pull it back on. If there are running containers that use the chosen image, we must use the -f
flag to force removal.
Example: docker rmi suvadityamuk/docker-trial-pyimagesearch
Example output:
docker search
This allows us to search for images on Docker Hub with their names or other specific filters.
Example: docker search python
Example output:
docker restart
This command stops and restarts a container.
Example: docker restart
Example output:
docker rename
This command is used to change the human-readable name of a container.
Example: docker rename 4d8d "my-container"
Example output:
What's next? We recommend PyImageSearch University.
86 total classes • 115+ hours of on-demand code walkthrough videos • Last updated: October 2024
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled
I strongly believe that if you had the right teacher you could master computer vision and deep learning.
Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?
That’s not the case.
All you need to master computer vision and deep learning is for someone to explain things to you in simple, intuitive terms. And that’s exactly what I do. My mission is to change education and how complex Artificial Intelligence topics are taught.
If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to successfully and confidently apply computer vision to your work, research, and projects. Join me in computer vision mastery.
Inside PyImageSearch University you'll find:
- ✓ 86 courses on essential computer vision, deep learning, and OpenCV topics
- ✓ 86 Certificates of Completion
- ✓ 115+ hours of on-demand video
- ✓ Brand new courses released regularly, ensuring you can keep up with state-of-the-art techniques
- ✓ Pre-configured Jupyter Notebooks in Google Colab
- ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
- ✓ Access to centralized code repos for all 540+ tutorials on PyImageSearch
- ✓ Easy one-click downloads for code, datasets, pre-trained models, etc.
- ✓ Access on mobile, laptop, desktop, etc.
Summary
That’s it! In this blog post, we look at the following:
- What makes a Docker container
- What are the components and steps to create a Docker container
- What a sample container for a simple Flask App looks like
- How we can manipulate containers using the Docker CLI (command line interface)
- We discuss how containers can be used as self-contained executables
In the next blog post, we will get completely hands-on and see how to set up a full Jupyter environment through Docker on a GPU-enabled machine on a Cloud service.
Citation Information
Mukherjee, S. “Getting Used to Docker for Machine Learning,” PyImageSearch, P. Chugh, A. R. Gosthipaty, S. Huot, K. Kidriavsteva, and R. Raha, eds., 2023, https://pyimg.co/hf5bk
@incollection{Mukherjee_2023_Docker4ML-P2, author = {Suvaditya Mukherjee}, title = {Getting Used to Docker for Machine Learning}, booktitle = {PyImageSearch}, editor = {Puneet Chugh and Aritra Roy Gosthipaty and Susan Huot and Kseniia Kidriavsteva and Ritwik Raha}, year = {2023}, url = {https://pyimg.co/hf5bk}, }
Unleash the potential of computer vision with Roboflow - Free!
- Step into the realm of the future by signing up or logging into your Roboflow account. Unlock a wealth of innovative dataset libraries and revolutionize your computer vision operations.
- Jumpstart your journey by choosing from our broad array of datasets, or benefit from PyimageSearch’s comprehensive library, crafted to cater to a wide range of requirements.
- Transfer your data to Roboflow in any of the 40+ compatible formats. Leverage cutting-edge model architectures for training, and deploy seamlessly across diverse platforms, including API, NVIDIA, browser, iOS, and beyond. Integrate our platform effortlessly with your applications or your favorite third-party tools.
- Equip yourself with the ability to train a potent computer vision model in a mere afternoon. With a few images, you can import data from any source via API, annotate images using our superior cloud-hosted tool, kickstart model training with a single click, and deploy the model via a hosted API endpoint. Tailor your process by opting for a code-centric approach, leveraging our intuitive, cloud-based UI, or combining both to fit your unique needs.
- Embark on your journey today with absolutely no credit card required. Step into the future with Roboflow.
Enter your email address below to join the PyImageSearch Newsletter and download my FREE 17-page Resource Guide PDF on Computer Vision, OpenCV, and Deep Learning.Join the PyImageSearch Newsletter and Grab My FREE 17-page Resource Guide PDF
Comment section
Hey, Adrian Rosebrock here, author and creator of PyImageSearch. While I love hearing from readers, a couple years ago I made the tough decision to no longer offer 1:1 help over blog post comments.
At the time I was receiving 200+ emails per day and another 100+ blog post comments. I simply did not have the time to moderate and respond to them all, and the sheer volume of requests was taking a toll on me.
Instead, my goal is to do the most good for the computer vision, deep learning, and OpenCV community at large by focusing my time on authoring high-quality blog posts, tutorials, and books/courses.
If you need help learning computer vision and deep learning, I suggest you refer to my full catalog of books and courses — they have helped tens of thousands of developers, students, and researchers just like yourself learn Computer Vision, Deep Learning, and OpenCV.
Click here to browse my full catalog.