Run Python in Raspberry PI Containers with Docker
Last Updated on 1st December 2024 by peppe8o
This tutorial will show you how to setup and run Python in Raspberry PI Containers with Docker so that you can run your Python script in isolated containers.
Why Running Python Scripts in Docker Containers
Containers have been a revolution in ICT: they are used in large infrastructures as well as in small projects because they allow developers to keep their programs isolated from the host machine and easy to manage.
Together with Python, containers can allow you to run your scripts and apps in an efficient environment, bringing many advantages:
- Portability: Docker containers can include all the Python libraries and configurations you need inside the container. This will allow you to run the same Python script in any environment (development, testing, production) and host without worrying about versions or dependencies. With the use of a Dockerfile you can completely define the environment, making it easy to reproduce the same setup or backup it for a new installation or for moving to a Cloud environment.
- Isolation: Containers are isolated from the host machine so that the installed libraries will not affect other Python scripts running on the same PC. Moreover, you can use different library versions on the same PC (by using different containers), preventing any conflict or interference.
- upgrades/downgrades: with containers you can test different versions of Python or any other dependency without affecting the working container, so you can try the newest Python versions without risking breaking other parts of your system.
- Reproducibility for Data Science / Machine Learning Projects: with Docker, you can package complex dependencies like machine learning libraries (e.g., TensorFlow, PyTorch, scikit-learn) and datasets in a container. This allows you to easily reproduce and share the entire environment with others.
Differently from Python virtual environments, Docker containers allow you to have higher isolation from the host system, as the latter also isolates the OS components. Moreover, Docker containers allow you to scale up the infrastructure as you need.
What We Need
As usual, I suggest adding from now to your favourite e-commerce shopping cart all the needed hardware, so that at the end you will be able to evaluate overall costs and decide if to continue with the project or remove them from the shopping cart. So, hardware will be only:
- Raspberry PI Computer Board (including proper power supply or using a smartphone micro USB charger with at least 3A)
- high speed micro SD card (at least 16 GB, at least class 10)
Step-by-Step-Procedure
Prepare the Operating System and Install Docker
The first step is installing the Raspberry PI OS Lite (please note that we need the 64-bit version) to get a fast and light operating system (headless). In this case, you will need to work from a remote SSH terminal. If you need a desktop environment, you can also use the Raspberry PI OS Desktop, in this case working from its terminal app. Please find the differences between the 2 OS versions in my Raspberry PI OS Lite vs Desktop article.
Make sure that your OS is up to date. From your terminal, use the following command:
sudo apt update -y && sudo apt upgrade -y
We also need to install Docker. For this process, please refer to my Beginner’s Guide to Install and Use Docker with Raspberry PI. Please make sure to enable your user to use Docker without the need of sudo.
Python Containers with Docker Hub
When using Docker, you can get free images from something like a marketplace: the Docker Hub. It includes a huge number of container images (from official and unofficial authors), supporting different platform architectures (386, amd64, arm v5, arm v7, arm64, ppc64le, and so on). From these images, we can use only those compatible with our Raspberry PI. Generally, the official Python images support all the Raspberry PI architectures. If you’re curious about your one, you can check it with the hostnamectl
command. In my case:
pi@raspberrypi:~ $ hostnamectl
Static hostname: raspberrypi
Icon name: computer
Machine ID: 1a2846ba11a84f068bf682dcba26cce3
Boot ID: 1209cc6b4ba74ac5904f46e1e7a28a6b
Operating System: Debian GNU/Linux 12 (bookworm)
Kernel: Linux 6.6.47-v8+
Architecture: arm64
About the Python images, there are different tags available from the Python page in Docker Hub. At the date of this tutorial, the “3” tag is the most complete and most recent, but it requires a bit of disk space (the uncompressed image takes around 1GB).
There are many alternative images like, for example, those having “slim” in the tag name, which require less space. On the other hand, these images may not support all the library installations you may need. So, you have to test them.
In this tutorial, we’ll use the “Python:3” image. Moreover, we’ll build our custom container starting from this image, adding the needed libraries.
Hello World Python in Raspberry PI Container
Our Hello World container doesn’t make real sense as you don’t need to install any library and you can just run a Python script printing “Hello World!” without the need for any container. Nevertheless, it’s important to understand how to approach Python containers.
Before starting, I suggest you create a specific folder for docker and, inside it, specific subfolders for any project. In this way, your life will be simpler if you will backup your Raspberry PI folders for security purposes. Moreover, inside the project, you can create an “app” folder which will include all your scripts.
So, please create the folder path:
mkdir docker/python-hello/app -p
Enter to the app folder:
cd docker/python-hello/app/
Here we’ll create our very simple hello world script:
nano myscript.py
Put the following print statement inside the container. It will just print a simple message in your console:
print("Hello world by peppe8o.com")
Save and close. Now, you can go to the upper level, where we’ll create our Docker build environment:
cd ..
The Hello-World Dockerfile
Create a file named “Dockerfile”. It is important to note that it is the default name for the docker build
command, which we’ll use to create a custom image with our Python script.
nano Dockerfile
Fill the file with the following content:
FROM python:3
WORKDIR /usr/src/app
COPY ./app/myscript.py ./
CMD [ "python3", "./myscript.py" ]
Save and exit. It tells Docker to perform the following operations while building our custom image:
- use the python:3 image getting it from Docker Hub (if not available locally)
- set the Working Directory to
/usr/src/app
inside the container (move to it inside the container) - Copy the file myscript.py from the host storage (inside the app folder previously created) to the container (inside the current Working Directory)
- set as main command of the container the command “python3 ./myscript.py” (running it from the Working Directory).
The main command is one of the most important things in containers, as containers live as long as the main command has something to do. When the main command exits (for example because it ended its job or returned an error) the container “dies”.
At this point, your folder should be as follows:
└── docker
└── python-hello
├── app
│ └── myscript.py
└── Dockerfile
Build and Run the Hello-World Script
Now, we can build our custom Docker image. From the folder where the Dockerfile is located, please issue the following command:
docker build -t my-python-hello . --no-cache
It will start by downloading the base image (only for the first build) and preparing the container according to the Dockerfile. From this command:
- “-t my-python-hello“: it gives a name (tag) for your custom image in your Docker environment. You can also add a colon after the image name and give it a specific version (for example “my-python-hello:0.1”). You can list all the current images in your Raspberry PI with the
docker images
command. - “.”: the dot in the command may appear as a banal option. It tells the Docker build command to set the current folder as build context. This means that it will look for the Dockerfile in the current folder and search any required resource inside it
- “–no-cache“: you may need to build several times the same container image as you test different options and/or different Dockerfiles. This option avoids that Docker uses cached layers, making your changes ineffective
With the new container built, you can run it with the following docker run command:
docker run -it --rm my-python-hello
It will execute the print statement and return the set hello message:
pi@raspberrypi:~/docker/python-hello $ docker run -it --rm my-python-hello
Hello world by peppe8o.com
Please note that the “–rm” option in the above docker run command will delete the container after it finishes the job.
Complex Python Raspberry PI Containers
More complex projects will require installing dependencies and sharing data between the host and container. In these cases, we must add a “pip” installation step in the Dockerfile and map a volume for the static data of your container. I will show you how to perform these actions by using as an example a web crawler with Python and Scrapy.
Let’s go back to the “docker” folder, create a new subfolder for this project, and enter it:
cd ..
mkdir py-crawler
cd py-crawler
The first file to prepare is the requirement.txt, which will include all the Python libraries to install via PIP:
nano requirements.txt
This project requires only 2 libraries: “scrapy” and “cryptography”. You can paste these 2 libraries inside the requirements.txt file. Please note that you can optionally specify the versions, as in any requirements.txt file.
scrapy
cryptography
Save and close.
Now, let’s create the “app” folder, which will include the running script together with all the data we’ll create from the container, and enter it:
mkdir app
cd app/
Let’s create our Python script:
nano my-crawler.py
And paste here the crawler code:
import scrapy
class QuotesSpider(scrapy.Spider):
name = "peppe8o"
start_urls = [
'https://peppe8o.com',
]
def parse(self, response):
for posts in response.css('div.post-wrapper article'):
yield {
'Title': posts.css('h2.entry-title a::text').get(),
'Description': posts.css('div.post-content p::text').get(),
'Date': posts.css('time::text').get(),
}
Save and close.
The Python Dockerfile
Now, back to the higher level folder, let’s create our Dockerfile:
cd ..
nano Dockerfile
Paste the following lines:
FROM python:3
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY ./app/my-crawler.py ./my-crawler.py
CMD ["scrapy", "runspider", "my-crawler.py", "-o", "peppe8o.json"]
Save and close. Differently from the previous Dockerfile, this includes the copy of the requirements.txt file and the installation of all the packages in the “RUN” line.
At this point, your directory should be as follows:
└── docker
└── py-crawler
├── app
│ └── my-crawler.py
├── Dockerfile
└── requirements.txt
Build and Run the Python Script
You can now build the my-crawler image:
docker build -t my-crawler . --no-cache
At the end of this command, we can run our crawler container with the following docker run command:
docker run -it --rm --name my-running-crawler -v /home/pi/docker/py-crawler/app:/usr/src/myapp -w /usr/src/myapp my-crawler
In this command, the news are the following:
- –name my-running-crawler: gives a specific name to the container, so that you can clearly identify it in the running containers while executing with the
docker ps -a
command - -v /home/pi/docker/py-crawler/app:/usr/src/myapp: it maps a persistent volume with the host folder “/home/pi/docker/py-crawler/app” containing the same files of the “/usr/src/myapp” folder in the container
- -w /usr/src/myapp: it sets the working directory in the container. We need this again as it tells the Python script to save the output files in this folder inside the container
After you run this command, you will find the “peppe8o.json” output file in the “app” folder from the host storage in the current path
Next Step
Interested in more Raspberry PI projects? Take a look at peppe8o Raspberry PI tutorials to find cool ideas.
Enjoy!
Docker containers seems similar to running Django in a virtual environment. I do not understand it deleting the container when the script finishes. What do you have to do to restart the script? I’ve never heard of Docker before so I’m very new to these concepts.
Hi Ron,
docker containers are quite different from virtual environments and they are the base for microservices. While in virtual environments you can create programs only based on a specific programming language, containers allow you to create infrastructures with different parts, where each part can be different from the others. This is the reason why they are really loved from developers.
Back your question, containers will always tend to reduce the used resources. If a container ends its job, there’s no reason to get it occuping space or any resources. At any time you can run again the container with the same docker run command. Please remember that if you need to save data you must use persistent volumes as shown in the tutorial (otherwise they will be erased with the container).
An important consideration to do is that containers ARE NOT virtual machines, even if they may appear similar in some cases.
I think that if you try docker containers you will appreciate the flexibility and power of them.
Cheers, Giuseppe