[JavaScript, Node.JS, TypeScript, Микросервисы] Делаем микрообразы с микросервисами

Автор Сообщение
news_bot ®

Стаж: 6 лет 2 месяца
Сообщений: 27286

Создавать темы news_bot ® написал(а)
22-Июн-2021 23:30

Из цикла "Микросервисы или смерть"Решаемая проблема: монолитное приложение на Node.js раньше, в развернутом состоянии, занимало 0.2 Гб всего. Теперь же, разбитое на 33 микросервиса, занимает 33 * 0.1 = 3.3 Гб. Можно ли избежать подобной издержки? -- можно! В статье мы избавимся от лишнего веса.
Решение, представленное в статье подходит больше для контура разработки, но и для продуктового контура его использовать никто не запрещал.Откуда лишний размер?Во-первых разберемся, откуда берётся лишний размер при переходе от монолита к микросервисной архитектуре.Допустим есть микросервис MsA с зависимостями: express, axios, nats ; и микросервис MsB с зависимостями: express, axios и mongoose. Рассмотрим докер файл для MsA (упрощено для краткости):
FROM node:alpine
COPY . .
RUN npm install
CMD ["npm", "start"]
Получившиеся слои образа:
  • FROM node:alpine --> 100 Mb
  • COPY . . --> 0.5 Mb
  • RUN npm install --> 50-100+ Mb
Dockerfile для MsB и его слои будут выглядить аналогично.node:alpine у нас используется для всех микросервисов, и, соответственно, этот слой (слой №1) будет общий. Но два следующих слоя будут отличатся от микросервиса к микросервису. Именно они будут сказываться на общем размере. У наших микросервисов есть общие зависимости - express, axios При npm install они будут скопированы в каждый образ. Отсюда общее увеличение. Общие зависимости дублируются во всех микросервисах, увеличивая общий размер.РешениеПриходит на ум решение, что должен быть некий общий образ, который будет базовым для всех микросервисов
Есть много способов прийти к такому результату, не буду ходить вокруг да около, рассматривая плюсы и минусы, а сразу приведу решение. В микросервисах MsA и MsB есть общие зависимости (express, axios) но есть и отличающиеся (mongoose и nats). В нашем решении мы просто возьмём и объединим их всех в один package.json. С некоторыми особенностями. Нам нужны только зависимости, работающие на этапе эксплуатации. Зависимости на этапе сборки нам не нужны. Т.е. jest, webpack, typescript и т.п. зависимости в devDependences каждого микросервиса могут отличаться. Но вот раздел dependences будет одинаков для всех микросервисов. Вне зависимости, используют ли они nats или mongoose, эта зависимость там будет. Вторая особенность это общая практика использования зависимостей со строго фиксированными версиями зависимостей. Чтобы билд при создании образа надёжно проходил, а не падал от минорных апдейтов.Т.е. у нас будет проект BaseMS (типа базовый образ для всех микросервисов) с package.json примерно таким (упрощено для краткости):
{
    "name": "basems",
     "dependencies": {
        "axios": "0.21.1",
        "express": "4.17.1",
        "mongoose": "5.12.8",
        "node-nats-streaming": "0.3.2"
  }
}
и Dockerfile примерно таким:
FROM node:alpine
COPY . .
RUN npm install
Для MsA package.json будет таким (упрощено для краткости):
{
  "name": "markups",
  "main": "index.js",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "test": "jest --watchAll --no-cache"
  },
  "devDependencies": {
    "jest": "^26.1.0",
    "mongodb-memory-server": "^6.9.6",
    "supertest": "^6.1.2",
    "ts-jest": "^26.1.3",
    "typescript": "^4.1.3",
    "webpack": "^5.21.2",
    "webpack-cli": "^4.5.0",
    "webpack-node-externals": "^2.5.2"
  },
  "dependencies": {
    "axios": "0.21.1",
    "express": "4.17.1",
    "mongoose": "5.12.8",
    "node-nats-streaming": "0.3.2"
  }
}
Для MsB package.json будет аналогичен, но набор devDependencies может отличаться.Webpack (опционально) Допустим мы используем typescript и хотим еще всё пожать webpack. Webpack можно использовать для бэкэнда, надо лишь не включать в итоговый бандл node_modules. В этом нам поможет небольшой пакет для webpack -- webpack-node-externals. Надо просто добавить в webpack.config.js следующий код:
const nodeExternals = require('webpack-node-externals');
...
module.exports = {
    target: 'node',
    ...
    externals: [nodeExternals()],
    ...
};
Dockerfile для микросервисовДля микросервисов теперь будем использовать мультистейдж билд в докере. На первом этапе собираем итоговый файл index.js. На втором создаем итоговый образ, просто копируя итоговый index.js в базовый образ
# Этап сборки
FROM node:alpine
COPY package.json .
RUN npm install
COPY . .
RUN npm run build
# Рабочий уровень
FROM localhost:5000/basems
COPY --from=0 app/dist/index.js .
CMD ["node", "index.js"]
Образ localhost:5000/basems - это как раз наш базовый образ, собранный выше. Он называется так, т.к. мы его пушим в локальный хаб registryДля всех микросервисов файл докера будет одинаковый. Давайте рассмотрим получившиеся слои:
  • FROM localhost:5000/basems --> 150 Mb
  • COPY --from=0 app/dist/index.js . --> 0.5 Mb
Вот и всё, первый слой для всех общий и весит 150 Мб, а вот слой уникальный для каждого докера будет минимального размера.Достоинства и недостатки подходаНедостатки:
  • Если необходимо изменить набор рабочих зависимостей для отдельного микросервиса, придется ребилдить/репушить все микросервисы. Но на деле набор зависимостей быстро устаканится в процессе разработки и это не будет проблемой.
  • При изменении зависимостей в одном микросервисе (рабочих) необходимо менять package.json файлы всех микросервисов. На деле такие изменения легко автоматизировать, это может делаться по кнопке в доли секунду и, к тому же, даже будет плюсом, т.к. поможет не допустить ошибок при ручном изменении.
  • Подобный трюк работает только на Node.js основанных микросервисах. Но ничего страшного, если у вас на ноде лишь часть микросервисов -- это сработает и для них. А остальные останутся как и раньше.
Достоинства:
  • Итоговый размер слоев минимален. Можно делать хоть тысячу микросервисов с микрофункциональностью.
  • Мы обновляем рабочие зависимости в одном месте. Устраняем vulnerabilities в одном месте. А затем по кнопке накатываем на все микросервисы.. Это, кстати, достоинство даже круче первого
Всем спасибо!
===========
Источник:
habr.com
===========

Похожие новости: Теги для поиска: #_javascript, #_node.js, #_typescript, #_mikroservisy (Микросервисы), #_optimizatsija (оптимизация), #_docker, #_dockerfile, #_webpack, #_javascript, #_node.js, #_typescript, #_mikroservisy (
Микросервисы
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 02-Май 22:31
Часовой пояс: UTC + 5