Почему изображения контейнера Docker настолько велики?
Я сделал простой образ через Dockerfile из Fedora (первоначально 320 МБ).
Добавлен Nano (этот крошечный редактор размером 1 МБ), а размер изображения увеличился до 530 МБ. Я добавил Git поверх этого (30-ish MB), а затем мой размер изображения sky-rockets до 830 МБ.
Разве это не безумие?
Я попытался экспортировать и импортировать контейнер для удаления истории/промежуточных изображений. Это усилие было сохранено до 25 МБ, теперь мой размер изображения составляет 804 МБ. Я также пытался запустить много команд на одном RUN
, но все же я получаю тот же начальный 830 МБ.
У меня возникают сомнения, стоит ли вообще использовать Docker. Я имею в виду, я почти ничего не установил, и я набираю 1 ГБ. Если мне придется добавить некоторые серьезные вещи, такие как база данных и т.д., Я мог бы закончиться дисковым пространством.
Кто-нибудь страдает от смешного размера изображений? Как вы справляетесь с этим?
Если мой файл Docker не правдоподобен?
FROM fedora:latest
MAINTAINER Me NotYou <[email protected]>
RUN yum -y install nano
RUN yum -y install git
но трудно представить, что здесь может пойти не так.
Ответы
Ответ 1
Как сообщает @rexposadas, изображения включают в себя все слои, и каждый уровень содержит все зависимости от того, что вы установили. Также важно отметить, что базовые изображения (например, fedora:latest
имеют тенденцию быть очень голыми. Вы можете быть удивлены количеством зависимостей, установленными вашим установленным программным обеспечением.
Мне удалось сделать вашу установку значительно меньшей, добавив yum -y clean all
в каждую строку:
FROM fedora:latest
RUN yum -y install nano; yum -y clean all
RUN yum -y install git; yum -y clean all
Важно сделать это для каждого RUN, прежде чем уровень будет зафиксирован, или же удалит, фактически не удаляя данные. То есть, в файловой системе union/copy-on-write, очистка в конце не уменьшает использование файловой системы, потому что реальные данные уже привязаны к более низким уровням. Чтобы обойти это, вы должны очищать каждый слой.
$ docker history bf5260c6651d
IMAGE CREATED CREATED BY SIZE
bf5260c6651d 4 days ago /bin/sh -c yum -y install git; yum -y clean a 260.7 MB
172743bd5d60 4 days ago /bin/sh -c yum -y install nano; yum -y clean 12.39 MB
3f2fed40e4b0 2 weeks ago /bin/sh -c #(nop) ADD file:cee1a4fcfcd00d18da 372.7 MB
fd241224e9cf 2 weeks ago /bin/sh -c #(nop) MAINTAINER Lokesh Mandvekar 0 B
511136ea3c5a 12 months ago 0 B
Ответ 2
Изображения Docker невелики, вы просто создаете большие изображения.
Изображение scratch
равно 0B, и вы можете использовать его для упаковки своего кода, если вы можете скомпилировать свой код в статическую двоичную. Например, вы можете скомпилировать свою программу Go и упаковать ее поверх scratch
, чтобы сделать полностью пригодный для использования образ менее 5 МБ.
Ключ должен не использовать официальные изображения Docker, они слишком большие. Scratch не так уж и практичен, поэтому я бы рекомендовал использовать Alpine Linux в качестве базового изображения. Это ~ 5 МБ, а затем добавьте только то, что требуется для вашего приложения. Это сообщение о Microcontainers показывает вам, как создать очень маленькую базу изображений на Alpine.
ОБНОВЛЕНИЕ: официальные изображения Docker основаны на альпийских теперь, поэтому они хороши для использования сейчас.
Ответ 3
Да, эти размеры смешны, и я действительно не знаю, почему так мало людей замечают это.
Я сделал изображение Ubuntu, которое фактически минимально (в отличие от других так называемых минимальных изображений). Он называется textlab/ubuntu-essential
и имеет 60 МБ.
FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano
Вышеупомянутое изображение составляет 82 МБ после установки nano.
FROM textlab/ubuntu-essential
RUN apt-get update && apt-get -y install nano git
Git имеет гораздо больше предварительных условий, поэтому изображение становится больше, примерно 192 МБ. Это еще меньше, чем исходный размер большинства изображений.
Вы также можете взглянуть на script, я написал, чтобы сделать минимальное изображение Ubuntu для Docker. Вы можете адаптировать его к Fedora, но я не уверен, сколько вы сможете удалить.
Ответ 4
Вот еще несколько вещей, которые вы можете сделать:
- Избегайте нескольких команд
RUN
, где вы можете. Поместите как можно больше в одну команду RUN
(используя &&
)
- очистка ненужных инструментов, таких как wget или git (которые вам нужны только для загрузки или сборки, но не для запуска вашего процесса).
С этими И И рекомендациями от @Andy и @michau я смог изменить размер моего изображения nodejs с 1.062 ГБ до 542 МБ.
Изменить:
Еще одна важная вещь:
"Мне потребовалось некоторое время, чтобы понять, что каждая команда Dockerfile создает новый контейнер с дельтами. [...] Не имеет значения, будете ли вы rm -rf файлы в более поздней команде, они продолжают существовать на каком-то промежуточном уровне контейнер."
Теперь мне удалось установить apt-get install
, wget
, npm install
(с зависимостями git) и apt-get remove
в одну команду RUN
, поэтому теперь у моего изображения всего 438 МБ.
Редактировать 29/06/17
С Docker v17.06 появятся новые функции для Dockerfiles:
У вас может быть несколько операторов FROM
внутри одного файла Docker, и только материал из последнего FROM
будет находиться в вашем окончательном изображении Docker. Это полезно для уменьшения размера изображения, например:
FROM nodejs as builder
WORKDIR /var/my-project
RUN apt-get install ruby python git openssh gcc && \
git clone my-project . && \
npm install
FROM nodejs
COPY --from=builder /var/my-project /var/my-project
Будет получен образ, имеющий только базовое изображение nodejs плюс содержимое из /var/my -project с первых шагов - но без - ruby, python, git, openssh и gcc
Ответ 5
Мне многое помогло:
После удаления неиспользуемых пакетов (например, redis 1200 mb freed) внутри моего контейнера я выполнил следующее:
- экспорт docker [containerID] -o containsername.tar
- docker import -m "commit message here" containsername.tar imagename: tag
Слои выравниваются. Размер нового изображения будет меньше, потому что я удалил пакеты из контейнера, как указано выше.
Это заняло много времени, чтобы понять это и почему я добавил свой комментарий.
Ответ 6
Docker Squash - это действительно хорошее решение. вы можете $packagemanager clean
на последнем шаге, а не в каждой строке, а затем просто запустить скриншот докера, чтобы избавиться от всех слоев.
https://github.com/jwilder/docker-squash
Ответ 7
Для лучшей практики вы должны выполнить одну команду RUN, потому что
каждая инструкция RUN в файле Dockerfile записывает новый слой в изображение, и для каждого слоя требуется дополнительное пространство на диске. Чтобы свести числовые уровни к минимуму, любые файлы, такие как установка, перемещение, извлечение, удаление и т.д., В идеале должны быть сделаны с помощью одной инструкции RUN
FROM fedora:latest
RUN yum -y install nano git; yum -y clean all
Ответ 8
Да, система слоев довольно удивительна.
Если у вас есть базовое изображение, и вы увеличиваете его, выполняя следующие действия:
# Test
#
# VERSION 1
# use the centos base image provided by dotCloud
FROM centos7/wildfly
MAINTAINER JohnDo
# Build it with: docker build -t "centos7/test" test/
# Change user into root
USER root
# Extract weblogic
RUN rm -rf /tmp/* \
&& rm -rf /wildfly/*
Изображение имеет точно такой же размер. Это, по сути, означает, что вам нужно вносить в свои действия RUN много средств для извлечения, установки и очистки, чтобы сделать изображения такими же маленькими, как и установленное программное обеспечение.
Это значительно усложняет жизнь...
В dockerBuild отсутствуют шаги RUN без фиксации.