Як кожен раз створювати найменший образ робочого докера?


19

Мета: щоразу створювати найменші робочі зображення докера

Поточний

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    x                   42 minutes ago       1.92 GB

Спроба

Додавання кроку очищення в кінці Dockerfile:

#clean
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

трохи зменшив розмір зображення:

REPOSITORY          TAG       IMAGE ID            CREATED             SIZE
a-docker-image      latest    y                   2 minutes ago       1.86 GB

Обговорення

Я створив різні зображення докера. Кожен раз, коли я намагаюся зменшити розмір створеного зображення, але завжди відчуваю, що він занадто великий. Я шукаю сценарій, який вже створив хтось на github, який видаляє всі зайві пакети із зображення, тому розмір створеного зображення буде як можна меншим.

Як я вже говорив, я завжди намагаюся зменшити розмір зображення, але хочу застосувати це послідовно, щоб кожне зображення, яке я створюю відтепер, було якомога меншим.

Питання

Як кожен раз створювати найменший образ робочого докера?

Відповіді:


1

Існує безліч методів, без єдиного рішення. Ви, ймовірно, захочете виконати декілька наступних дій:


Спочатку оптимізуйте шари зображень для повторного використання. Надайте часто змінюються кроки пізніше в Dockerfile, щоб збільшити шанси на те, що ранні шари кешуються з попередніх збірок. Повторно використаний шар відображатиметься як більше дискового простору в а docker image ls, але якщо вивчити базову файлову систему, на диску завжди зберігається лише одна копія кожного шару. Це означає, що 3 зображення по 2 ГБ кожен, але у яких лише 50 Мбайт різних за останні кілька шарів збірки, займуть лише 2,1 ГБ дискового простору, навіть якщо в списку видно, що вони використовують 6 ГБ, оскільки ви подвійний підрахунок кожного з повторно використаних шарів.

Повторне використання шару - це те, чому ви бачите зображення з нечасто мінливими залежностями збірки, які встановлюються першими перед копіюванням у код. Дивіться будь-який приклад python, який має такий зразок:

FROM python
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
# note how the code is copied only after the pip install
# since code changes but requirements.txt doesn't
COPY . .
CMD ["gunicorn", "app:app"]

Виберіть мінімальне базове зображення. Ось чому ви бачите людей перейти від ubuntuдо debian:slim(в тонкі варіанти менше, поставляються з меншою кількістю інструментів), або навіть alpine. Це зменшує розмір початкової точки і дуже корисно, якщо ви постійно перетягуєте нові версії базового зображення. Однак якщо ваше базове зображення рідко змінюється, повторне використання шарів видаляє більшу частину переваги мінімального базового зображення.

Найменше базове зображення, яке ви можете вибрати, - scratchце нічого, не оболонка чи бібліотеки, і корисне лише зі статично складеними бінарними файлами. В іншому випадку виберіть базове зображення, яке включає необхідні інструменти без безлічі інструментів, які вам не потрібні.


Далі будь-який крок, який змінює або видаляє файл, повинен поєднуватися з попередніми кроками, які створюють цей файл. Інакше шарувата файлова система, яка використовує копіювання під час запису навіть у таких речах, як зміна дозволу на файл, матиме вихідний файл у попередньому шарі, і розмір зображення не зменшиться при видаленні файлів. Ось чому ваші rmкоманди не впливають на отриманий дисковий простір. Натомість ви можете ланцюжок команд, наприклад:

RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
 && ... \
 && apt-get purge -y wget \
 && rm -r a-build-dir \
 && apt-get purge -y a-package

Зауважте, що надмірне використання командних ланцюгів може уповільнити ваші збірки, оскільки вам потрібно буде перевстановити один і той же набір інструментів будь-коли, коли необхідні умови (наприклад, код, який витягується за допомогою wget). Дивіться багатоетапність нижче для кращої альтернативи.


Будь-який створений вами файл, який не потрібен у вашому отриманому зображенні, слід видалити на кроці, який його створює. Сюди входять кеші пакетів, журнали, вказівні сторінки тощо. Щоб дізнатись, які файли створюються в кожному шарі, ви можете використовувати такий інструмент, як wagoodman / dive (якого я особисто не перевіряв і висловлював би обережність, оскільки він працює з повним кореневим доступом на своєму хості), або ви можете створювати свої зображення докера, не обрізаючи проміжні контейнери, а потім переглядати відмінності з:

# first create and leave containers from any RUN step using options on build
docker image build --rm=false --no-cache -t image_name . 
# review which layers use an unexpectedly large amount of space
docker image history image_name
# list all containers, particularly the exited ones from above
docker container ps -a 
# examine any of those containers
docker container diff ${container_id} 
# ... repeat the diff for other build steps
# then cleanup exited containers
docker container prune

З кожним з цих проміжних контейнерів, то різниця покаже , що додані файли, змінені або видалені в цій стадії (вони помічені за допомогою A, Cабо Dперед кожним ім'ям файлу). Що відрізняється, це специфічна для контейнера файлова система читання / запису, яка є будь-яким файлом, зміненим контейнером із стану зображення, використовуючи функцію копіювання на запис.


Найкращий спосіб зменшити розмір зображення - це усунення непотрібних компонентів, як-от компіляторів, із завантаженого зображення. Для цього багатоступеневі збірки дозволяють компілювати на одному етапі, а потім копіювати лише отримані артефакти зі стадії збірки на зображення часу виконання, яке має лише мінімальний необхідний для запуску програми. Це дозволяє уникнути необхідності оптимізації будь-якого з етапів збирання, оскільки вони не постачаються із отриманим зображенням.

FROM debian:9 as build
# still chain update with install to prevent stale cache issues
RUN apt-get update \
 && apt-get install -y \
      a-package \
      wget \
RUN ... # perform any download/compile steps

FROM debian:9-slim as release
COPY --from=build /usr/local/bin/app /usr/local/bin/app
CMD [ "/usr/local/bin/app" ]

Багатоетапність ідеально підходить зі статично складеними бінарними файлами, які можна запускати з подряпиною як базове зображення або переходити з середовища компіляції, наприклад, JDK, до часу виконання, як JRE. Це найпростіший спосіб різко зменшити розмір зображення, незважаючи на швидке нарощування. Ви все ще можете виконати ланцюжок кроків на етапі випуску, якщо у вас є кроки, які змінюють або видаляють файли, створені на попередніх етапах, але здебільшого, COPYз іншої стадії ізолює етап випуску від будь-якого прошарку шару, що виник на попередніх етапах збірки.


Зауважте, я не рекомендую знімати зображення, оскільки це зменшує розмір одного зображення за рахунок усунення повторного використання шару. Це означає, що майбутні збірки одного зображення вимагатимуть більше дискового та мережевого трафіку для надсилання оновлень. Щоб повернутися до першого прикладу, сквашина може зменшити ваше зображення з 2 ГБ до 1 ГБ, але не три зображення можуть займати 3 Гб замість 2,1 ГБ.


25

A Dockerfileстворює новий шар для кожної з команд у файлі. Оскільки шари добре шаруються один на одного - ви не можете видалити файли, додані попереднім шаром. Ось чому при встановленні пакетів або завантаженні файлів або створенні складання кожного в окремій команді - вони все ще є в зображенні, навіть якщо в майбутньому шарі ви їх видалили.

Тож якщо ви просто зміните це:

RUN apt-get update -y
RUN apt-get install -y wget a-package
# ...
RUN apt-get purge -y wget
RUN rm -r a-build-dir
RUN apt-get purge -y a-package

До цього:

RUN apt-get update -y \
    && apt-get install -y wget a-package \
    && mkdir a-build-dir \
    && wget http://some-site/very-big-source-code.tar.gz \
    && tar xzvf very-big-source-code.tar.gz \
    && do-some-compilation \
    && apt-get purge -y wget \
    && cd .. \
    && rm -rf a-build-dir \
    && apt-get purge -y a-package

У вас вийде значно менший образ.


Ще один варіант - це збити зображення після того, як ви його побудували. З: Як працює новий docker --squash?


Ще один варіант - вибрати тонкий базовий образ. Наприклад, зображення, які використовують альпійський Linux в якості основи замість Debian, беруть всього 10-15mb замість 180-250mb. І це перед тим, як додати власну програму та дані. Багато офіційних базових зображень на Docker Hub мають альпійську версію.


3
2.37vs.1.47 GB
030

4

Можливо, не зовсім відповідь, але варто дати альтернативи.

Зважаючи на це, було створено середовище проживання шеф-кухаря , створивши пакет з усіма необхідними залежностями без стороннього навантаження дистрибутива / базового зображення, якого ви не бажаєте.

Витяги з того, що тут важливо, розмір контейнера з цієї публікації в блозі з простим додатком nodejs:

michael@ricardo-2:plans_pkg_part_2$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
mfdii/node-example   latest              36c6568c606b        40 minutes ago      655.9 MB
node                 latest              04c0ca2a8dad        16 hours ago        654.6 MB
mfdii/mytutorialapp  latest              534afd80d74d        2 minutes ago       182.1 MB

mdfii/node-exampleце зображення докера з класичного dockerfile, тоді mfdii/mytutorialappяк зображення докера, створене з середовищем існування.

Якщо розмір є вашим головним питанням, і ви готові взяти криву навчання планів Хабітат, це може бути рішенням для вас.


0

Можна також скористатися зануренням

docker run --rm -it \
    -v /var/run/docker.sock:/var/run/docker.sock \
    wagoodman/dive:latest <dive arguments...>

щоб отримати звіт про те, які відходи можна видалити з зображення докера, щоб зменшити розмір.


0

Якщо ви хочете мати рівні розробки для багаторазового використання, але зменшити використання диска для доставки, ви можете створити об'єднаний "рівень доставки" на зразок цього:

  1. Переконайтеся, що у вас є контейнер, який використовує ваше зображення (якщо у вас його немає, можливо, використовуйте щось на зразок docker run IMAGE echo, якщо команда ехо доступна)
  2. Знайдіть ідентифікатор контейнера (можливо, використовуючи docker container ls -l)
  3. Труба docker exportдля docker importстворення об'єднаного шару (щось на зразок docker export 20f192c6530a | docker import - project:merged)

Це дозволить зберегти ваші шари розвитку навколо, але дасть вам менший об'єднаний образ, який ви можете надати.


0

Багатоетапні побудови. Використовуйте зображення, у яких є всі складові компоненти для створення програми, і легше зображення під час виконання. Скопіюйте артефакт побудови на зображення, яке виконується. Не потрібно нічого видаляти.

https://docs.docker.com/develop/develop-images/multistage-build/


0

простий .. docker ps перевірити поточні запущені зображення ... для простого прикладу файлу нижче ..

ВІД ubuntu16

MAINTAINER sreeni (електронна пошта / домен)

RUN apt-get update

RUN apt-get install -y nginx

ENTRYPOINT [“/ usr / sbin / nginx”, “- g”, “демон демон;”]

ВИДАЧА 80 (порт)

простий файл докера ...

використовувати нижче команду docker

docker run -d -p 80:80 - ім'я веб-сервера ubuntu16 (ім'я зображення), після цього перевірте localhost або ip адресу: 80 (відкрити браузер і перевірити)


1
будь ласка, виправте форматування своєї відповіді ...
Pierre.Vriens
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.