Some time ago I start an article about microservices but I got no time to continue the series. Nevertheless, I’ll publish the first one of the series. It’s a simple yet effective article on how to optimize often tremendous by size images to something that takes a lot less space and therefore can be run much faster.

The original code of a Dockerfile to run quite a simple python app looks like this:

FROM ubuntu:latest
WORKDIR /app
COPY ./app /app
RUN apt-get update && apt-get install python3 -y
RUN apt-get update && apt-get install python3-pip -y
RUN pip install requests==2.27.1
ENTRYPOINT [“echo”,”Hello”]

The result after we build the Dockerfile:

~/repo/docker-articles$ time docker build . -t original:0.1 --quiet
docker build . -t original:0.1 --quiet  0.10s user 0.09s system 0% cpu 35.108 total
$ docker images -a                                                                                                                                                                 REPOSITORY   TAG       IMAGE ID       CREATED         SIZE
original     0.1       27cfff826324   7 seconds ago   438MB

Let’s optimize:

FROM python:3.8-alpine
WORKDIR /app
COPY ./app /app
RUN pip install --no-cache-dir requests==2.27.1
ENTRYPOINT ["python", "hello.py"]

Changes:

  • Update the docker image to a python alpine (use the latest python on lightweight Alpine Linux)
  • Remove install python & pip steps (they come prepackaged)
  • Use –no-cache-dir to save some space

Result:

~/repo/docker-articles$ docker images -a
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
optimized    0.1       f5036ae50ca7   16 seconds ago   55MB

Build time:

~/repo/docker-articles$ time docker build . -t optimized:0.1 --quiet
docker build . -t optimized:0.1 --quiet  0.08s user 0.07s system 2% cpu 7.027 total

Build size reduced by 155.375%

Build time reduced by 133.291%

Choosing the right image with Docker is crucial. With a simple change, we can save 155% on the container’s size and reduce build time by 133%! With the next tutorial we’ll see multi-stage builds and how we can produce miniature, yet completely working and idempotent docker containers adding just a little more code in our Dockerfile.