274 votes

Intégration de Python Poetry avec Docker

Pouvez-vous me donner un exemple de Dockerfile dans lequel je peux installer tous les paquets dont j'ai besoin à partir de poetry.lock y pyproject.toml dans mon image/conteneur depuis Docker ?

407voto

sobolevn Points 5397

Il y a plusieurs choses à garder à l'esprit lorsque l'on utilise poetry en même temps que docker .

Installation

Méthode officielle d'installation poetry est via :

curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -

Cette façon de faire permet poetry et ses dépendances pour être isolés de vos dépendances. Mais, de mon point de vue, ce n'est pas une très bonne chose pour deux raisons :

  1. poetry pourrait obtenir une mise à jour et cela casserait votre construction. Dans ce cas, vous pouvez spécifier POETRY_VERSION variable d'environnement. L'installateur la respectera
  2. Je n'aime pas l'idée de faire passer des choses d'Internet dans mes conteneurs sans aucune protection contre d'éventuelles modifications de fichiers.

Donc, j'utilise pip install 'poetry==$POETRY_VERSION' . Comme vous pouvez le constater, je recommande toujours d'épingler votre version.

Aussi, épinglez cette version dans votre pyproject.toml également :

[build-system]
# Should be the same as `$POETRY_VERSION`:
requires = ["poetry>=1.0"]
build-backend = "poetry.masonry.api"

Il vous protègera contre le décalage de version entre votre local et le docker environnements.

Mise en cache des dépendances

Nous voulons mettre en cache nos exigences et ne les réinstaller que lorsque pyproject.toml o poetry.lock changement de dossiers. Sinon, les constructions seront lentes. Pour obtenir une couche de cache fonctionnelle, nous devons mettre :

COPY poetry.lock pyproject.toml /code/

Après le poetry est installé, mais avant que d'autres fichiers ne soient ajoutés.

Virtualenv

La prochaine chose à garder à l'esprit est virtualenv création. Nous n'en avons pas besoin dans docker . Il est déjà isolé. Donc, nous utilisons poetry config virtualenvs.create false pour le désactiver.

Développement et production

Si vous utilisez le même Dockerfile pour le développement et la production comme je le fais, vous devrez installer différents ensembles de dépendances en fonction de certaines variables d'environnement :

poetry install $(test "$YOUR_ENV" == production && echo "--no-dev")

De cette façon $YOUR_ENV contrôlera quel ensemble de dépendances sera installé : tous (par défaut) ou production seulement avec --no-dev drapeau.

Vous pouvez également ajouter quelques options supplémentaires pour une meilleure expérience :

  1. --no-interaction de ne pas poser de questions interactives
  2. --no-ansi pour rendre votre sortie plus conviviale pour les journaux

Résultat

Vous vous retrouverez avec quelque chose de similaire :

FROM python:3.6.6-alpine3.7

ARG YOUR_ENV

ENV YOUR_ENV=${YOUR_ENV} \
  PYTHONFAULTHANDLER=1 \
  PYTHONUNBUFFERED=1 \
  PYTHONHASHSEED=random \
  PIP_NO_CACHE_DIR=off \
  PIP_DISABLE_PIP_VERSION_CHECK=on \
  PIP_DEFAULT_TIMEOUT=100 \
  POETRY_VERSION=1.0.0

# System deps:
RUN pip install "poetry==$POETRY_VERSION"

# Copy only requirements to cache them in docker layer
WORKDIR /code
COPY poetry.lock pyproject.toml /code/

# Project initialization:
RUN poetry config virtualenvs.create false \
  && poetry install $(test "$YOUR_ENV" == production && echo "--no-dev") --no-interaction --no-ansi

# Creating folders, and files for a project:
COPY . /code

Vous pouvez trouver un exemple concret et entièrement fonctionnel ici : wemake-django-template

Mise à jour le 2019-12-17

  • Mise à jour poetry à 1.0

169voto

Claudio Points 1349

Construction de Docker en plusieurs étapes avec Poetry et venv

Ne pas désactiver la création de virtualenv. Les Virtualenvs ont leur utilité dans les constructions Docker parce qu'ils offrent un moyen élégant de tirer parti des constructions en plusieurs étapes. En résumé, votre étape de construction installe tout dans le virtualenv, et l'étape finale copie simplement le virtualenv dans une petite image.

Utilisez poetry export et installez d'abord vos exigences épinglées, avant de copier votre code. Cela vous permettra d'utiliser le cache de construction de Docker, et de ne jamais réinstaller les dépendances juste parce que vous avez changé une ligne dans votre code.

Ne pas utiliser poetry install pour installer votre code, car il effectuera une installation modifiable. Au lieu de cela, utilisez poetry build pour construire une roue, et ensuite pip-installer cela dans votre virtualenv. (Merci à PEP 517 ce processus pourrait également être réalisé avec un simple pip install . mais en raison de construire l'isolement vous finiriez par installer une autre copie de Poetry).

Voici un exemple de Dockerfile installant une application Flask dans une image Alpine, avec une dépendance sur Postgres. Cet exemple utilise un point d'entrée script pour activer le virtualenv. Mais en général, vous devriez vous passer d'un point d'entrée script car vous pouvez simplement référencer le binaire Python à l'adresse suivante /venv/bin/python dans votre CMD l'instruction.

Dockerfile

FROM python:3.7.6-alpine3.11 as base

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1

WORKDIR /app

FROM base as builder

ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1 \
    POETRY_VERSION=1.0.5

RUN apk add --no-cache gcc libffi-dev musl-dev postgresql-dev
RUN pip install "poetry==$POETRY_VERSION"
RUN python -m venv /venv

COPY pyproject.toml poetry.lock ./
RUN poetry export -f requirements.txt | /venv/bin/pip install -r /dev/stdin

COPY . .
RUN poetry build && /venv/bin/pip install dist/*.whl

FROM base as final

RUN apk add --no-cache libffi libpq
COPY --from=builder /venv /venv
COPY docker-entrypoint.sh wsgi.py ./
CMD ["./docker-entrypoint.sh"]

docker-entrypoint.sh

#!/bin/sh

set -e

. /venv/bin/activate

while ! flask db upgrade
do
     echo "Retry..."
     sleep 1
done

exec gunicorn --bind 0.0.0.0:5000 --forwarded-allow-ips='*' wsgi:app

wsgi.py

import your_app

app = your_app.create_app()

37voto

Jeffrey04 Points 1647

Il s'agit d'une révision mineure de la réponse fournie par @Claudio qui utilise la nouvelle poetry install --no-root telle que décrite par @sobolevn dans sa réponse .

Afin de forcer poésie pour installer des dépendances dans un virtualenv spécifique, il faut d'abord l'activer.

. /path/to/virtualenv/bin/activate && poetry install

Par conséquent, en ajoutant ces éléments à la réponse de @Claudio, nous avons

FROM python:3.9-slim as base

ENV PYTHONFAULTHANDLER=1 \
    PYTHONHASHSEED=random \
    PYTHONUNBUFFERED=1

RUN apt-get update && apt-get install -y gcc libffi-dev g++
WORKDIR /app

FROM base as builder

ENV PIP_DEFAULT_TIMEOUT=100 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    PIP_NO_CACHE_DIR=1 \
    POETRY_VERSION=1.1.3

RUN pip install "poetry==$POETRY_VERSION"
RUN python -m venv /venv

COPY pyproject.toml poetry.lock ./
RUN . /venv/bin/activate && poetry install --no-dev --no-root

COPY . .
RUN . /venv/bin/activate && poetry build

FROM base as final

COPY --from=builder /venv /venv
COPY --from=builder /app/dist .
COPY docker-entrypoint.sh ./

RUN . /venv/bin/activate && pip install *.whl
CMD ["./docker-entrypoint.sh"]

Si vous devez l'utiliser à des fins de développement, vous ajoutez ou supprimez l'élément --no-dev en remplaçant cette ligne

RUN . /venv/bin/activate && poetry install --no-dev --no-root

à quelque chose comme ceci, comme indiqué dans la réponse de @sobolevn

RUN . /venv/bin/activate && poetry install --no-root $(test "$YOUR_ENV" == production && echo "--no-dev")

après avoir ajouté la déclaration de la variable d'environnement appropriée.

L'exemple utilise l'image debian-slim comme base, cependant, l'adapter à l'image alpine devrait être une tâche triviale.

29voto

lmiguelvargasf Points 9693

TL;DR

J'ai pu mettre en place poetry pour un Django projet utilisant postgres . Après avoir fait quelques recherches, j'ai abouti à ce qui suit Dockerfile :

FROM python:slim

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1

# Install and setup poetry
RUN pip install -U pip \
    && apt-get update \
    && apt install -y curl netcat \
    && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
ENV PATH="${PATH}:/root/.poetry/bin"

WORKDIR /usr/src/app
COPY . .
RUN poetry config virtualenvs.create false \
  && poetry install --no-interaction --no-ansi

# run entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

C'est le contenu de entrypoint.sh :

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."

    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

python manage.py migrate

exec "$@"

Explication détaillée

Quelques points à noter :

  • J'ai décidé d'utiliser slim au lieu de alpine comme étiquette pour le python car même si alpine sont censées réduire la taille des images Docker et accélérer la construction, mais avec Python, vous pouvez en fait vous retrouver avec une image un peu plus grande et cela prend un certain temps à construire (lire cet article pour plus d'informations).

  • En utilisant cette configuration, les conteneurs sont construits plus rapidement qu'en utilisant l'image alpine car je n'ai pas besoin d'ajouter des paquets supplémentaires pour installer correctement les paquets Python.

  • J'installe poetry directement à partir de l'URL fournie dans la documentation. Je suis conscient des avertissements fournis par sobolevn . Cependant, je considère qu'il est préférable à long terme d'utiliser la dernière version de poetry par défaut plutôt que de dépendre d'une variable d'environnement que je devrais mettre à jour périodiquement.

  • Mise à jour de la variable d'environnement PATH est crucial. Sinon, vous obtiendrez une erreur disant que la poésie n'a pas été trouvée .

  • Les dépendances sont installées directement dans l'interpréteur python du conteneur. Il ne crée pas poetry pour créer un environnement virtuel avant d'installer les dépendances.

Au cas où vous auriez besoin du alpine version de ce Dockerfile :

FROM python:alpine

# Keeps Python from generating .pyc files in the container
ENV PYTHONDONTWRITEBYTECODE 1
# Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED 1

# Install dev dependencies
RUN apk update \
    && apk add curl postgresql-dev gcc python3-dev musl-dev openssl-dev libffi-dev

# Install poetry
RUN pip install -U pip \
    && curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
ENV PATH="${PATH}:/root/.poetry/bin"

WORKDIR /usr/src/app
COPY . .
RUN poetry config virtualenvs.create false \
  && poetry install --no-interaction --no-ansi

# run entrypoint.sh
ENTRYPOINT ["/usr/src/app/entrypoint.sh"]

Notez que le alpine La version nécessite quelques dépendances postgresql-dev gcc python3-dev musl-dev openssl-dev libffi-dev pour fonctionner correctement.

21voto

maciek Points 2631

C'est la configuration minimale qui fonctionne pour moi :

FROM python:3.7

ENV PIP_DISABLE_PIP_VERSION_CHECK=on

RUN pip install poetry

WORKDIR /app
COPY poetry.lock pyproject.toml /app/

RUN poetry config virtualenvs.create false
RUN poetry install --no-interaction

COPY . /app

Notez que ce n'est pas aussi sûr que La configuration de @sobolevn .

Pour la petite histoire, j'ajouterai que si les installations modifiables seront possibles pour pyproject.toml projets une ligne ou deux pourraient être supprimées :

FROM python:3.7

ENV PIP_DISABLE_PIP_VERSION_CHECK=on

WORKDIR /app
COPY poetry.lock pyproject.toml /app/

RUN pip install -e .

COPY . /app

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X