我应该在 Docker 中运行 Poetry,还是应该使用 pip、pipx 或类似的东西?
我应该构建轮子或 tarball 并将它们传递到 Docker 容器中,而不是在 Docker 容器中运行 pip 或 poetry 吗?
这是我尝试过但从未开始工作的 Dockerfile 之一的示例 - 环境已损坏,我不知道为什么:
FROM python:3.10
# Configure Poetry
ENV POETRY_VERSION=1.2.0
ENV POETRY_HOME=/opt/poetry
ENV POETRY_VENV=/opt/poetry-venv
ENV POETRY_CACHE_DIR=/opt/.cache
# Install poetry separated from system interpreter
RUN python3 -m venv $POETRY_VENV \
&& $POETRY_VENV/bin/pip install -U pip setuptools \
&& $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
# Add `poetry` to PATH
ENV PATH="${PATH}:${POETRY_VENV}/bin"
WORKDIR /app
# Install dependencies
COPY poetry.lock pyproject.toml ./
RUN poetry install
# Run your app
COPY . /app
ENTRYPOINT [ "./entrypoint.sh" ]
entrypoint.sh
包含:
poetry run blah
在这种情况下,问题是 virtualenv 坏了,我不知道为什么:
$ docker run blah/blah:latest
The virtual environment found in /app/.venv seems to be broken.
Recreating virtualenv blah-9TtSrW0h-py3.10 in /opt/.cache/virtualenvs/blah-9TtSrW0h-py3.10
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/local/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
...
import dateutil.parser
ModuleNotFoundError: No module named 'dateutil'
我什至应该在 Docker 中使用 Poetry 吗?我应该改用 pip 还是 pipx?
当你想在容器中运行 Python 应用程序时,你应该做什么?轮子是答案吗?还有别的答案吗?
从错误中,
poetry
在/app/.venv
中检测到一个虚拟环境,我猜你的应用程序没有.dockerignore
从docker构建上下文中排除.venv
,你本地的.venv
也被COPY . .
复制到图像中
您可以使用
poetry
在图像中安装依赖项,也可以使用 poetry
创建虚拟环境作为图像中的应用程序解释器,如下所示:
poetry.toml
,是项目的poetry
设置[virtualenvs]
create = true # create virtual env when run poetry cmd
in-project = true # create .venv folder in project root dir for virtual env
.dockerignore
.git
.venv
__pycache__
Dockerfile
FROM python:3.10
# Add virtual env bin into PATH, use python of virtual env firstly
# Add virtual site-packages into PYTHONPATH, python can find module in it
ENV POETRY_VERSION=1.2.0 \
PATH=/app/.venv/bin:${PATH} \
PYTHONPATH=.:src:./.venv/lib/python3.10/site-packages:$PYTHONPATH
# Install poetry
RUN pip install poetry==${POETRY_VERSION}
WORKDIR /app
COPY . /app
# Install dependencies
RUN poetry install
ENTRYPOINT [ "./entrypoint.sh" ]
我想出了一个似乎有效的方法:
requirements.txt
文件:$ poetry export -f requirements.txt -o requirements.txt --without-hashes
requirements.txt
安装应用程序的依赖项,而不是使用 Poetry:FROM python:3.10
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
ENTRYPOINT [ "./entrypoint.sh" ]
entrypoint.sh
包含:
#!/bin/bash
python3 -m blah.cli "$@"
为了确保我的
requirements.txt
与 poetry.lock
同步,我使用已简化为的 Makefile 构建容器:
VERSION := $(shell poetry version | cut -d ' ' -f 2)
CONTAINER_NAME := blah/blah
requirements:
poetry export -f requirements.txt -o requirements.txt --without-hashes
container: requirements
docker build -t $(CONTAINER_NAME):$(VERSION) -t $(CONTAINER_NAME):latest .
.PHONY: requirements container
当调用
poetry.lock
Makefile 目标时,这会在构建时将 requirements.txt
转换为 build
文件,并确保在构建容器映像时这两个文件同步。