GoogleContainerTools / distroless

🥑 Language focused docker images, minus the operating system.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Using official Python base images and packaging into distroless later on

artursmet opened this issue · comments

Hello,

I’ve been using official Docker images for python (eg. python:3.11-slim-bookworm) in my projects and I wanted to use multi stage build approach to package the final image into distroless one.

I’ve found an instruction of how to do it in this repo - https://github.com/GoogleContainerTools/distroless/tree/main/examples/python3-requirements but I wonder if it would be possible to use an official python docker image instead of installing an apt-based python distro from debian repos.

My attempt so far was like this:

FROM python:3.11-slim-bookworm AS build-venv

WORKDIR /opt/app/
ADD requirements.txt /opt/app/
RUN python3 -m venv /venv
RUN /venv/bin/pip install -r /opt/app/requirements.txt

FROM gcr.io/distroless/python3-debian12
COPY --from=build-venv /venv /venv
COPY . /app
WORKDIR /app
ENTRYPOINT ["/venv/bin/uvicorn", "app:app", "--host", "0.0.0.0", "--port", "9090"]
EXPOSE 9090

However, the virtualenv produced by official python image does not work, because python in that image is compiled, not sourced from official Debian repositories (it has an additional benefit of being able to deliver most recent python version, without waiting for Debian maintainers).

So the python binary is located in /usr/local/bin/python3.11 in this case. However, on the distoless image, the python binary is located in /usr/bin/python3.11.
As an effect, the container does not boot because the binary path inside the virtualenv is incorrect.
This is because the virtualenv configuration:

/app # cat /venv/pyvenv.cfg 
home = /usr/local/bin
include-system-site-packages = false
version = 3.11.8
executable = /usr/local/bin/python3.11
command = /usr/local/bin/python3 -m venv /venv
/app # 

I’ve tried to work around it and add a symlink into the final image, it worked fine in the debug image in interactive shell:

/app # /venv/bin/python --version
sh: /venv/bin/python: not found
/app # mkdir -p /usr/local/bin && ln -s /usr/bin/python3 /usr/local/bin/python3 && ln -s /usr/bin/python3 /usr/local/bin/python3.11
/app # /venv/bin/python --version
Python 3.11.2
/app # 

But after adding it into the Dockerfile:

RUN mkdir -p /usr/local/bin && ln -s /usr/bin/python3 /usr/local/bin/python3 && ln -s /usr/bin/python3 /usr/local/bin/python3.11

It produces the following build error:

failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: exec: "/bin/sh": stat /bin/sh: no such file or directory: unknown

Is there a way to use the official python base image and later on carry over the virtualenv from this image into a distroless base? In my opinion it will bring a lot of benefits and allow to use most recent python versions in distroless (even in my case - official python image has 3.11.8 while the debian-repo-based distroless has 3.11.2 - both use Debian 12 bookworm)

I made it worked this way

  1. Install pip/peotry into a distroless container (build container). Make sure to run in exec/vector mode as there is no shell.
  2. Build your project
  3. Copy the python sys dist-package (/usr/local/lib/python3.11/dist-packages) into a new distroless container (deploy)

That way you have one a container that only has your app with its dependencies - no build tools.
Hope this helps