Python Docker
last modified January 29, 2024
Python Docker tutorial shows how to use Docker for Python applications.
Docker
Docker is a platform for developers and sysadmins to build, run, and share applications with containers. Docker facilitates application portability and scalability. Docker provides application isolation and thus eliminates many issues caused by library and environment differences. It helps automate development and deployment. With predefined community images, developers save time and improve their overall experience.
A Docker image is a read-only template with instructions for creating a Docker container. A Docker container is a runnable instance of an image.
Docker images are stored in repositories. The Docker Hub is the official Docker repository. Docker Engine is the underlying client-server technology that builds and runs containers using Docker's components and services.
A Dockerfile is a special file which contains instructions needed to build the Docker image.
$ sudo docker --version Docker version 19.03.12, build 48a66213fe
This is the Docker version we use.
Python Docker hello example
In the following example, we create and run a very simple Docker image. When we run the image, a simple Python file is executed.
#!/usr/bin/python
import sys
print("hello there!")
print(sys.version)
This is the simple file to be executed inside the container.
FROM python:3.8 COPY hello.py /tmp/ CMD ["python", "/tmp/hello.py"]
These are the instructions to build the Docker image.
FROM python:3.8
We base our image on the community python:3.8 image.
COPY hello.py /tmp/
The COPY instruction copies the hello.py file into the
image's tmp directory.
CMD ["python", "/tmp/hello.py"]
The CMD instruction lauches the Python program.
$ sudo docker build -t hello .
We build the image and name it hello.
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello latest 60251c18f538 5 minutes ago 882MB firstimage latest 319917db1025 5 hours ago 111MB python slim 38cd21c9e1a8 5 days ago 113MB python 3.8 79cc46abd78d 5 days ago 882MB python latest 79cc46abd78d 5 days ago 882MB
We list the available images with the docker images command.
$ sudo docker run hello hello there! 3.8.5 (default, Aug 5 2020, 08:22:02) [GCC 8.3.0]
We run the hello image.
Python Docker interactive mode
We can run the image in interactive mode by using the -it option.
The -it instructs Docker to allocate a pseudo-TTY connected to the
container's stdin; creating an interactive bash shell in the container.
$ sudo docker run -it python3.8:slim bash root@98ece0c01946:/#
We run the image and get the bash shell inside the container.
root@98ece0c01946:/# python -c "import os; print(os.system('ls -l'))"
total 68
drwxr-xr-x 1 root root 4096 Aug 4 16:25 bin
drwxr-xr-x 2 root root 4096 Jul 10 21:04 boot
drwxr-xr-x 5 root root 360 Aug 19 13:40 dev
drwxr-xr-x 1 root root 4096 Aug 19 13:39 etc
drwxr-xr-x 2 root root 4096 Jul 10 21:04 home
drwxr-xr-x 1 root root 4096 Aug 4 16:25 lib
drwxr-xr-x 2 root root 4096 Aug 3 07:00 lib64
drwxr-xr-x 2 root root 4096 Aug 3 07:00 media
drwxr-xr-x 2 root root 4096 Aug 3 07:00 mnt
drwxr-xr-x 2 root root 4096 Aug 3 07:00 opt
dr-xr-xr-x 345 root root 0 Aug 19 13:40 proc
drwx------ 1 root root 4096 Aug 4 16:18 root
drwxr-xr-x 3 root root 4096 Aug 3 07:00 run
drwxr-xr-x 2 root root 4096 Aug 3 07:00 sbin
drwxr-xr-x 2 root root 4096 Aug 3 07:00 srv
dr-xr-xr-x 13 root root 0 Aug 19 13:40 sys
drwxrwxrwt 1 root root 4096 Aug 11 20:37 tmp
drwxr-xr-x 1 root root 4096 Aug 3 07:00 usr
drwxr-xr-x 1 root root 4096 Aug 3 07:00 var
0
We can run Python code.
root@98ece0c01946:/# python -c "import sys; print(sys.version)" 3.8.5 (default, Aug 4 2020, 16:24:08) [GCC 8.3.0]
In our case, we have Python 3.8.5 preinstalled.
Python Docker get request
In the next example, we build an image which retrieves an HTML page.
We use the requests library, which must be installed in the image.
#!/usr/bin/python
import requests as req
resp = req.get("http://webcode.me")
print(resp.text)
The code example retries a simpe web page by issuing a GET request.
FROM python:slim RUN pip install requests COPY get_req.py /tmp/ CMD ["python", "/tmp/get_req.py"]
This is the Dockerfile.
FROM python:slim
In this example, we use the community python:slim image, which
occupies much less space.
RUN pip install requests
With the RUN instruction, we execute the pip manager
and install the requests module.
COPY get_req.py /tmp/
The COPY instruction copies the get_req.py file from
our host computer to the container's /tmp/ directory.
The directory is created if it does not exist.
CMD ["python", "/tmp/get_req.py"]
The CMD instruction runs the program upon starting the container.
$ sudo docker build -t pygetreq .
We build the image and call it pygetreq.
$ sudo docker images | grep pygetreq pygetreq latest 0d3c5953ff60 23 seconds ago 121MB
This image requires only 121MB.
$ sudo docker run pygetreq
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My html page</title>
</head>
<body>
<p>
Today is a beautiful day. We go swimming and fishing.
</p>
<p>
Hello there. How are you?
</p>
</body>
</html>
Python Docker Flask
In the next example, we run a simple Flask application in a Docker container.
#!/usr/bin/python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello there!'
This is a simple Flask application with one home route.
FROM python:slim COPY app.py /app/ WORKDIR /app RUN pip install flask RUN export FLASK_APP=app.py EXPOSE 5000 CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]
This is the Dockerfile.
FROM python:slim
We base our image on the python-slim image.
COPY app.py /app/ WORKDIR /app
We copy a file to a directory on the image and set the working directory. If the directory does not exist yet, it is created.
RUN pip install flask
With the RUN instruction, we install Flask.
RUN export FLASK_APP=app.py
We set the FLASK_APP environment variable to the app.py
application file.
EXPOSE 5000
We expose the port.
CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]
With the CMD instruction, we set the default command that is run
when the container starts. We set the host IP to 0.0.0.0 so that
the application is accessible outside the container.
$ sudo docker build -t flasksimple .
We build the image.
$ docker run -p 5000:5000 flasksimple
We run the image. The container's 5000 port is mapped to our computer's 5000 port.
$ curl localhost:5000/ Hello there!
With the curl tool, we generate a GET request to the application.
Python Docker MariaDB
In the following example, we create a container based on the mariadb
image.
USE testdb;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
This is the SQL code for the cities table.
FROM mariadb
RUN apt-get update && apt-get install -y \
python3.8 \
python3-pip
RUN pip3 install pymysql
ADD schema.sql /docker-entrypoint-initdb.d
ENV MYSQL_USER=user7
ENV MYSQL_PASSWORD=7user
ENV MYSQL_DATABASE=testdb
ENV MYSQL_ROOT_PASSWORD=s$cret
EXPOSE 3306
We derive our image from the mariadb image.
RUN apt-get update && apt-get install -y \
python3.8 \
python3-pip
On the image, we install Python and pip.
RUN pip3 install pymysql
We install the pymysql driver.
ADD schema.sql /docker-entrypoint-initdb.d
SQL scripts under /docker-entrypoint-initdb.d directory are run
at initialization of the container. We copy the schema file with the ADD
instruction.
ENV MYSQL_USER=user7 ENV MYSQL_PASSWORD=7user ENV MYSQL_DATABASE=testdb ENV MYSQL_ROOT_PASSWORD=s$cret
With environment variables, we create a new user, a new database, and set a password for root user.
EXPOSE 3306
The EXPOSE instruction informs Docker that the container listens on
the specified network ports at runtime.
#!/usr/bin/python
import pymysql
con = pymysql.connect(host='localhost', user='user7',
password='7user', database='testdb', port=3306)
try:
with con.cursor() as cur:
cur.execute('SELECT * FROM cities')
rows = cur.fetchall()
for row in rows:
print(f'{row[0]}, {row[1]}, {row[2]}')
finally:
con.close()
The example connects to the MariaDB testdb database, which is running
inside the container. It shows all rows from the cities table.
$ sudo docker build -t pymaria-simple .
Sending build context to Docker daemon 4.608kB
Step 1/9 : FROM mariadb
---> b95867b52886
Step 2/9 : RUN apt-get update && apt-get install -y python3.8 python3-pip
---> Using cache
---> 9370769248ed
Step 3/9 : RUN pip3 install pymysql
---> Using cache
---> 108146aaa2d8
...
We build the image.
$ sudo docker run -p 3306:3306 pymaria-simple
We run the container from the custom pymaria-simple image.
With the -p option, we publish a container's 3306 port to the
host port 3306.
$ ./app.py 1, Bratislava, 432000 2, Budapest, 1759000 3, Prague, 1280000 4, Warsaw, 1748000 5, Los Angeles, 3971000 6, New York, 8550000 7, Edinburgh, 464000 8, Berlin, 3671000
After the container is started, we run the app.py program, which
shows the cities.
Source
In this article we have worked with Python and Docker.
Author
List all Python tutorials.