- PVSM.RU - https://www.pvsm.ru -
Ускорить имеющиеся пайплайны в 2 раза (до, хотя бы, получаса). Попутно повысив стабильность до 90%.
Забегая вперед, скажу что требуемые показатели были достигнуты.
Для инкрементальной сборки lerna filter options [5]:
lerna run build:packages --since --include-merged-tags --include-dependencies
Чтобы попасть в инкремент пакеты должны проходить фазу lerna publish [6] в артифакторий (JFrog):
# Master
lerna publish patch --yes
# Feature
lerna publish prepatch --yes --no-push --preid "${PREID}"
При такой организации pipeline, возможно только вертикальное масштабирование путём увеличения мощностей elastic агентов.
Этот подход крайне ограничен. И с ростом числа пакетов средняя длительность постепенно росла (~1ч).
Надо заметить, что в силу короткого релизного цикла (сутки), стабильность JFrog и, как следствие, всего pipeline была низка (~70%).
Собирать каждое приложение независимо от остальных.
На входе — монорепозиторий
На выходе — production image приложения.
Тестировать тоже независимо от остальных.
На входе — production image (зависимости устанвлены, все пакеты собраны)
На выходе — отчеты о тестировании и покрытии.
Это позволит собирать и тестировать в параллельном режиме, масштабируясь горизонтально по мере развития линейки продуктов.
Но в таком случае размер node_modules составил бы ~1.5Gb (суммарные зависимости всех пакетов монорепозитория). Что негативно отразилось бы на размере image, времени его загрузки в AWS ECR, и времени развертывания.
Чтобы "урезать" ("сфокусировать") монорепозиторий для сборки, тестирования и развертывания одного конкретного приложения, достаточно найти подмножество пакетов в общем графе пакетов и переписать декларацию workspaces [2] в корневом package.json непосредственно перед сборкой на CI.
#!/usr/bin/env node
const { spawnSync } = require('child_process');
const { existsSync, promises: { readFile, writeFile } } = require('fs');
const { join, dirname, relative, normalize } = require('path');
const PACK_JSON_PATH = './package.json';
(async (apps) => {
const packJSON = JSON.parse((await readFile(PACK_JSON_PATH)).toString());
await spawnSync('yarn', ['global', 'add', 'lerna'], { shell: true });
const locations = await listPackages(apps);
const [someLocation] = locations;
const basePath = findBasePath(someLocation);
// All paths should be relative to monorepo root
const workspaces = locations.map((loc) => normalize(relative(basePath, loc)));
packJSON.workspaces.packages = workspaces;
const packJSONStr = JSON.stringify(packJSON, undefined, 2);
await writeFile(PACK_JSON_PATH, `${packJSONStr}n`);
})(
process.argv.slice(2),
);
async function listPackages(apps = []) {
const filterOptions = apps.flatMap((app) => ['--scope', app]);
const { stdout } = await spawnSync(
'lerna',
['ls', '-pa', '--include-dependencies', ...filterOptions],
{ shell: true },
);
return String(stdout).split(/[rn]+/).filter(Boolean);
}
function findBasePath(packageLocation) {
return existsSync(join(packageLocation, 'lerna.json'))
? packageLocation
: findBasePath(dirname(packageLocation));
}
После "фокусировки" все команды (в том числе и changed) будут относится лишь к подмножетсву пакетов конкретного приложения.
Размер node_modules удалось снизить в среднем в 3 раза.
Lerna fixed mode [7], отказ от lerna publish
и артифактория позволили повысить стабильность и упростить логику pipeline.
Но как же быть с инкрементальностью сборок?
Для инкремента достаточно отслеживать изменения через команду lerna changed [8]
lerna changed -a --include-merged-tags
Если изменений не обнаружено, то можно переиспользовать latest image приложения для развертывания и тестирования:
#!/usr/bin/env bash
APP=$1
lerna-focus.js "${APP}"
function nothing_changed() {
[[ -z "$(lerna changed -a --include-merged-tags || true)" ]]
}
function pull_latest_image() {...}
function push_latest_image() {...}
function tag_latest_with_version() {...}
pull_latest_image
if nothing_changed; then
tag_latest_with_version
exit
fi
build-app.sh "${APP}"
if is-master.sh; then
push_latest_image
fi
Сейчас активно набирают обороты такие решения как Nx: Extensible Dev Tools for Monorepos [10]. Это предмет следующих разборов.
Если эта статья окажется полезной, то в следующей расскажу о горизонтальном масштабировании "на коленке" модульных тестов (Angular, Jest, ElasticSearch, Bamboo CI).
Автор: Alexander
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/bash/355165
Ссылки в тексте:
[1] Lerna: https://github.com/lerna/lerna
[2] Yarn workspaces: https://classic.yarnpkg.com/en/docs/workspaces/
[3] Atlassian Bamboo CI/CD: https://www.atlassian.com/ru/software/bamboo/features
[4] Image: https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcblx0Q1tDaGVja291dF0gLS0-IEJQW0J1aWxkIHBhY2thZ2VzIGluY3JlbWVudGFsbHldIC0tPiBCW0J1aWxkIGFwcHMgaW5jcmVtZW50YWxseV1cblx0QyAtLT4gQlBUW0J1aWxkIGFsbCBwYWNrYWdlc10gLS0-IFRbVGVzdCBhbGwgYXBwc11cblx0VCAtLT58Y292ZXJhZ2V8IFNbU29uYXJdXG5cdEIgJiBTIC0tPiBQW1B1Ymxpc2hdXG5cdC0tPiBEW0RlcGxveV0gLS0-IEUyRSIsIm1lcm1haWQiOnsidGhlbWUiOiJkZWZhdWx0In0sInVwZGF0ZUVkaXRvciI6ZmFsc2V9
[5] lerna filter options: https://github.com/lerna/lerna/tree/master/core/filter-options#readme
[6] lerna publish: https://github.com/lerna/lerna/tree/master/commands/publish
[7] Lerna fixed mode: https://github.com/lerna/lerna#fixedlocked-mode-default
[8] lerna changed: https://github.com/lerna/lerna/tree/master/commands/changed
[9] Image: https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoiZ3JhcGggTFJcblx0Q1tDaGVja291dF0gLS0-IFZbQnVtcCB2ZXJzaW9uXVxuXHRWIC0tPiBGMVtGb2N1cyBvbiBhcHAgIzFdIC0tPiBCMVtCdWlsZCBhcHAgIzFdIC0tPiBQMVtQdXNoIGltYWdlICMxXVxuXHRWIC0tPiBGMltGb2N1cyBvbiBhcHAgIzJdIC0tPiBCMltCdWlsZCBhcHAgIzJdIC0tPiBQMltQdXNoIGltYWdlICMyXVxuXHRWIC0tPiBGM1tGb2N1cyBvbiBhcHAgIzNdIC0tPiBCM1tCdWlsZCBhcHAgIzNdIC0tPiBQM1tQdXNoIGltYWdlICMzXVxuXHRWIC0tPiBGTltGb2N1cyBvbiBhcHAgI05dIC0tPiBCTltCdWlsZCBhcHAgI05dIC0tPiBQTltQdXNoIGltYWdlICNOXVxuXHRQMSAtLT4gVDFbVGVzdCBhcHAgIzFdICYgRDFbRGVwbG95IGFwcCAjMV1cblx0UDIgLS0-IFQyW1Rlc3QgYXBwICMyXSAmIEQyW0RlcGxveSBhcHAgIzJdXG5cdFAzIC0tPiBUM1tUZXN0IGFwcCAjM10gJiBEM1tEZXBsb3kgYXBwICMzXVxuXHRQTiAtLT4gVE5bVGVzdCBhcHAgI05dICYgRE5bRGVwbG95IGFwcCAjTl1cblx0VDEgLS0-fGxjb3Z8IFMxW1NvbmFyICMxXVxuXHRUMiAtLT58bGNvdnwgUzJbU29uYXIgIzJdXG5cdFQzIC0tPnxsY292fCBTM1tTb25hciAjM11cblx0VE4gLS0-fGxjb3Z8IFNOW1NvbmFyICNOXVxuXHREMSAtLT58dXJsfCBFMVtFMkUgIzFdXG5cdEQyIC0tPnx1cmx8IEUyW0UyRSAjMl1cblx0RDMgLS0-fHVybHwgRTNbRTJFICMzXVxuXHRETiAtLT58dXJsfCBFTltFMkUgI05dXG5cdFMxICYgUzIgJiBTMyAmIFNOICYgRTEgJiBFMiAmIEUzICYgRU4gLS0-IFByb21vdGVcblx0XHRcdFx0XHQiLCJtZXJtYWlkIjp7InRoZW1lIjoiZGVmYXVsdCJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ
[10] Nx: Extensible Dev Tools for Monorepos: https://nx.dev/
[11] Источник: https://habr.com/ru/post/511614/?utm_source=habrahabr&utm_medium=rss&utm_campaign=511614
Нажмите здесь для печати.