web-dev-qa-db-fra.com

Intégration Python Poésie avec Docker

Pouvez-vous s'il vous plaît me donner un exemple de Dockerfile dans lequel je peux installer tous les packages dont j'ai besoin de poetry.lock et pyproject.toml dans mon image/conteneur de Docker?

9
Alex Bodea

Il y a plusieurs choses à garder à l'esprit lorsque vous utilisez poetry avec docker.

Installation

La manière officielle d'installer poetry est via:

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

De cette façon, poetry et ses dépendances peuvent être isolés de vos dépendances. Mais, à mon avis, ce n'est pas une très bonne chose pour deux raisons:

  1. poetry la version peut recevoir une mise à jour et elle cassera votre build. Dans ce cas, vous pouvez spécifier POETRY_VERSION variable d'environnement. L'installateur le respectera
  2. Je n'aime pas l'idée de diriger 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 voir, je recommande toujours d'épingler votre version.

Épinglez également cette version dans votre pyproject.toml ainsi que:

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

Il vous protègera de l'inadéquation des versions entre vos environnements local et docker.

Mise en cache des dépendances

Nous voulons mettre en cache nos besoins et les réinstaller uniquement lorsque pyproject.toml ou poetry.lock les fichiers changent. Sinon, les builds seront lents. Pour obtenir une couche de cache fonctionnelle, nous devons mettre:

COPY poetry.lock pyproject.toml /code/

Après l'installation de poetry, mais avant l'ajout de tout autre fichier.

Virtualenv

La prochaine chose à garder à l'esprit est la création de virtualenv. Nous n'en avons pas besoin dans docker. Il est déjà isolé. Nous utilisons donc poetry config settings.virtualenvs.create false réglage pour le désactiver.

Développement vs production

Si vous utilisez le même Dockerfile pour le développement et la production que moi, vous devrez installer différents ensembles de dépendances en fonction d'une variable d'environnement:

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

Par ici $YOUR_ENV contrôlera le jeu de dépendances qui sera installé: tout (par défaut) ou la production uniquement avec --no-dev drapeau.

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

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

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=0.12.11

# 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 settings.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 pleinement fonctionnel ici: wemake-Django-template

33
sobolevn

C'est une 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 settings.virtualenvs.create false
RUN poetry install --no-interaction

COPY . /app

Notez qu'il n'est pas aussi sûr que configuration de @ sobolevn .

Comme anecdote, j'ajouterai que si des installations modifiables seront possibles pour pyproject.toml projets , une ou deux lignes 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
5
maciek

Construction Docker en plusieurs étapes avec poésie et venv

Ne désactivez pas la création de virtualenv. Virtualenvs sert un objectif dans les builds Docker , car ils fournissent un moyen élégant de tirer parti des builds à plusieurs étapes. En un mot, votre étape de construction installe tout dans le virtualenv, et la dernière étape copie simplement le virtualenv sur une petite image.

Si cela ne vous dérange pas d'utiliser la version préliminaire de Poetry, vous pouvez utiliser poetry export et installez d'abord vos exigences épinglées avant de copier votre code. Cela vous permettra d'utiliser le cache de génération Docker et de ne jamais réinstaller les dépendances simplement parce que vous avez modifié une ligne dans votre code.

Ne pas utiliser poetry install pour installer votre code, car il effectuera une installation modifiable. Utilisez plutôt poetry build pour construire une roue, puis installez-la dans votre virtualenv. (Merci à PEP 517 , tout ce processus peut également être effectué avec un simple pip install ., mais en raison de build isolation vous finiriez par installer une autre copie de Poetry.)

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

Dockerfile

FROM python:3.7.4-Alpine3.10 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.0b1

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()
2
Claudio

Voici un exemple dépouillé où d'abord un calque avec les dépendances (qui n'est construit que lorsque celles-ci ont changé), puis un avec le code source complet est ajouté à une image. Configuration de poetry pour une installation dans le global site-packages laisse un artefact de configuration qui pourrait également être supprimé.

FROM python:Alpine

WORKDIR /app

COPY poetry.lock pyproject.toml ./
RUN pip install --no-cache-dir --upgrade pip \
 && pip install --no-cache-dir poetry \
 \
 && poetry config settings.virtualenvs.create false \
 && poetry install --no-dev \
 \
 && pip uninstall --yes poetry \

COPY . ./
1
funky-future