Оптимизация образов Dockerfile для NextJS
Докер-образы NextJS слишком велики. Поэтому эта статья будет посвящена тому, как оптимизировать dockerfile для производства. Здесь я использую 2 способа оптимизации образов docker.
Полный исходный код здесь
Установка
Сначала нам нужно создать проект в nextjs. В качестве примера я использую Vercel, проект здесь.
Структура проекта:
.
├── @types
│ └── remark-html.d.ts
├── README.md
├── _posts
│ ├── dynamic-routing.md
│ ├── hello-world.md
│ └── preview.md
├── components
│ ├── alert.tsx
│ ├── avatar.tsx
│ ├── container.tsx
│ ├── cover-image.tsx
│ ├── date-formatter.tsx
│ ├── footer.tsx
│ ├── header.tsx
│ ├── hero-post.tsx
│ ├── intro.tsx
│ ├── layout.tsx
│ ├── markdown-styles.module.css
│ ├── meta.tsx
│ ├── more-stories.tsx
│ ├── post-body.tsx
│ ├── post-header.tsx
│ ├── post-preview.tsx
│ ├── post-title.tsx
│ └── section-separator.tsx
├── interfaces
│ ├── author.ts
│ └── post.ts
├── lib
│ ├── api.ts
│ ├── constants.ts
│ └── markdownToHtml.ts
├── next-env.d.ts
├── package.json
├── pages
│ ├── _app.tsx
│ ├── _document.tsx
│ ├── index.tsx
│ └── posts
│ └── [slug].tsx
├── postcss.config.js
├── public
│ ├── assets
│ │ └── blog
│ │ ├── authors
│ │ │ ├── jj.jpeg
│ │ │ ├── joe.jpeg
│ │ │ └── tim.jpeg
│ │ ├── dynamic-routing
│ │ │ └── cover.jpg
│ │ ├── hello-world
│ │ │ └── cover.jpg
│ │ └── preview
│ │ └── cover.jpg
│ └── favicon
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ ├── apple-touch-icon.png
│ ├── browserconfig.xml
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── favicon.ico
│ ├── mstile-150x150.png
│ ├── safari-pinned-tab.svg
│ └── site.webmanifest
├── styles
│ └── index.css
├── next.config.js
├── tailwind.config.js
└── tsconfig.json
Затем установите и соберите этот блог:
➜ blog-starter git:(master) ✗ yarn
➜ blog-starter git:(master) ✗ yarn build
➜ blog-starter git:(master) ✗ yarn start
Ваш блог должен быть запущен и работать на localhost:3000.
Сборка на Docker
Игнорируйте ненужные файлы с помощью .dockerignore
:
node_modules
*.DS_Store
.next
.gitignore
README.md
.dockerignore
LICENSE
.docker
.gitlab
Здесь у нас есть 3 сценария dockerfile
. Сначала я использую базовый Dockerfile:
➜ blog-starter git:(master) ✗ docker build -t blog-with-basic-dockerfile -f .docker/basic.dockerfile .
# Check docker images
➜ blog-starter git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
blog-with-basic-dockerfile latest b70f75178890 8 seconds ago 370MB
В этом сценарии мы построили nextjs image
размером 370MB.
Далее мы используем многоступенчатый докер с помощью Multi Stage Docker:
➜ blog-starter git:(master) ✗ docker build -t blog-with-multistage-dockerfile -f .docker/multistage.dockerfile .
# Check docker images
➜ blog-starter git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
blog-with-multistage-dockerfile latest 07c84ea2173a 38 seconds ago 339MB
В этом способе я использую модуль node-prune
в стадии BUILD после установки пакетов. node-prune
может удалять ненужные файлы из node_modules
:
files total 43,924
files removed 12,814
size removed 28 MB
duration 866ms
Хехе, уменьшилось на 28 МБ. Вы можете следовать этому руководству для настройки в вашем базовом образе ноды. Итак, это изображение было оптимизировано 370MB -> 339MB.
Наконец, мы собираем dockerfile
с многоступенчатым docker и включаем режим standalone для NextJS. Создаем файл next.config.js
с содержимым:
module.exports = {
output: "standalone"
}
Nextjs
может автоматически создавать автономную папку, в которую копируются только необходимые файлы для развертывания на производстве, включая некоторые файлы в node_modules
. Больше документации.
Начнем с Dockerfile:
➜ blog-starter git:(master) ✗ docker build -t blog-with-multistage-standalone-dockerfile -f .docker/multistage_standalone.dockerfile .
# Check docker images
➜ blog-starter git:(master) ✗ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
blog-with-multistage-standalone-dockerfile latest 07c84ea2173a 38 seconds ago 119MB
Вот это да! Отлично … Размер изображений составляет всего 119MB.
Итак, я представил 3 способа оптимизации размера изображения, но … они работают очень медленно. В следующем посте я покажу вам, как создать изображение быстрее.
Спасибо за прочтение 😁😁😁😁