诗歌安装的软件包在为 amd64 构建时会显着增加图像大小。
我正在我的主机(MacOS、M2 Pro)上构建一个 docker 映像,我想将其部署到 EC2 实例。正常构建将使图像大小为 2GB,这很好。但部署在EC2上会导致系统兼容性问题:
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64/v3) and no specific platform was requested
。所以我正在尝试使用 buildx
命令进行构建。然而,即使我更改的只是一个构建命令,它也会产生高达 13GB 的空间。我想知道为什么以及如何减小尺寸。
这是 Dockerfile:
FROM python:3.11-slim
# for -slim version (it breaks if you don't comment out && apt-get clean)
RUN apt-get update && apt-get install -y \
gfortran \
libopenblas-dev \
liblapack-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set environment variables to make Python and Poetry play nice
ENV POETRY_VERSION=1.7.1 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
EXPERIMENT_ID=$EXPERIMENT_ID \
RUN_ID=$RUN_ID
## Install poetry
RUN pip install "poetry==$POETRY_VERSION"
## copy project requirement files here to ensure they will be cached.
WORKDIR /app
COPY pyproject.toml ./
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-dev --no-ansi --verbose \
&& poetry cache clear pypi --all
使用这个 pyproject.toml,您可以重现构建。
[tool.poetry]
name = "malicious-url"
version = "0.1.0"
description = ""
authors = ["Makoto1021 <[email protected]>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
numpy = "^1.26.4"
tld = "^0.13"
fuzzywuzzy = "^0.18.0"
scikit-learn = "^1.4.1.post1"
pandas = "^2.2.1"
mlflow = {extras = ["pipelines"], version = "^2.11.3"}
xgboost = "^2.0.3"
python-dotenv = "^1.0.1"
imblearn = "^0.0"
torch = "^2.2.2"
flask = "^3.0.3"
googlesearch-python = "^1.2.3"
whois = "^1.20240129.2"
nltk = "^3.8.1"
[tool.poetry.group.dev.dependencies]
ipykernel = "^6.29.3"
tldextract = "^5.1.2"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"
这个命令将构建一个 2GB 的镜像。
docker build -f ./docker/Dockerfile \
-t malicious-url-prediction-img:v1 .
这将生成一个 13GB 的图像
docker buildx build --platform linux/amd64 -f ./docker/Dockerfile \
-t malicious-url-prediction-img:v1-amd64 .
如果删除 RUN 命令
poetry config virtualenvs.create...
,即使我为 amd64 构建映像,映像大小仍然很小。所以我认为诗歌造成了这个问题。然而,仅通过更改构建上下文就产生如此大的大小差异仍然很奇怪。
我使用
/bin/bash
和 du
命令进入巨大的图像,我发现总使用空间约为 2MB。因此,这表明大型 Docker 映像大小问题可能与我添加到映像中的文件没有直接关系,而是与基础映像以及包安装和配置创建的层直接相关。
我还使用
dive
来调查空间使用情况,但并没有真正说明问题所在。
我有一种感觉,它来自
poetry
有什么建议吗?
仅供参考,这就是我运行容器的方式。
docker run --rm -p 7070:5000 -v $(pwd)/logs:/app/logs malicious-url-prediction-img:v1-amd64
编辑:
某些 ISA 可能会生成更小/更大的构建。但在你的情况下增加尺寸是不正常的。在这里,我建议对您的 Dockerfile 进行一次小重构。
我一直使用这个技巧,但我没有在这里测试。
您需要
gfortran
和其他一些包来构建您的 python 包。构建后,它们不是必需的,您可以卸载它们。
RUN apt install -y gfortran liblapack liblapack-dev libopenblas libopenblas-dev
RUN build your packages
RUN apt purge gfortran lapack-dev openblas-dev
RUN apt autoremove --purge
RUN other-cleanups
但是上面的代码不会减少你的docker镜像,因为构建依赖关系存在于上面的层中。您必须将上面的代码更改为:
RUN apt install -y gfortran liblapack liblapack-dev libopenblas libopenblas-dev ; \
build your packages ; \
apt purge gfortran lapack-dev openblas-dev ; \
apt autoremove --purge
这将大大减小您的图像尺寸。
apt
、pip
和 ...(默认情况下,apt
会删除下载的 .deb
文件)下载缓存目录中的文件。您可以将 --mount=type=cache
添加到 RUN
参数中,以将它们缓存在单独的缓存卷中,而不是图像中。
所以这是你重构的
Dockerfile
(我添加了liblapack
和libopenblas
,所以它们必须留在apt autoremove
之后):
FROM python:3.11-slim
ENV POETRY_VERSION=1.7.1 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
EXPERIMENT_ID=$EXPERIMENT_ID \
RUN_ID=$RUN_ID
WORKDIR /app
COPY poetry.lock pyproject.toml ./
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/root/.cache/pip \
--mount=type=cache,target=/root/.cache/pypoetry/cache \
set -eux ; \
apt update && apt install -y gfortran libopenblas libopenblas-dev liblapack liblapack-dev ; \
pip install "poetry==$POETRY_VERSION" ; \
poetry install --no-interaction --no-dev --no-ansi --verbose ; \
poetry cache clear pypi --all ; \
apt purge gfortran libopenblas-dev liblapack-dev ; \
apt autoremove --purge ; \
rm -rf /var/lib/apt/lists/*
COPY mlartifacts/542535033067401306/2ba405d6d3144db6a5cd237509e53ef8 /app/mlartifacts/542535033067401306/2ba405d6d3144db6a5cd237509e53ef8/
COPY data/blacklist.txt data/whitelist.txt /app/data/
COPY *.py .
COPY utils/ ./utils/
COPY .env .
EXPOSE 7070
CMD ["poetry", "run", "flask", "run", "--host=0.0.0.0"]
问题在于构建。
当您运行 AMD64 时,可能已经有可以使用的预编译轮子,因此无需构建任何东西。当您使用 ARM64 时,可用的轮子通常会少很多,需要您构建项目。
构建占用空间 - 它们下载库、编译工件并将事物链接在一起。
您应该做的是使用多阶段构建。在构建过程的一个阶段运行安装,然后将创建的文件移至新容器中。
例如(这未经测试,但基于您的文件,并且应该进行一些调整):
FROM python:3.11-slim
# for -slim version (it breaks if you don't comment out && apt-get clean)
RUN apt-get update && apt-get install -y \
gfortran \
libopenblas-dev \
liblapack-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set environment variables to make Python and Poetry play nice
ENV POETRY_VERSION=1.7.1 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
EXPERIMENT_ID=$EXPERIMENT_ID \
RUN_ID=$RUN_ID
## Install poetry
RUN pip install "poetry==$POETRY_VERSION"
## copy project requirement files here to ensure they will be cached.
WORKDIR /app
COPY poetry.lock pyproject.toml ./
RUN poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-dev --no-ansi --verbose \
&& poetry cache clear pypi --all
# Build our actual container now.
FROM python:3.11-slim
ENV POETRY_VERSION=1.7.1 \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
EXPERIMENT_ID=$EXPERIMENT_ID \
RUN_ID=$RUN_ID
# Copy all of the python files built in the Builder container into this smaller container.
COPY --from=Builder /usr/local/lib/python3.11 /usr/local/lib/python3.11
# Copy the model directory to the Docker image
COPY mlartifacts/542535033067401306/2ba405d6d3144db6a5cd237509e53ef8 /app/mlartifacts/542535033067401306/2ba405d6d3144db6a5cd237509e53ef8/
# Copy the blacklist and whitelist data
COPY data/blacklist.txt data/whitelist.txt /app/data/
## Copy Python files
COPY *.py .
COPY utils/ ./utils/
COPY .env .
EXPOSE 7070
CMD ["poetry", "run", "flask", "run", "--host=0.0.0.0"]
此方法用于所有 Multi-Py 项目(免责声明:我是这些项目的作者),因此您可以在那里查看示例。