Poetry is a great build system.
And in 2023, I believe, no one should use the pip
for a private Python codebase.
Getting it right inside Docker is a different issue, however.
Consider a simple Flask-based web server as an example
# Install poetry $ pip3 install poetry==1.7.1 $ poetry --version Poetry (version 1.7.1) # Create a sample package $ poetry init --python=~3.10 --name=src --description='Flask Hello world' --dependency=Flask@3.0.0 --author='Ashish' --license='Apache 2.0' --no-interaction $ poetry install $ touch README.md $ mkdir src # Create a file src/server.py in your favorite editor $ cat src/server.py from flask import Flask app = Flask(__name__) @app.route("/") def hello_world(): return "<p>Hello, World!</p>" if __name__ == "__main__": app.run()
Let’s finish the build process
Now, let’s add a simple Dockerfile titled Dockerfile1
FROM python:3.10-slim as base # Install Poetry RUN pip3 install poetry==1.7.1 WORKDIR /app COPY pyproject.toml poetry.lock /app # Install dependencies RUN poetry install COPY src /app/src ENTRYPOINT ["poetry", "run", "python", "src/server.py"]
And let’s build and check its size
$ docker build -f Dockerfile1 -t example1 . && docker image inspect example1 --format='{{.Size}}' | numfmt --to=iec-i 235Mi
We don’t need poetry in the final build, so, we can save space via multi-stage docker builds.
Consider following the multi-stage docker file Dockerfile2
FROM python:3.10-slim as builder # Install Poetry RUN pip3 install poetry==1.7.1 WORKDIR /app COPY pyproject.toml poetry.lock /app # virtual env is created in "/app/.venv" directory ENV POETRY_NO_INTERACTION=1 \ POETRY_VIRTUALENVS_IN_PROJECT=1 \ POETRY_VIRTUALENVS_CREATE=true \ POETRY_CACHE_DIR=/tmp/poetry_cache # Install dependencies RUN --mount=type=cache,target=/tmp/poetry_cache poetry install --only main --no-root RUN poetry install FROM python:3.10-slim as runner COPY src /app/src COPY --from=builder /app/.venv /app/.venv ENV PATH="/app/.venv/bin:$PATH" ENTRYPOINT ["/app/.venv/bin/python", "src/server.py"]
And the result
$ docker build -f Dockerfile2 -t example1 . && docker image inspect example1 --format='{{.Size}}' | numfmt --to=iec-i 158Mi
That’s an extra 77Mi (33%) of saving while reducing the attack surface of the docker image!
No one should use poetry in 2023 which still can’t implement pep621. If you really want “cargo-like”/package manager, use PDM. Also relying on lock files is a bad idea for docker caching https://pythonspeed.com/articles/poetry-vs-docker-caching/
Tldr: use pip, it’s great nowadays.
Thanks for the link.
I don’t think this is really broken.
It reduces efficiency in certain cases and that’s an acceptable trade-off as it still leads to better dev experience that pip.