Оптимизация образов Docker — Lean Docker Images для Next.JS
3 февраля 2023 г.Использование многоэтапных сборок для оптимизации рабочего образа Docker для более быстрого развертывания.
В этой статье
- 🧑🔬 Мы обсудим, почему и где оптимизация образа Docker может иметь смысл.
- 🙈 Мы рассмотрим, как докеризировать проект Next.js со скрытой функцией.
- 🪄 Мы углубимся в магию оптимизации образа Docker.
Проблема
На работе я заметил, что наш конвейер развертывания работает значительно медленнее, чем я ожидал. Упрощенный конвейер состоит из следующих заданий:
После некоторого исследования мы смогли выявить узкое место в производительности. Больше всего времени занимала загрузка рабочих образов в реестр Google Cloud Artifact Registry. Это произошло потому, что мы загружали в реестр большие неоптимизированные образы Docker.
Размер изображения не является такой серьезной проблемой, как безопасность или пропускная способность в целом. Хранилище и стоимость в облаке обычно щедры. Однако это становится проблематичным, когда замедляет конвейер. Это увеличивает время выхода на рынок и влияет на нашу способность непрерывно доставлять.
На что влияет оптимизация образа Docker?
Мы будем использовать демо-версию DALL-E, созданную мной для моей предыдущей статьи. в качестве примера. Демо выглядит так:
<цитата>
Вы можете найти демонстрацию на GitHub. Не стесняйтесь взглянуть на репозиторий и попробовать✨
Мы создадим два файла docker:
* Dockerfile.local: базовый образ без оптимизации. * Dockerfile: оптимизированный образ
Давайте создадим образы на основе каждого файла докера. Результаты:
* Неоптимизированное изображение: 2,85 ГБ * Оптимизированное изображение: 202 МБ
Размер уменьшился на 92%. Мы можем грубо интерпретировать это как сокращение времени загрузки на 92%, потому что передача файлов по HTTPS является линейной. Теперь давайте рассмотрим, как добиться того же результата.
Поехали.
Перед оптимизацией изображения
Мы можем начать с создания простого Dockerfile, подобного этому:
# Dockerfile.local
FROM node:18-alpine
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY . ./
# Build the app
RUN yarn --frozen-lockfile
RUN yarn build
# Serve the app
CMD [ "yarn", "start" ]
В этом образе мы используем Alpine Linux Node 18 в качестве базового образа из-за его гораздо меньшего размера. по сравнению с другими базовыми изображениями. Мы также следуем рекомендации и добавляем libc6-compat для поддержки использования "process. открыть". Остальное точно так же, как мы строим и обслуживаем проект локально:
* Сначала мы устанавливаем зависимости на основе файла yarn.lock, * мы генерируем производственную сборку, * и, наконец, запускаем сервер скриптом "yarn start".
Давайте создадим образ, используя этот файл докера, и это обычно то, что вы можете увидеть в командной строке:
Сборка была завершена за 52,9 с.
Оптимизированный образ Docker
Оптимизация основана на двух функциях Docker и Next.js:
* Многоэтапные сборки Docker * Трассировка выходного файла Next.js
Идея состоит в том, чтобы использовать многоэтапную сборку, чтобы выбрать только то, что нам нужно в рабочей среде, этап по этапам. Давайте посмотрим на файл докера.
# Dockerfile
ARG NODE=node:18-alpine
# Stage 1: Install dependencies
FROM ${NODE} AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json yarn.lock* ./
RUN yarn --frozen-lockfile
# Stage 2: Build the app
FROM ${NODE} AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
# Stage 3: Run the production
FROM ${NODE} AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# copy assets and the generated standalone server
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
# Serve the app
CMD ["node", "server.js"]
Мы использовали тот же «node:18-alpine», что и базовое изображение.
Этап 1. Установка зависимостей
Вместо того, чтобы копировать все в образ, мы копировали только "package.json" и "yarn.lock" для установки.
Этап 2. Создание приложения
Для сборки проекта нам нужны были установленные зависимости, исходный код и все конфигурации проекта в корне проекта. Итак, мы скопировали зависимости из предыдущего этапа и все из корня проекта.
Этап 3. Запуск производства
Трассировка выходных файлов – это функция Next.js, которая помогает нам сократить развертывание. размера путем отслеживания всех файлов, необходимых для производства, во время сборки.
Как только мы включим «автономный» вывод, Next.js создаст и выведет автономный сервер Node в каталоге «.next/standalone».
module.exports = {
output: 'standalone',
}
Результат сборки выглядит следующим образом:
![отдельная папка
](https://cdn.hackernoon.com/images/XyqHIwK0xDMOGdIf5iTNW4CrLjb2-m8e35c6.png)
На этом этапе мы всего лишь скопировали автономный сервер, ресурсы в папке "./public", фрагменты JavaScript и CSS из папки ".next/static" в рабочий каталог и запустили сервер. с портом 3000.
Магия трассировки выходного файла заключается в @vercel/nft. Он статически анализирует граф зависимостей и выводит список модулей в графе. Для иллюстрации давайте зарегистрируем зависимости для нашей страницы, API и сервера Node:
import { nodeFileTrace } from "@vercel/nft";
const files = [
"./.next/server/app/sc/page.js",
"./.next/server/pages/api/images.js",
"node_modules/next/dist/server/next-server.js",
];
const { fileList } = await nodeFileTrace(files);
console.log(fileList);
Вывод выглядит следующим образом:
Заключительные мысли
Теперь, когда мы изучили этапы и автономный сервер, давайте создадим образ и посмотрим на результат:
Сборка была завершена за 41,3 с. По сравнению с неоптимизированной сборкой мы не снизили время сборки. Это большая победа, учитывая, что мы значительно уменьшили размер сборки на 92%.
Ссылки
- Многоэтапные сборки – документация по Docker
- Трассировка выходного файла — Next.js
- nodejs/docker-node – Node.js
- Справочник по запуску Docker — документация по Docker
- DawChihLiou/qwik-vs-next — Доу-Чих Лиу
- Является ли Qwik быстрее, чем серверный компонент React? — Daw- Чжи Лю
- С Docker — Next.js
- Развертывание — Next.js
- vercel/nft – Vercel
- libc6-compat – Alpine Linux
- Реестр артефактов – Google Cloud
- Сверхмалый образ Docker на базе Alpine Linux — Hacker News
- Время выхода на рынок – Википедия
- Руководство бывшего главного инженера по дизайн-мышлению и Непрерывная доставка – Доу-Чи Лиу
Хотите подключиться?
Эта статья изначально была опубликована на веб-сайте Daw-Chih.
Оригинал