Почему многоступенчатое docker изображение больше, чем одноэтапное? - PullRequest
1 голос
/ 18 февраля 2020

Я создал микросервис (https://github.com/staticdev/enelvo-microservice), который должен клонировать репозиторий git для создания образа docker, с одноэтапным Dockerfile, конечное изображение имеет 759 МБ:

FROM python:3.7.6-slim-stretch

# set the working directory to /app
WORKDIR /app

# copy the current directory contents into the container at /app
COPY . /app

RUN apt-get update && apt-get install -y git \
 && pip install -r requirements.txt \
 && git clone https://github.com/tfcbertaglia/enelvo.git enelvo-src \
 && cd enelvo-src \
 && python setup.py install \
 && cd .. \
 && mv enelvo-src/enelvo enelvo \
 && rm -fr enelvo-src

EXPOSE 50051

# run app.py when the container launches
CMD ["python", "app.py"]

Я пробовал подход с использованием многоэтапной сборки (https://blog.bitsrc.io/a-guide-to-docker-multi-stage-builds-206e8f31aeb8), чтобы уменьшить размер изображения без git и списков apt-get (из обновления):

FROM python:3.7.6-slim-stretch as cloner

RUN apt-get update && apt-get install -y git \
 && git clone https://github.com/tfcbertaglia/enelvo.git enelvo-src

FROM python:3.7.6-slim-stretch

COPY --from=cloner /enelvo-src /app/enelvo-src

# set the working directory to /app
WORKDIR /app

# copy the current directory contents into the container at /app
COPY . /app

RUN pip install -r requirements.txt \
 && cd enelvo-src \
 && python setup.py install \
 && cd .. \
 && mv enelvo-src/enelvo enelvo \
 && rm -fr enelvo-src

EXPOSE 50051

# run app.py when the container launches
CMD ["python", "app.py"]

Проблема в том, что после этого окончательный размер стал еще больше (815 МБ). Есть идеи, что может быть не так в этом случае?

1 Ответ

1 голос
/ 18 февраля 2020

В первом примере вы запускаете

RUN git clone https://github.com/tfcbertaglia/enelvo.git enelvo-src \
    ... \
 && rm -fr enelvo-src

, поэтому дерево enelvo-src никогда не существует вне этой конкретной инструкции RUN; он удаляется до того, как Docker сможет создать из него слой.

Во втором примере вы запускаете

COPY --from=cloner /enelvo-src /app/enelvo-src
RUN rm -fr enelvo-src

Docker внутренне создает слой изображения после первого шага, который содержит содержимое этого исходного дерева. Последующий RUN rm на самом деле не делает изображение меньше, он просто записывает, что контент, который был там с более раннего уровня, технически больше не является частью файловой системы.

Обычно стандартный способ использования многоэтапная сборка - это максимально возможное количество сборок на ранней стадии, и только COPY конечный результат в образе времени выполнения. Для пакетов Python один подход, который может хорошо работать, состоит в создании колеса из пакета:

FROM python:3.7.6-slim-stretch as build
WORKDIR /build
RUN apt-get update && apt-get install -y git \
 && git clone https://github.com/tfcbertaglia/enelvo.git enelvo-src
 && ...
 && python setup.py bdist_wheel  # (not "install")

FROM python:3.7.6-slim-stretch
WORKDIR /app
COPY --from=build /build/dist/wheel/enelvo*.whl .
RUN pip install enelvo*.whl
...
...