py & docker

Now is the era of containers, cooperation between teams must be packaged unified Docker Image to solve the problem of inconsistent environment, but the size of the container determines the time to deploy microservices, this article to introduce how to build the smallest Python container. If you need to collaborate across departments, Docker is definitely the best tool for you, so you don’t have to bother with the environment. The following Flask application shows how to write a Dockerfile.

Writing the Flask service

Use the Flask service as an example directly and store the file in src/server.py.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from flask import Flask

server = Flask(__name__)

@server.route("/")
def hello():
  return "Hello World!"

if __name__ == "__main__":
  server.run(host='0.0.0.0')

Write all related packages in requirements.txt.

1
2
Flask==1.1.1
gunicorn==20.1.0

The developer can write all the dependency packages with the following commands.

1
pip freeze > requirements.txt

Writing a Dockerfile

Find the official Python Docker Image page, which has an example of how to write a Dockerfile.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
FROM python:3.9

WORKDIR /app

COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY src /app

CMD [ "python", "server.py" ]

If you don’t care much about the image size, there is nothing wrong with writing it this way. To create a smaller Image, you can start with FROM. In fact, it is officially mentioned that if you want to use it as Production, it is recommended to use python:<version>-slim, which removes all unnecessary packages and leaves only the most basic Python packages to run. developers can use this image to overlay the packages they want to use, so the image will be minimal. Let’s replace python:3.9 with python:3.9-slim.

In addition to slim, I would personally recommend using the alpine version (previous introductory article), where the entire In order to reduce the system to such a small size, Alpine version removes most of the software, including git or bash large packages, so basically, after logging into the system, it is almost empty, and you have to install all the packages yourself, which is very suitable for microservices and can achieve rapid deployment.

python3.9 python3.9-slim python3.9-alpine
842MB 118MB 55.8MB

Please note that you must process the requirements.txt part first, and then process the COPY file, so that you can enjoy the advantages of Layer Cache, otherwise the whole build image time will not be saved after the Source Code changes.

Using Multistage Build

In addition to using the smallest size Alpine Image, you can also use Multistage Build to copy the required files into a new Image for final packing, and change the writing style as follows to reduce some space.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FROM python:3.9-alpine as base
FROM base as builder
COPY requirements.txt /requirements.txt
RUN pip install --user -r /requirements.txt

FROM base
# copy only the dependencies installation from the 1st stage image
COPY --from=builder /root/.local /root/.local
COPY src /app
WORKDIR /app

# update PATH environment variable
ENV PATH=/home/app/.local/bin:$PATH

CMD ["/bin/sh"]

Take a look at the results below.

python3.9 python3.9-slim python3.9-alpine python3.9-alpine (Multistage)
842MB 118MB 55.8MB 48.8MB

Here the files are placed under the root with --user, and then copied to another image with COPY --from=builder.