如何使用pipenv为python应用程序制作轻量级Docker映像

f5emj3cl  于 2022-11-03  发布在  Docker
关注(0)|答案(4)|浏览(148)

我可以为我的python应用程序生成工作图像,使用以下简单的Dockerfile

FROM python:3.7
WORKDIR /myapp
COPY Pipfile* ./
RUN pip install pipenv
RUN pipenv install --system --deploy
COPY src .
CMD ["python3", "app.py"]

但是,它会产生约1 GB的映像,其中可能包含临时文件,部署起来很麻烦。我只需要完整的python映像用于构建目的。我的应用可以在alpine变体上成功运行,所以我可以创建两遍Dockerfile

FROM python:3.7 as builder
COPY Pipfile* ./
RUN pipenv lock --requirements > requirements.txt
RUN python3 -m venv /venv
RUN /venv/bin/pip install --upgrade pip
RUN /venv/bin/pip install -r requirements.txt

FROM python:3.7-alpine
COPY --from=builder /venv /venv
WORKDIR /myapp
COPY src .
CMD ["/venv/bin/python3", "app.py"]

到目前为止一切顺利,它也工作,是6倍小。但这个方案被认为是一些“存根”,有一些缺点:

  • 它有不必要的额外COPY --from=builder步骤
  • 它不使用pipenv,但还需要pip来安装(+1个额外步骤,pipenv lock + pip install总是比仅使用pipenv install慢)
  • 它不会在系统范围内安装,而是安装到/venv中,在容器中应避免这种情况
  • 次要:构建会更多地污染中间图像缓存,并且需要下载两个图像变体。

如何将这两种方法结合起来,得到基于pipenv的轻量阿尔卑斯山图像,而不存在上述缺点?
或者你能提供你的生产Dockerfile的想法吗?

qxgroojn

qxgroojn1#

当你需要像ciso8601这样的东西,或者一些需要构建过程的库时,问题就来了。构建工具没有“合并”到slimalpine变体中,以减少占用空间。
因此,要安装deps,您必须:

  • 安装生成工具
  • 从Pipfile部署依赖项。锁定系统范围
  • 卸载生成工具并清除缓存

在一个RUN层中执行这3个操作,如下所示:

FROM python:3.7-slim

WORKDIR /app

# both files are explicitly required!

COPY Pipfile Pipfile.lock ./

RUN pip install pipenv && \
  apt-get update && \
  apt-get install -y --no-install-recommends gcc python3-dev libssl-dev && \
  pipenv install --deploy --system && \
  apt-get remove -y gcc python3-dev libssl-dev && \
  apt-get autoremove -y && \
  pip uninstall pipenv -y

COPY app ./

CMD ["python", "app.py"]
  • 操作构建系统将花费大约300MiB和一些额外的时间
  • 卸载pipenv将为您节省另外20MiB(这是结果大小的10%)。
  • 分离RUN命令不会从层中删除数据,并且会产生约500MiB的图像。这是docker的具体要求。

因此,这将产生约200 MiB大小的完美图像,

  • 比原始python:3.7小5倍(即〉1.0GiB)
  • 无Alpine不相容性(这些通常与glibc置换相关)

当时,我们对slim(debian buster)版本变体还满意,更喜欢slim而不是alpine(为了大部分的兼容性)。如果你真的想进一步优化大小,我建议你看看这些家伙的一些优秀版本:

zfycwa2u

zfycwa2u2#

不如这样吧

FROM python:3.7-alpine

WORKDIR /myapp

COPY Pipfile* ./

RUN pip install --no-cache-dir pipenv && \
    pipenv install --system --deploy --clear

COPY src .
CMD ["python3", "app.py"]

1.它使用了较小的Alpine版本。
1.使用pip--no-cache-dir选项和pipenv--clear选项,您将不会留下任何不必要的缓存文件。
1.您还可以在venv之外部署。
您也可以在同一个RUN命令中,在pipenv install --system --deploy --clear之后添加&& pip uninstall pipenv -y,以消除pipenv占用的空间(如果额外的图像大小让您感到困扰)。

7vux5j2d

7vux5j2d3#

我使用micropipenv来完成这项工作,它将自己描述为
pip的轻量级 Package 器,支持requirements.txt、Pipenv和Poetry锁定文件或将它们转换为pip-tools兼容的输出。为容器化Python应用程序设计,但不限于此。
从它创建的映像看起来如下所示:由于alpine基础映像缺少toml解析器,我们必须使用包含toml附加项的micropipenv版本(micropipenv[toml]而不是micropipenv)。

FROM python:3.9-alpine

WORKDIR /myapp
COPY Pipfile Pipfile.lock ./

RUN \
  # Install dependencies
  && pip install --no-cache-dir micropipenv[toml] \
  && micropipenv install --deploy \
  && pip uninstall -y micropipenv[toml]

COPY src .
CMD ["python3", "app.py"]
5hcedyr0

5hcedyr04#

它具有不必要的额外COPY --from=builder步骤
该指令是无害的,实际上使您的最终阶段图像更加轻量级:只复制virtualenv,没有构建工具链,也没有缓存的轮子,甚至在最后阶段也没有pipenv!
它不使用pipenv,但也需要pip安装(+1额外步骤,pipenv锁+pip安装总是比只安装pipenv慢)
在构建阶段使用pipenv生成virtualenv!

FROM python:3 as builder
COPY Pipfile* /
RUN mkdir /.venv  # The presence of a .venv folder triggers pipenv to use it by default
RUN pipenv install --deploy

FROM python:3-slim
COPY --from=builder /.venv /.venv
WORKDIR /myapp
COPY src .
CMD ["/.venv/bin/python3", "app.py"]

它不会在系统范围内安装,而是安装到/venv中,在容器中应避免安装
虽然在docker中不使用venv是一种常见的做法,但它们仍然有一些好处。而且绝对没有缺点。不要再听人们说venv不应该在dockers中使用。Pipenv目前的建议是不要在容器https://github.com/pypa/pipenv/pull/2762中发布系统范围的安装
次要:构建会更多地污染中间图像缓存,并且需要下载两个图像变体。
只需在CI系统中优化缓存设置。
但是
“看在上帝的份上”“建造和最后阶段使用同一个平台”
两者皆可

  • 在两个阶段都使用python:3-alpine,根据需要在构建阶段使用尽可能多的apk
  • 我决定用python:3作为建筑物,用python:3-slim作为最后阶段。它并不是那么大

高山图像使用musl而不是libc,这意味着python包https://peps.python.org/pep-0656/使用不同的ABI。不要将高山图像与非高山图像混合,就像不要将python:3.A图像与不同的python:3.B混合一样。
否则,在构建阶段安装的某些组件将无法在最后阶段使用。

相关问题