Search code examples
pythondockerpipdependency-managementpython-poetry

Should I use Poetry in production dockerfile?


I have a web app built with a framework like FastAPI or Django, and my project uses Poetry to manage the dependencies.

I didn't find any topic similar to this.

The question is: should I install poetry in my production dockerfile and install the dependencies using the poetry, or should I export the requirements.txt and just use pip inside my docker image?

Actually, I am exporting the requirements.txt to the project's root before deploy the app and just using it inside the docker image.

My motivation is that I don't need the "complexity" of using poetry inside a dockerfile, since the requirements.txt is already generated by the poetry and use it inside the image will generate a new step into docker build that can impact the build speed.

However, I have seen much dockerfiles with poetry installation, what makes me think that I am doing a bad use of the tool.


Solution

  • There's no need to use poetry in production. To understand this we should look back to what the original reason poetry exists. There are basically two main reasons for poetry:-

    1. To manage python venv for us - in the past people use different range of tools, from home grown script to something like virtualenvwrapper to automatically manage the virtual env.
    2. To help us publishing packages to PyPI

    Reason no. 2 not really a concern for this question so let just look at reason no. 1. Why we need something like poetry in dev? It because dev environment could be different between developers. My venv could be in /home/kamal/.venv while John probably want to be fancy and place his virtualenv in /home/john/.local/venv.

    When writing notes on how to setup and run your project, how would you write the notes to cater the difference between me and John? We probably use some placeholder such as /path/to/your/venv. Using poetry, we don't have to worry about this. Just write in the notes that you should run the command as:-

    poetry run python manage.py runserver ...
    

    Poetry take care of all the differences. But in production, we don't have this problem. Our app in production will be in single place, let say in /app. When writing notes on how to run command on production, we can just write:-

    /app/.venv/bin/myapp manage collectstatic ...
    

    Below is a sample Dockerfile we use to deploy our app using docker:-

    FROM python:3.10-buster as py-build
    
    # [Optional] Uncomment this section to install additional OS packages.
    RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
         && apt-get -y install --no-install-recommends netcat util-linux \
            vim bash-completion yamllint postgresql-client
    
    RUN curl -sSL https://install.python-poetry.org | POETRY_HOME=/opt/poetry python3 -
    
    COPY . /app
    WORKDIR /app
    ENV PATH=/opt/poetry/bin:$PATH
    RUN poetry config virtualenvs.in-project true && poetry install
    
    FROM node:14.20.0 as js-build
    
    COPY . /app
    WORKDIR /app
    RUN npm install && npm run production
    
    FROM python:3.10-slim-buster
    
    EXPOSE 8000
    COPY --from=py-build /app /app
    COPY --from=js-build /app/static /app/static
    WORKDIR /app
    CMD /app/.venv/bin/run
    

    We use multistage build where in the build stage, we still use poetry to install all the dependecies but in the final stage, we just copy /app which would also include .venv virtualenv folder.