Оптимизация Pipeline монорепозитория

Если мы ведём разработку всего проекта в одном монорепозитории, то сталкиваемся с неудобством долгого запуска Pipeline. При малейшей правке файлов фронтенда у нас запускаются линтеры и тесты для всего проекта, а не только для фронтенда.

Сегодня мы оптимизируем наш Pipeline в Jenkins так, чтобы он запускал проверки только для изменённого кода. Для этого научим его пользоваться командами git diff и docker-compose images для отслеживания изменений кода и софта. При этом рассмотрим нюансы, с которыми можно столкнуться при внедрении такой автоматизации:

  • 00:00:21 Плюсы и минусы монорепозитория
  • 00:05:08 Оптимизация запуска тестов
  • 00:06:41 Отключение React Dev Server
  • 00:09:56 Пропуск шагов по git diff
  • 00:15:42 Запуск git diff в Pipeline
  • 00:18:10 Условия запуска when
  • 00:20:35 Слежение за служебными файлами
  • 00:25:52 Работа с новыми ветками
  • 00:29:35 Защита от форсированного git push
  • 00:34:46 Отслеживание Docker-образов
  • 00:45:42 Обзор результата

Это нам будет полезно в следующих эпизодах, где мы будем делать регистрацию на фронтенде.

Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (18)
Arunas
2021-02-03 17:01

Спасибо.

Ответить
fedot
2021-02-07 12:45

Спасибо за отличный урок! Есть вопрос по оптимизации, например если есть проект в 10к файлов, то при сборке контейнера докер, если один файл изменился, в контейнер будут копироваться все 10к файлов или только один? как у нас сделано сейчас, я малость запутался, не могу найти ответ в коде что-то.

Ответить
Дмитрий Елисеев
2021-02-08 07:28

Да, сейчас одной командой:

COPY ./ ./

копируются все файлы в один слой.

Для оптимизации можно разбить копирование:

COPY ./config ./config
COPY ./src/Frontend ./src/Frontend
COPY ./src/Auth ./src/Auth
...

поместив в начале списка редко меняющиеся директории.

Ответить
fedot
2021-02-08 11:43

Понял, спасибо, тогда там тоже надо получается смастерить что то вроде темы урока и копировать только измененное, тогда все будет быстро конечно.

Ответить
Игорь
2021-02-11 19:32

Парни, проблемы со сборкой дженкинса ни у кого не возникает? Там, насколько я понимаю, в pip добавили зависимость от rust, а в репозиториях alpine нет rust нужной версии, в итоге, если запустить сборку дженкинса, то докер падает с ошибкой:

  error: Rust 1.44.0 does not match extension requirement >=1.45.0

Есть варианты как-то установить в образ rust нужной версии или собрать контейнер без него?

Ответить
Игорь
2021-02-12 20:35

Отвечу сам себе, вдруг кому-нибудь еще пригодится. Решение проблемы - ставить раст не из репозиториев а собирать в контейнере В итоге у меня получился такой Dockerfile для дженкинса:

FROM jenkinsci/blueocean

USER root

RUN apk upgrade \
    && apk update \
    && apk add --no-cache ca-certificates gcc make

ENV RUSTUP_HOME=/usr/local/rustup \
    CARGO_HOME=/usr/local/cargo \
    PATH=/usr/local/cargo/bin:$PATH \
    RUST_VERSION=1.45.1

RUN set -eux; \
    url="https://static.rust-lang.org/rustup/archive/1.22.1/x86_64-unknown-linux-musl/rustup-init"; \
    wget "$url"; \
    echo "cee31c6f72b953c6293fd5d40142c7d61aa85db2a5ea81b3519fe1b492148dc9 *rustup-init" | sha256sum -c -; \
    chmod +x rustup-init; \
    ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION; \
    rm rustup-init; \
    chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \
    rustup --version; \
    cargo --version; \
    rustc --version;

RUN apk add --no-cache py-pip python3-dev libffi-dev openssl-dev libc-dev gettext \
    && pip3 install docker-compose

USER jenkins
Ответить
elmut
2021-02-13 00:57

pip3 install docker-compose долго ставится

apk add --update docker openrc docker-cli && rc-update add docker boot  && usermod -aG docker jenkins
Ответить
Дмитрий Елисеев
2021-02-13 16:01

Можно проще:

FROM jenkinsci/blueocean

USER root

ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
RUN sh -c 'curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y'

RUN apk add --no-cache py-pip python3-dev libffi-dev openssl-dev gcc libc-dev make gettext \
    && pip3 install docker-compose

USER jenkins

А когда обновят версию alpine перейти на rust cargo:

FROM jenkinsci/blueocean

USER root

RUN apk add --no-cache py-pip python3-dev libffi-dev openssl-dev gcc libc-dev rust cargo make gettext \
    && pip3 install docker-compose

USER jenkins
Ответить
Игорь
2021-02-14 14:29

Да, такой вариант намного лучше, спасибо большое.

Ответить
Дмитрий Елисеев
2021-02-13 16:00

Да, неделю у всех так.

Ответить
Руслан
2021-02-19 10:50

Спасибо Дмитрий, примерно когда ждать следующий урок?

Ответить
Дмитрий Елисеев
2021-03-01 08:02

Уже записываю следующие два. Отвлёкся на написание статей на elisdn.ru

Ответить
Руслан
2021-03-03 11:59

Дмитрий, спасибо огромное за статьи и Ваш труд!

Ответить
Максим (@myks92)
2021-05-26 01:38

Здравствуйте, Дмитрий!

Хотел бы уточнить один интересный вопрос касаемо рефакторингa Makefilе...

  1. В данном проекте практически всё делится на небольшие, понятные куски кода и файлы, вводится оптимизация, однако Makefile почему то это не касается... Я знаю, что у него есть возможность подключать другие Makefile, то почему бы для каждого сервиса (api, frontend, cucumber...) не сделать свои Makefile и вызывать их из главноего Makefile в корне. Так же у него есть возможность не запускать уже исполненные команды и запускать процессы в несколько потоков make -j<количество потоков>. Почему рефакторинг не затрагивает этот Makefile? Ведь это было бы удобнее и понятнее.

  2. У Makefile есть стандартные команды all, install, clear, uninstall. Почему не используются эти команды, а придумали свои вроде init? Как раз если разделить файлы на разные отвественности будет логично использовать make install (для api и других сервисов) или просто make. По умолчанию цель all, но можно её заменить на .DEFAULT_GOAL: init, например, как описано тут http://pushorigin.ru/bash/make Спасибо!)

Ответить
Дмитрий Елисеев
2021-06-07 11:34
  1. Можно, но разбивка будет не всегда удобна для работы. Либо придётся каждый раз в консоли через -f указывать используемый в данный момент файл, либо делать прокидывание всех команд из основного Makefile вручную или динамически.

  2. Инициализация проекта у нас производит не только установку, но и остановку с очисткой предыдущего мусора. Остановку проекта мы можем производить как есть по down и с очисткой по down-clear. У нас намного больше действий, поэтому примитивного стандартного списка из all, install, clear и uninstall нам не хватит. И будет непонятно, что именно делает all. Поэтому всегда удобнее придумывать свои более понятные названия команд вместо стандартных.

Ответить
Руслан
2022-02-17 07:33

Дима, добрый день,

сейчас на продакшене мы вызываем установку зависимостей в докер образе через:

RUN composer install --no-dev --prefer-dist --no-progress --no-suggest --optimize-autoloader \
  && rm -rf /root/.composer/cache

а затем в Jenkinsfile на шаге Init снова запускаем composer install (make init-ci -> api-init -> api-composer-install):

docker-compose run --rm api-php-cli composer install

подскажите, это оптимально, или что я упустил?

Спасибо!

Ответить
Дмитрий Елисеев
2022-03-02 16:16

В девелоперском окружении make init нам нужны все пакеты c линтерами и тестами, а для боевой сборки по make build нужны только продакшеновские с флагами --no-dev --optimize-autoloader.

Поэтому у нас две установки, где девелоперская папка vendor игнорируется через .dockerignore, чтобы она не попадала в продакшеновскую сборку.

Ответить
Саид
2022-03-27 17:30

Дим, добавьте пожалуйста отображение уже просмотренных ссылок: a:visited

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Yandex
MailRu
GitHub
Google