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 ?
Réponses
Trop de publicités?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 :
-
poetry
pourrait obtenir une mise à jour et cela casserait votre construction. Dans ce cas, vous pouvez spécifierPOETRY_VERSION
variable d'environnement. L'installateur la respectera - 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 :
-
--no-interaction
de ne pas poser de questions interactives -
--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
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()
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.
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 dealpine
comme étiquette pour lepython
car même sialpine
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 parsobolevn
. Cependant, je considère qu'il est préférable à long terme d'utiliser la dernière version depoetry
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.
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
- Réponses précédentes
- Plus de réponses