DEV Community

Cover image for Docker with Python for Dummies
Jesse Ilc
Jesse Ilc

Posted on • Edited on

Docker with Python for Dummies

TLDR @ bottom

Overview

Docker is a powerful tool for creating, deploying, and managing applications in containers. It allows you to package your application and its dependencies into a single container, making it easy to run consistently across different environments. It basically functions like a VM (virtual machine) if you're familiar with that. However, there are differences which I won't get into but here's a great video that provides more information.

Docker
"Docker's container-based platform allows for highly portable workloads." - docs.docker.com

In this read, I hope to give you the basic knowledge to help set up Docker in your project. Without further ado let's get started.

Prerequisites

I assume that you already have Python installed but if not click here, you're going to need it. I also assume that you already have some basic knowledge of Python so this will not cover any Python fundamentals.

First we need to install Docker. We can visit the site here to install what we need. For Mac user's it's really easy; just click and install. However for Windows it's a bit more complicated because we need to use WSL. Here's a great video that gives an awesome tutorial on how to install Docker on WSL. The Docker site here also provides a tutorial as well. Feel free to use whichever one you like. Once you have Docker installed make sure you have it running before you type any docker commands otherwise they won't work.

Step 1: Python Project Structure

You can either create a new project or I'm assuming you're probably looking to add this to an existing project. Either way the process is the same. A very basic Python project might look something like this:

my_python_project/
    └── app.py
Enter fullscreen mode Exit fullscreen mode

Very basic. Let's assume however you plan on adding dependencies to your project. You might have a Pipfile and Pipfile.lock, you also might also be using pipenv. To make our lives easier we're going to add a requirements.txt somewhere in our working directory. So our file structure will look like this now:

my_python_project/
    └── app.py
    └── requirements.txt
Enter fullscreen mode Exit fullscreen mode

In our requirements.txt we're going to make a list of the dependencies which we need for our project. This will come in handy later. The requirements.txt will look something like this:

# /requirements.txt

Flask==2.1.0
SQLAlchemy==1.4.30
requests>=2.25.0
numpy~=1.21.2
Enter fullscreen mode Exit fullscreen mode

Step 2: Dockerfile / .dockerignore

1. Dockerfile
In order to actually use Docker we need to include a Dockerfile in the root directory. To do this you simply create a new file and name it Dockerfile.

my_python_project/
    └── app.py
    └── requirements.txt
    └── Dockerfile
Enter fullscreen mode Exit fullscreen mode

Let's talk about what goes into our Dockerfile.

FROM

FROM determines what application platform our parent image will use in docker. In this case we will use Python 3.8.

# /Dockerfile

FROM python:3.8
Enter fullscreen mode Exit fullscreen mode

WORKDIR

WORKDIR determines what the working directory is in the parent image. In this case our working directory will be /app however for you it may be different.

# /Dockerfile

FROM python:3.8

WORKDIR /app
Enter fullscreen mode Exit fullscreen mode

COPY

COPY will literally copy all of the contents in a
specified location. In our case we want to copy /app and requirements.txt.

# /Dockerfile

FROM python:3.8

WORKDIR /app

COPY requirements.txt .

COPY app .
Enter fullscreen mode Exit fullscreen mode

RUN

RUN will run any commands you specify. This is where we want to include our dependencies and any other commands we want to run prior to running the application. Because we created a requirements.txt we don't need to pip install each of our dependencies, only the requirements.txt.

Note: It's important to install our dependencies first before we copy our app to speed up subsequent builds. For more information follow the link here.

# /Dockerfile

FROM python:3.8

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY app .
Enter fullscreen mode Exit fullscreen mode

EXPOSE

EXPOSE will make any ports available that are needed for your project. This is helpful if you're using python for web development. In this case we will expose the port 5555.

# /Dockerfile

FROM python:3.8

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY app .

EXPOSE 5555
Enter fullscreen mode Exit fullscreen mode

CMD

CMD will be the final command that Docker will run in order to start your application. This will be written as a list and not include spaces. For example the code to run our application would be python app.py. In the Dockerfile that would like this ["python", "app.py"].

# /Dockerfile

FROM python:3.8

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY app .

EXPOSE 5555

CMD ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode

Here is the Docker documentation for more information on various other commands.

2. .dockerignore

.dockerignore will tell Docker what files to ignore when building an image. In our case we have nothing to ignore but in case you do here is a list of some items you can include (link to the repo):

# /.dockerignore

# Git
.git
.gitignore
.gitattributes


# CI
.codeclimate.yml
.travis.yml
.taskcluster.yml

# Docker
docker-compose.yml
Dockerfile
.docker
.dockerignore

# Byte-compiled / optimized / DLL files
**/__pycache__/
**/*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Virtual environment
.env
.venv/
venv/

# PyCharm
.idea

# Python mode for VIM
.ropeproject
**/.ropeproject

# Vim swap files
**/*.swp

# VS Code
.vscode/
Enter fullscreen mode Exit fullscreen mode
my_python_project/
    └── app.py
    └── requirements.txt
    └── Dockerfile
    └── .dockerignore
Enter fullscreen mode Exit fullscreen mode

Step 3: Building The Docker Image

Once your Dockerfile is completed and you have Docker running in the background you can begin to build the image. To do so you want to open your terminal and navigate to your project directory where the Dockerfile is located. Now we want to run the following command:

docker build -t my-python-app .
Enter fullscreen mode Exit fullscreen mode

The -t flag lets Docker know what we want to call the image. So whatever follows -t will be the image name. The . indicates the directory so don't forget it or the build won't run.

Once the build runs you should see the following in your terminal:

What's Next?
  View summary of image vulnerabilities and recommendations → docker scout quickview
Enter fullscreen mode Exit fullscreen mode

Step 4: Run your Docker Container

Once you run your build you can start your container with the following command:

docker run -p 5555:5555 my-python-app
Enter fullscreen mode Exit fullscreen mode

-p 5555:5555 maps port 5555 on your local machine to port 5555 in the Docker container. You can change these ports to whatever your needs are.

Conclusion

Docker is a powerful tool that you can use to your advantage. It simplifies the process of packaging and deploying your Python applications, making them more portable and consistent across different environments. You can further customize your Docker setup to suit the needs of your project and deploy it to various platforms. I hope that this guide was helpful to you and good luck to any projects you work on. Happy coding!

TLDR

File Stucture

my_python_project/
    └── app.py
    └── requirements.txt
    └── Dockerfile
    └── .dockerignore
Enter fullscreen mode Exit fullscreen mode

Dockerfile

# /Dockerfile

# Use an official Python runtime as a parent image
FROM python:3.8



COPY app .

# Set the working directory in the container
WORKDIR /app

# copy the dependencies file to the working directory
COPY requirements.txt .

# Install any needed packages specified in requirements.txt or run any commands prior to starting your app
RUN pip install -r requirements.txt

# Copy the current directory contents into the container at /app
COPY app .

# Make port 5555 available to the world outside this container
EXPOSE 5555

# Define the command to run your application
CMD ["python", "app.py"]
Enter fullscreen mode Exit fullscreen mode

.dockerignore

# /.dockerignore
# list of files/folder that can be ignored

# Git
.git
.gitignore
.gitattributes


# CI
.codeclimate.yml
.travis.yml
.taskcluster.yml

# Docker
docker-compose.yml
Dockerfile
.docker
.dockerignore

# Byte-compiled / optimized / DLL files
**/__pycache__/
**/*.py[cod]

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.cache
nosetests.xml
coverage.xml

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Virtual environment
.env
.venv/
venv/

# PyCharm
.idea

# Python mode for VIM
.ropeproject
**/.ropeproject

# Vim swap files
**/*.swp

# VS Code
.vscode/
Enter fullscreen mode Exit fullscreen mode

Build Image Command:

docker build -t my-python-app .
Enter fullscreen mode Exit fullscreen mode

note: -t my-python-app tags the image with the name "my-python-app".

Run Image Command:

docker run -p 5555:5555 my-python-app
Enter fullscreen mode Exit fullscreen mode

note: -p 5555:5555 maps port 5555 on your local machine to port 5555 in the Docker container.

Sources

Top comments (2)

Collapse
 
glours profile image
Guillaume

Hey 👋
There is some potential improvements for you Dockerfile, the main one is to install your dependencies before copy your source to use layers caching efficiently.
You can take a look to this blog post series which could help you to make a efficient containerization of your Python app for prod and development 😉
docker.com/blog/containerized-pyth...

Collapse
 
jesseilc123 profile image
Jesse Ilc

Thanks for the pointer! I made some changes according to your suggestion including the link you provided. Appreciate the help!