Оптимизация 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

Спасибо.

Ответить
fedot

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

Ответить
Дмитрий Елисеев

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

COPY ./ ./

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

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

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

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

Ответить
fedot

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

Ответить
Игорь

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

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

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

Ответить
Игорь

Отвечу сам себе, вдруг кому-нибудь еще пригодится. Решение проблемы - ставить раст не из репозиториев а собирать в контейнере В итоге у меня получился такой 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

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

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

Можно проще:

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
Ответить
Игорь

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

Ответить
Дмитрий Елисеев

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

Ответить
Руслан

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

Ответить
Максим (@myks92)

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

Хотел бы уточнить один интересный вопрос касаемо рефакторинг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 Спасибо!)

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

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

Ответить
Руслан

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

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

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

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

Спасибо!

Ответить
Дмитрий Елисеев

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

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

Ответить
Саид

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

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

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

Yandex
MailRu
GitHub
Google