@Dima_Amigo

Как ускорить docker push?

Столкнулся с тем, что команда docker push работает ну очень медленно и в этом, наверное, нет никакого смысла.

В Dockerfile запускается команда загрузки всех зависимостей `RUN npm install`. Она качает около 600МБ файлов и всё это попадает в один слой докер образа, который в сжатом виде весит около 400МБ (не суть).
Далее этот слой грузится на приватный docker registry.

Вопрос: даже если изменится хотя бы один файл в зависимостях, докер опять создаст и попытается загрузить новый слой размером в 400МБ. Может быть есть готовые решения, чтобы docker push/pull не скачивали по 400МБ при малейшем изменении? Может быть есть другая утилита, которая заменяет собой docker push/pull и внутри хранит содержимое отдельных слоёв в гите?

UPD:

Представьте, что мы можем изменить реализацию команд docker push/pull.

Альтернативный docker push берёт нужный образ и помещает его через docker save в архив. Этот архив нужно разархивировать вместе со всеми слоями внутри и запушить в специальный git-репозиторий.

Альтернативный docker pull скачивает нужный образ из определённой ветки или тега в гите, собирает обратно из него архив и через docker load загружает образ в докер.

По времени должно работать быстрее, потому что будут догружены только те файлы, которые изменились.

Минусы в таком подходе тоже есть: каждый git fetch вынужден грузить абсолютно все новые изменения (все версии).

Можно думать над велосипедами в эту сторону (может быть rsync вместо git), но вдруг уже есть готовое решение...
  • Вопрос задан
  • 351 просмотр
Решения вопроса 1
Lynn
@Lynn
nginx, js, css
Можно использовать multi-stage build
Примерно так:
FROM node:lts-alpine as build
WORKDIR /app
# копируем исходный код
COPY ./ ./
# устанавливаем зависимости
RUN npm ci
# Компилируем приложение
RUN npm run build
# оставляем только production зависимости
RUN npm ci --prod
# опционально удаляем из исходников всякие тесты, ts-файлы и т.п.

FROM node:lts-alpine as app
WORKDIR /app
# копируем сначала node_modules
COPY --from=build /app/node_modules ./node_modules
# а потом всё остальное
COPY --from=build /app ./
# и запускаем
CMD [ "node", "/app/app.js" ]


В результате, если не меняется файл package-lock.json (т.е. не меняются зависимости прода), то слой созданный в команде COPY --from=build /app/node_modules ./node_modules будет взят из кэша. А это и есть все наши 400 мегабайт зависимостей.

живой пример

Это второй запуск после изменения приложения и версии в package.json, но без изменений зависимостей. Тут видно, что шаг 4 сборки честно выполнился, но при этом шаг 9 (копирование node_modules) взят из кэша, т.к. папка node_modules не поменялась.
$ docker build .
Sending build context to Docker daemon  6.656kB
Step 1/11 : FROM node:lts-alpine as build
 ---> 1c342643aa5c
Step 2/11 : WORKDIR /app
 ---> Using cache
 ---> 01d641ac9d8b
Step 3/11 : COPY ./ ./
 ---> 2a369bda0312
Step 4/11 : RUN npm ci
 ---> Running in 5becac2f9f07
added 2 packages in 1.914s
Removing intermediate container 5becac2f9f07
 ---> c010ba772a08
Step 5/11 : RUN npm run build
 ---> Running in de6fd7f872a5

> docker-node@1.2.3 build /app
> echo building app

building app
Removing intermediate container de6fd7f872a5
 ---> dc80bc125954
Step 6/11 : RUN npm ci --prod
 ---> Running in 825f86a54af5
npm WARN prepare removing existing node_modules/ before installation
added 1 packages in 0.079s
Removing intermediate container 825f86a54af5
 ---> a00a029b86dc
Step 7/11 : FROM node:lts-alpine as app
 ---> 1c342643aa5c
Step 8/11 : WORKDIR /app
 ---> Using cache
 ---> 01d641ac9d8b
Step 9/11 : COPY --from=build /app/node_modules ./node_modules
 ---> Using cache
 ---> 81d587ccf147
Step 10/11 : COPY --from=build /app ./
 ---> bb40061f06b6
Step 11/11 : CMD [ "node", "/app/app.js" ]
 ---> Running in e6b9e08d9d8f
Removing intermediate container e6b9e08d9d8f
 ---> eceb38619009
Successfully built eceb38619009

Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@vitaly_il1
DevOps Consulting
Я человек практический, поэтому не верю что могу изобрести велосипед, который
1) будет работать принципиально лучше чем существующие
2) станет общепринятым

Поэтому я за multi-stage build, плюс можно выделить в отдельные слои "постоянные" и "переменнные" пакеты.
Обычно есть 80% пакетов 3rd party, они постоянные, и немного своих которые меняются.
Ответ написан
Комментировать
shurshur
@shurshur
Сисадмин, просто сисадмин...
Это невозможно. В принципе. Слой загружается на сервер только целиком, нельзя проверять, что в нём отличается только один файл. Тем более отличаться будет не только файл, но и, например, каталог, в который его положили - у него изменится mtime. Всё это отслеживается через контрольную сумму архива слоя, она от любого нового файла меняется.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы