Distroless Docker Images is a project proposed by Google in order to help building slimmer containers. The project description states it’s "Language focused docker images, minus the operating system". Sounds interesting, right?
Compared to common base images like ubuntu, alpine, debian which have lots of OS packages and libraries that might not be required for your application, Distroless Images have only what you need, to run your application.
It’s worth noting that Distroless containers are not always the most secured solution as explained by RedHat in this article.
Although it'd be hard to package a python application since its standard library relies on some higher-level OS capabilities, it’s possible to achieve that.
Python distroless containers require multi-stage building process because the
gcr.io/distroless/python3 image has neither
pip nor even
Let’s try to package a FastAPI api with “Distroless” Docker Images.
Here is a sample api server:
import fastapi, uvicorn from starlette.requests import Request import prometheus_client import os api = fastapi.FastAPI() REQUESTS = prometheus_client.Counter( 'requests', 'Application Request Count', ['endpoint'] ) @api.get('/ping') def index(request: Request): REQUESTS.labels(endpoint='/ping').inc() return "pong" @api.get('/metrics') def metrics(): return fastapi.responses.PlainTextResponse( prometheus_client.generate_latest() ) if __name__ == "__main__": print("Starting webserver...") uvicorn.run( api, host="0.0.0.0", port=int(os.getenv("PORT", 8080)), debug=os.getenv("DEBUG", False), log_level=os.getenv('LOG_LEVEL', "info"), proxy_headers=True )
We will use Pipenv as package manager. Here is our Pipfile:
[[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] fastapi = "==0.77.1" uvicorn = "==0.17.6" prometheus-client = "==0.14.1" Jinja2 = "==3.1.2" [dev-packages] [requires] python_version = "3.10"
So, I ended up with the following Dockerfile (commented) allowing me to package a FastAPI application with the distroless Python image.
FROM python:3.10-slim AS base # Setup env ## Avoid to write .pyc files on the import of source modules ENV PYTHONDONTWRITEBYTECODE 1 # Enable fault handler ENV PYTHONFAULTHANDLER 1
# Dependencies FROM base AS python-deps ### Install pipenv and compilation dependencies RUN pip install pipenv \ && apt-get update \ && apt-get install -y --no-install-recommends gcc ### Install python dependencies in /.venv COPY Pipfile . COPY Pipfile.lock . # Allows to install the pipenv packages into the project instead of home user # --deploy RUN PIPENV_VENV_IN_PROJECT=1 pipenv install --deploy
# Runtime FROM gcr.io/distroless/python3 WORKDIR /app # Copy the python packages because the distroless base image does COPY --from=python-deps /.venv/lib/python3.10/site-packages /app/site-packages # Set the Python path where the interpreter will look for the packages ENV PYTHONPATH /app/site-packages COPY . . EXPOSE 8080 ENTRYPOINT ["python", "app.py"]
The resulting image was around 25Mb.
You could find all the code on my github repository.
If you have any points to or not to use “Distroless” for python applications, feel free to drop in comment.