Können Sie mir ein Beispiel geben, Dockerfile
in dem ich alle benötigten Pakete von poetry.lock
und pyproject.toml
in mein Image / Container von Docker installieren kann ?
quelle
Können Sie mir ein Beispiel geben, Dockerfile
in dem ich alle benötigten Pakete von poetry.lock
und pyproject.toml
in mein Image / Container von Docker installieren kann ?
Bei der Verwendung poetry
mit sind verschiedene Dinge zu beachten docker
.
Die offizielle Installation poetry
erfolgt über:
curl -sSL https://raw.githubusercontent.com/sdispater/poetry/master/get-poetry.py | python
Auf diese Weise können poetry
und ihre Abhängigkeiten von Ihren Abhängigkeiten isoliert werden. Aber aus meiner Sicht ist es aus zwei Gründen keine sehr gute Sache:
poetry
Die Version wird möglicherweise aktualisiert und Ihr Build wird beschädigt. In diesem Fall können Sie eine POETRY_VERSION
Umgebungsvariable angeben . Der Installer wird es respektierenAlso benutze ich pip install 'poetry==$POETRY_VERSION'
. Wie Sie sehen können, empfehle ich weiterhin, Ihre Version zu pinnen.
Stecken Sie diese Version auch in Ihre pyproject.toml
:
[build-system]
# Should be the same as `$POETRY_VERSION`:
requires = ["poetry>=1.0"]
build-backend = "poetry.masonry.api"
Es schützt Sie vor Versionsinkongruenzen zwischen Ihrem lokalen und dem docker
Umfeld.
Wir wollen , dass unsere Anforderungen zwischenzuspeichern und sie nur neu installieren , wenn pyproject.toml
oder poetry.lock
Dateien ändern. Andernfalls werden die Builds langsam sein. Um eine funktionierende Cache-Schicht zu erreichen, sollten wir Folgendes setzen:
COPY poetry.lock pyproject.toml /code/
Nach der poetry
Installation, aber bevor andere Dateien hinzugefügt werden.
Das nächste, was zu beachten ist, ist die virtualenv
Schöpfung. Wir brauchen es nicht in docker
. Es ist bereits isoliert. Also verwenden wir die poetry config virtualenvs.create false
Einstellung, um es auszuschalten.
Wenn Sie Dockerfile
für Entwicklung und Produktion dasselbe verwenden wie ich, müssen Sie verschiedene Abhängigkeiten basierend auf einer Umgebungsvariablen installieren:
poetry install $(test "$YOUR_ENV" == production && echo "--no-dev")
Auf diese Weise $YOUR_ENV
wird gesteuert, welche Abhängigkeiten festgelegt werden: alle (Standard) oder Produktion nur mit --no-dev
Flag.
Möglicherweise möchten Sie auch weitere Optionen hinzufügen, um eine bessere Erfahrung zu erzielen:
--no-interaction
keine interaktiven Fragen zu stellen--no-ansi
Flag, um Ihre Ausgabe protokollfreundlicher zu gestaltenSie werden am Ende etwas Ähnliches haben wie:
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
Ein voll funktionsfähiges Beispiel aus der Praxis finden Sie hier: wemake-django-template
poetry
auf 1.0
poetry
kurzem adoptiert .)pip install poetry
ist, dass die Abhängigkeiten von Poetry mit App-Abhängigkeiten in Konflikt stehen könnten.poetry config virtualenvs.create false
funktioniert nicht in 1.0.0. Verwenden SieRUN POETRY_VIRTUALENVS_CREATE=false poetry install
stattdessen.Mehrstufiger Docker Build mit Poetry und Venv
Deaktivieren Sie die Erstellung von virtualenv nicht. Virtualenvs erfüllen in Docker-Builds einen Zweck , da sie eine elegante Möglichkeit bieten, mehrstufige Builds zu nutzen. Kurz gesagt, Ihre Build-Phase installiert alles in die virtuelle Umgebung, und die letzte Phase kopiert die virtuelle Umgebung einfach in ein kleines Image.
Verwenden
poetry export
und installieren Sie zuerst Ihre angehefteten Anforderungen, bevor Sie Ihren Code kopieren. Auf diese Weise können Sie den Docker-Build-Cache verwenden und Abhängigkeiten niemals neu installieren, nur weil Sie eine Zeile in Ihrem Code geändert haben.Verwenden
poetry install
Sie diesen Code nicht zur Installation, da er eine bearbeitbare Installation ausführt. Verwenden Sie stattdessen,poetry build
um ein Rad zu bauen, und installieren Sie es dann per Pip in Ihre virtuelle Umgebung. (Dank PEP 517 könnte dieser gesamte Prozess auch mit einem einfachen Vorgang ausgeführt werden.pip install .
Aufgrund der Build-Isolation würden Sie jedoch eine weitere Kopie von Poetry installieren.)Hier ist ein Beispiel für eine Docker-Datei, in der eine Flask-App in einem Alpine-Image installiert wird, abhängig von Postgres. In diesem Beispiel wird ein Einstiegspunktskript verwendet, um die virtuelle Umgebung zu aktivieren. Im Allgemeinen sollten Sie jedoch ohne ein Einstiegspunktskript in Ordnung sein, da Sie
/venv/bin/python
in IhrerCMD
Anweisung einfach auf die Python-Binärdatei verweisen können .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()
quelle
--no-root
flag deaktivieren . Eine geschlossene Github-Ausgabe finden Sie hier .Das ist eine minimale Konfiguration, die für mich funktioniert:
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
Beachten Sie, dass es nicht so sicher ist wie die Konfiguration von @ sobolevn .
Als Trivia möchte ich hinzufügen, dass ein oder zwei Zeilen gelöscht werden könnten , wenn bearbeitbare Installationen für
pyproject.toml
Projekte möglich sind :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
quelle
mymodule
, das Sie installieren möchten - wie es Poetry standardmäßig tut, wenn es eines findet - müssen Sie eine Dummy-Version wie diese erstellen, bevor Sie die Poetry-Installation ausführen :RUN mkdir /app/mymodule && touch /app/mymodule/__init__.py
. Dies funktioniert, weil Poetry diese Art von Modulen mit pip -e installiert, wodurch nur eine symbolische Verknüpfung erstellt wird. Dies bedeutet, dass die Dinge wie erwartet funktionieren, wenn die realen Module im letzten Schritt darüber kopiert werden. (Laut Mods ist dies ein Kommentar und keine Bearbeitung - bitte versuchen Sie es in den Beitrag aufzunehmen, wenn Sie nicht einverstanden sind.)Hier ist ein Beispiel, bei dem zuerst eine Ebene mit den Abhängigkeiten (die nur erstellt wird, wenn sich diese ändern) und dann eine Ebene mit dem vollständigen Quellcode zu einem Bild hinzugefügt wird. Bei der Einstellung
poetry
für die Installation in der globalen Dateisite-packages
bleibt ein Konfigurationsartefakt erhalten, das ebenfalls entfernt werden kann.quelle
TL; DR
Ich konnte mich mit
poetry
für einDjango
Projekt einrichtenpostgres
. Nach einigen Recherchen kam ich zu folgendem ErgebnisDockerfile
: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"]
Dies ist der Inhalt von
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 "$@"
Ausführliche Erklärung
Einige Punkte zu beachten:
Ich habe mich entschieden,
slim
anstelle vonalpine
als Tag für daspython
Bild zu verwenden, denn obwohlalpine
Bilder die Größe von Docker-Bildern reduzieren und den Build beschleunigen sollen, können Sie mit Python tatsächlich ein etwas größeres Bild erhalten, und das dauert eine Weile Build (lesen Sie diesen Artikel für weitere Informationen).Mit dieser Konfiguration werden Container schneller erstellt als mit dem alpinen Image, da ich keine zusätzlichen Pakete hinzufügen muss, um Python-Pakete ordnungsgemäß zu installieren.
Ich installiere
poetry
direkt von der in der Dokumentation angegebenen URL. Mir sind die Warnungen von bekanntsobolevn
. Ich bin jedoch der Meinung, dass es auf lange Sicht besser ist, die spätere Versionpoetry
von standardmäßig zu verwenden, als sich auf eine Umgebungsvariable zu verlassen, die ich regelmäßig aktualisieren sollte.Das Aktualisieren der Umgebungsvariablen
PATH
ist von entscheidender Bedeutung. Andernfalls erhalten Sie eine Fehlermeldung, dass keine Poesie gefunden wurde .Abhängigkeiten werden direkt im Python-Interpreter des Containers installiert. Es wird keine
poetry
virtuelle Umgebung erstellt, bevor die Abhängigkeiten installiert werden.Falls Sie die
alpine
Version davon benötigenDockerfile
: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"]
Beachten Sie, dass die
alpine
Version einige Abhängigkeiten benötigtpostgresql-dev gcc python3-dev musl-dev openssl-dev libffi-dev
, um ordnungsgemäß zu funktionieren.quelle
Dies ist eine geringfügige Überarbeitung der Antwort von @Claudio , die die neue
poetry install --no-root
Funktion verwendet, wie sie von @sobolevn in seiner Antwort beschrieben wurde .Um Poesie zu zwingen , Abhängigkeiten in eine bestimmte virtuelle Umgebung zu installieren, muss sie zuerst aktiviert werden.
Fügen Sie diese daher zu @ Claudios Antwort hinzu, die wir haben
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"]
Wenn Sie dies für Entwicklungszwecke verwenden müssen, fügen Sie das hinzu oder entfernen Sie es,
--no-dev
indem Sie diese Zeile ersetzenzu so etwas wie in @ sobolevns Antwort gezeigt
RUN . /venv/bin/activate && poetry install --no-root $(test "$YOUR_ENV" == production && echo "--no-dev")
nach dem Hinzufügen der entsprechenden Umgebungsvariablendeklaration.
In diesem Beispiel werden Debian-Slims als Basis verwendet. Die Anpassung an ein alpines Bild sollte jedoch eine triviale Aufgabe sein.
quelle