Вы ненавидите развертывание приложения, которое занимает слишком много времени? Превышать гигабайты — не лучшая практика для одного контейнера. Иметь дело с гигабайтами каждый раз, когда мы развертываем новую версию, нам кажется неправильным.
В этой статье будет показано несколько простых шагов по оптимизации образов Docker, чтобы сделать их меньше, быстрее и более подходящими для производственных сред с помощью программы Nodejs.
Простой фрагмент проекта Node.js
Сначала напишите простую программу веб-сервера на основе экспресс-
// package.json
{
"name": "docker-test",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node app"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.16.4"
},
"devDependencies": {
"eslint": "^5.16.0"
}
}
// app.js
const express = require('express')
const app = express()
app.get('/', function(req, res){
res.send('hello world')
})
app.listen(3000)
Создайте новый DockerFile в корневом каталоге и напишите следующий код
# Dockerfile
FROM node
COPY . /home/app
RUN cd /home/app && npm install
WORKDIR /home/app
CMD ['npm', 'start']
воплощать в жизнь
- docker build -t myapp .
- docker images
Вы можете видеть, что самая простая программа nodejs имеет 920 МБ, пожалуйста, не делайте этого. Далее мы будем постепенно уменьшать размер этого изображения.
Оптимизация образа производственной среды Docker
-
Использование образа Node.js Alpine
Самый простой и быстрый способ резко уменьшить размер изображения — выбрать базовое изображение гораздо меньшего размера. Alpine — это крошечный дистрибутив Linux, который выполняет свою работу. Просто выберите версию Node.js для Alpine, и вы получите значительные улучшения.
FROM node:alpine COPY . /home/app RUN cd /home/app && npm install WORKDIR /home/app CMD ['npm', 'start']
после сборки
Видно, что уменьшение800MB, что является очень большой оптимизацией.
-
Пакеты зависимостей, разработанные в среде сборки, не упакованы
Но мы можем продолжить оптимизацию. Мы устанавливаем все зависимости, хотя нам нужны только зависимости среды сборки. Если вы упаковываете только производственную среду, она будет не так хороша, продолжайте ее улучшать.
FROM node:alpine COPY . /home/app RUN cd /home/app && npm install --production WORKDIR /home/app CMD ['npm', 'start']
после сборки
Мы уменьшили его еще на 6 МБ, потому что в настоящее время у нас есть только одна зависимость для разработки, что, вероятно, было бы довольно большой оптимизацией и в обычном проекте.
-
Соберите Nodejs, используя базовую версию образа Alpine.
Что, если мы воспользуемся базовой версией образа Alpine и сами установим Nodejs?
FROM alpine:latest RUN apk add --no-cache --update nodejs nodejs-npm COPY . /home/app RUN cd /home/app && npm install --production WORKDIR /home/app CMD ['npm', 'start']
после сборки
Сейчас осталось всего 65Мб, что более чем в 10 раз меньше, чем в начале.
-
многоступенчатая сборка
-
Образы Docker многоуровневые, каждая инструкция в Dockerfile создает новый слой образа, который можно повторно использовать и кэшировать. Когда инструкции Dockerfile изменены, скопированные файлы изменены или переменные, указанные при построении образа, отличаются, соответствующий кеш слоя изображения станет недействительным.После того, как кеш изображения определенного слоя станет недействительным, последующий слой изображения кеш станет недействительным.
-
Следовательно, мы также можем комбинировать инструкции RUN, но нам нужно помнить, что мы можем комбинировать только инструкции с одинаковой частотой изменения.
-
Мы должны поместить части с наименьшими изменениями в начало Dockerfile, чтобы мы могли в полной мере использовать кеш изображений.
-
Минимизируя количество слоев изображения, мы можем получить изображения меньшего размера.
-
В приведенном выше примере исходный код будет часто меняться, поэтому каждый раз при сборке образа необходимо переустанавливать модуль NPM, что явно не то, что мы хотим видеть. Таким образом, мы можем сначала скопировать package.json, затем установить модули npm и, наконец, скопировать остальную часть исходного кода. Таким образом, вам не нужно переустанавливать модули npm, даже если исходный код изменится.
FROM alpine AS builder
WORKDIR /home/app
RUN apk add --no-cache --update nodejs nodejs-npm
COPY package.json package-lock.json ./
RUN npm install --production
FROM alpine
WORKDIR /home/app
RUN apk add --no-cache --update nodejs nodejs-npm
COPY --from=builder /usr/src/app/node_modules ./node_modules
COPY . .
CMD [ 'npm', 'start' ]
Окончательное изображение весит всего 51 МБ, что примерно в 17 раз меньше оригинала! И последующая скорость сборки также значительно улучшена.
Каждая инструкция FROM представляет собой этап построения, а несколько FROM представляют собой многоэтапное построение. Хотя окончательное сгенерированное изображение может быть только результатом последнего этапа, файлы на предыдущем этапе можно скопировать на более поздний этап. значение многоэтапного строительства.
В приведенном выше Dockerfile мы сначала скопировали package.json, а затем npm install.На втором этапе построения мы напрямую скопировали скачанный node_moduls на первом этапе.В следующей сборке, если не будут добавлены новые зависимости, Docker будет использовать node_modules из кэша, что сокращает время развертывания.
Используя команду docker inspect imageId, мы видим, что хотя у нас есть несколько инструкций, финальное изображение имеет только 5 слоев, что является механизмом совместного использования слоев.
Использование многоэтапных сборок позволяет использовать кэш образов Docker, что значительно сокращает время до окончательного развертывания в рабочей среде.
В заключение
В реальной производственной среде нет причин использовать размер образа в ГБ, если вам действительно нужно ускорить развертывание, и вас мучает медленный CI/CD, то многоэтапная сборка будет очень полезным способом.
Надеюсь, эта короткая статья будет полезна всем, кто рассматривает возможность использования Docker для разработки или развертывания приложений на основе Node.js.
Сфокусируйся наgithubПодробное объяснение одного вопроса интервью каждый день