Построение Pipeline в Jenkins

Построение CI/CD Pipeline для автоматизации тестирования и деплоя в Jenkins. Сбор артефактов и уведомления по электронной почте.

  • 00:01:05 - Создание Jenkinsfile
  • 00:04:41 - Добавление GitHub-репозитория в Jenkins
  • 00:11:42 - Просмотр multibranch-проекта
  • 00:13:37 - Вывод временных меток в логах
  • 00:16:30 - Валидация Jenkinsfile
  • 00:18:02 - Переменная окружения CI
  • 00:19:39 - Доработка docker-compose pull
  • 00:20:43 - Команды init и down c защитой в post
  • 00:22:33 - Первый и повторный запуск
  • 00:26:01 - Установка git и make на машину-агент
  • 00:27:00 - Сравнение производительности
  • 00:28:25 - Этап valid
  • 00:28:53 - Параллельный запуск линтеров
  • 00:31:36 - Анализаторы и тесты
  • 00:32:44 - Переменная REGISTRY для реестра
  • 00:36:14 - Генерация тегов с номером сборки
  • 00:41:13 - Сборка production образов
  • 00:42:13 - Запуск Smoke и E2E тестов
  • 00:43:08 - Оптимизация числа потоков
  • 00:46:01 - Аутентификация в Docker-реестре и push
  • 00:49:55 - Автодеплой на production-сервер
  • 00:54:46 - Имя пользователя для деплоя
  • 00:55:31 - Отключение интерактивной SSH-проверки
  • 00:56:19 - Генерация SSH-ключа для деплоя
  • 01:04:14 - Подключение через плагин SSH Agent
  • 01:06:58 - Работа со Staging-сервером
  • 01:09:14 - Сохранение артефактов
  • 01:14:38 - Добавление Email-уведомлений
Скрытый контент
Комментарии (49)
Arunas

чудотворный урок, спасибо.

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

Спасибо! Стараемся.

Ответить
fedot

Спасибо, большое тебе Дима, ты конечно мастер. А сколько времени уходит если не секрет, что бы все скрипты заработали? Ведь на поиск правильно работающего в данной конфигурации рецепта, может уйти куча времени, иногда с виду простая вещь может упереться так, что мама не горюй, записал бы может стрим какой отдельно, как что то сложное настраивал, было бы тоже весьма познавательно.

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

С GitHub Actions просидел так три дня. В итоге и запись видео заняла шесть часов, так как каждый прогон Pipeline шёл несколько минут и в случае ошибок после каждого исправления приходилось всё перезапускать.

Ответить
fedot

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

Ответить
Andrey

Дмитрий, спасибо большое за урок! Вопрос, будет ли рассмотрен вариант использоваться докер образа с Git lab или вообще Git lab как инструмента? Там же есть встроенная возможность и репозиторий для docker организовать и ci\cd настраивать...

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

Да, скоро рассмотрим.

Ответить
Yevhenii Lykholai

Огромное спасибо за труд.

Ответить
Merlin

А сколько всего планируется уроков?

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

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

Ответить
Александр

Спасибо!

Ответить
Valentin

Этот урок просто бесценный, спасибо

Ответить
Андрей

А что если надо сделать деплой на две разных машины? Ну т.е. чтобы было 2 копии сайта. Как это сконфигурировать?

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

Для этого вместо Docker Compose мы в следующих эпизодах будем использовать Docker Swarm. И он уже задеплоит проект на все подключенные серверы.

Ответить
Андрей

А что если у нас есть shared данные. Например, изображения загруженные пользователями. Понятное дело, что можно заиметь ftp сервер какой-нибудь и грузить все туда. Но если все таки без сервера, т.е. хранить изображения надо где-то в отдельной папке, то как тогда ее монтировать в контейнер? Причем надо не забывать, что у нас может быть staging (или даже несколько staging).

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

Обычно их помещают на отдельный файловый сервер по S3 или FTP.

А если без него, то просто монтируем папку public/upload через volume. И для тестов отдельной командой вроде:

docker run --rm php-cli copy docker/testing/demo/photos public/upload/photos

заполняем тестовыми данными.

Ответить
Андрей

А почему в Jenkinsfile для make deploy мы явно указываем BUILD_NUMBER=${env.BUILD_NUMBER} make deploy? Ведь остальные переменные по типу HOST мы же не указываем....

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

В принципе да. Если имя переменной совпадает, то можно не присваивать повторно и работать сразу с ${BUILD_NUMBER} без env.

Ответить
Александр

Замечательный урок. Спасибо.

Остался только один вопрос как сделать возможность автоматического отката к прошлой рабочей версии или как сделать возможность хранить на сервере файлы допустим только 4-х или пяти предыдущих деплоев что бы откатить вручную и при этом не забивать дисковое пространство?

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

возможность автоматического отката к прошлой рабочей версии

Например, в Prod объявить подсекцию post { failure { ... } } по аналогии со сбором артефактов и там вызвать команду make auto-rollback, которая выполнит перезапуск из прошлой рабочей папки по симлинку cd site && docker-compose up ...

не забивать дисковое пространство

В папке деплоя у нас хранятся только два файла на ~5 КБ. Тысяча таких папок займёт всего 5 МБ.

Ответить
Александр

Спасибо за ответ. Я немного не верно задал вопрос. У меня есть продакшен на котором после деплоя выполняется еще мануальное тестирование и если я нахажу там критические баги то надо откатить продакшен до предыдущей версии. но т.к. мы не используем теги для деплоя мы не можем просто взять и задеплоить предыдущий релиз. Нужен какой то способ запустить деплой предыдущего смерженого пулл реквест.

Так же под файлами деплоя я имелл ввиду не файлы логов а файлы проекта я не использую билд образов и не пушу эти образы в реджестри а просто пулю ветку мастер на сервере и перезапускаю докер композ и была идея просто каждый релиз делать в отдельную папку с номером билда но остается проблема с местом на диске т.к. весь проект знимает прилично места и хотелось бы как то удалять все папки релизов кроме последних 4-х

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

Тогда можно поробовать деплоить через Deployer или Capistrano. Они как раз будут оставлять только нужное число папок.

Ответить
Анатолий

При сборке не находится sshagent java.lang.NoSuchMethodError: No such DSL method 'sshagent' found among steps Потом все таки досмотрел видео, когда установил модуль сам)

Ответить
Дмитрий

Дима помоги, у меня проблема: в момент docker-build в production/Dockerfile есть строчка COPY out/buildServer/stats.json app/out/buildServer/stats.json

файл stats.json - это результат работы stats-webpack-plugin, и он обязательно появляется, но не успевает появиться до момента COPY

как дождаться либо здесь, внутри Dockerfile, или в Makefile?

Ответить
Дмитрий

первое что на ум приходит

wait-stats:
	sh -c "until [ -f ./out/buildServer/stats.json ] ; do sleep 1 ; done"

в Makefile использовать перед билдом контейнеров

Ответить
Дмитрий

но интересно есть ли подобное решение внутри Dockerfile?

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

Внутри нет. Сборка производится в копии нашей папки, отправленной демону. Там файл не появится.

Ответить
Николай

Дмитрий, добрый день! Во время деплоя jenkins при сборке образа на основе jenkinsci/blueocean не устанавливается docker-compose. Ошибка во время компиляции "Could not build wheels for pynacl which use PEP 517 and cannot be installed directly". Не подскажите, в чем может быть проблема?

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

Увы, но не подскажу.

Ответить
Николай

И еще одна проблема (уже после установки docker-compose через curl). Во время запуска пайплайна на стадии "Init" возникает ошибка:

console output

  • make init
  • docker-compose down -v --remove-orphans
  • make: docker-compose: Operation not permitted
  • make: *** [Makefile:46: docker-down-clear] Error 127

Не подскажите, в чем может быть проблема?

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

Возможно, что текущему пользователю и файлу docker-compose не проставлена группа docker.

Ответить
Николай

Проблема была с образом jenkinsci/blueocean. Попробовал более ранний образ. Команда make перестала выдавать ошибку только со сборкой на основе jenkinsci/blueocean:1.24.7. А до этого ошибка была и из-под пользователя jenkins (который по умолчанию) и из-под root.

Ответить
Ярослав

Я также попробовал более старый образ, но на локалке контейнер jenkins у меня падает с ошибкой:

java.io.FileNotFoundException: /var/jenkins_home/war/WEB-INF/lib/cli-2.289.1.jar (Permission denied)

У тебя сразу заработало или еще что-то надо было проставить?

Ответить
Николай

У меня ошибка была именно на проде, на локалке все было нормально. Дополнительно ничего не делал, только образ сменил на 1.24.7. Возможно, ошибка из-за

volumes:
 - jenkins-data:/var/jenkins_home

Можно найти нужный вольюм (docker volume ls) и удалить (docker volume rm volume_name), чтобы он пересоздался при рестарте docker-compose. Но тогда слетят настройки jenkins (доступ к репозиторию, пароли ключи и т.д.), будет полностью переустановленный jenkins. Возможно, потребуется пересобрать сам образ на основе jenkinsci/blueocean

Ответить
Ярослав

Спасибо за ответ. Настройки не проблема восстановить, так как я уже устанавливал и настраивал его на разные сервера. Рука и голова набиты:))

Ответить
slo_nik

Добрый вечер, Дмитрий.

При выполнении шага "make init" возникают такие ошибки:

ERROR: for mailer  Get "registry-1.docker.io/v2/": net/http: TLS handshake timeout
error pulling image configuration: Get "registry-1.docker.io/v2/library/node/blobs/sha256:18f4bc97573275625b5337c93ac43f9b920a09fb4cb030e25a0c0ff42dd6b3dc": net/http: TLS handshake timeout

Если выполнить curl запрос к этим адресам, или перейти в браузере, то в ответ получаю следующее сообщение:

{"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"library/node","Action":"pull"}]}]}

Как победить данную проблему?

Ответить
slo_nik

При выполнении шага "make init" возникают такие ошибки:

Добавил для jenkins playbook docker-login

Предыдущая ошибка ушла, но появилась новая, ругается на docker.dind

HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)
Ответить
slo_nik

В обшем ничего не получилось)))

Рекомендации из интернета не помогли, пробовал увеличить лимит по выполнению сборки через COMPOSE_HTTP_TIMEOUT: 120 и DOCKER_CLIENT_TIMEOUT: 120, все сборки завершались ошибкой

HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)

Взял ещё один свой проект, там поменьше сервисов собирается в docker-compose-prod.yml

Первая сборка прошла успешно, а вот вторая вывалилась всё с теме же ошибками:

ERROR: for support_dev_support-php-fpm_1  HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)
ERROR: for support_dev_support-php-cli_1  HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)
ERROR: for support-php-fpm  HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)
ERROR: for support-php-cli  HTTPSConnectionPool(host='docker', port=2376): Read timed out. (read timeout=60)
An HTTP request took too long to complete. Retry with --verbose to obtain debug information.
If you encounter this issue regularly because of slow network conditions, consider setting COMPOSE_HTTP_TIMEOUT to a higher value (current value: 60).

Всё-таки, из-за чего это зависит и как это победить?

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

Может сервисы отваливаются из-за недостатка памяти. Увеличьте размер виртуальной машины.

Ответить
slo_nik

Думал об этом, но проблема оказалась совершенно в другом.

Эти ошибки возникали при попытке dind-ом создать контейнеры. Но в самом коде были проблемы, на уровне php, поэтому dind не мог создать контейнер и не отвечал jenkins-у.

Плохо, что не очень информативные ошибки в логах jenkins. Пытался в лохаг dind смотреть, тоже, ничего не находил.

Например как ошибки выше, еле докумекал и то, пока не увидел в инете сообщение, что не только недостаток памяти или плохая скорость инета может влиять.

Ответить
slo_nik

ERROR: for mailer Get "registry-1.docker.io/v2/": net/http: TLS handshake timeout

Хотя вот эта ошибка выскочила тогда, когда с двух веток jenkins пытался одновременно сделать сборку. Тут, я думаю, уже мощности не хватило.

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

Одновременно на одной виртуалке лучше не запускать. Выставить максимальное число 1.

Ответить
slo_nik

Только что проверил, моя ошибка, было выставлено "2". Переустанавливал виртуалку и забыл изменить этот параметр.

Ответить
slo_nik

Добрый день.

Если выставить в настройка jenkins-a число 1 для обрабатываемых задач и при этом сделать подряд два commit-a, то всё равно запускается две задачи.

Можно это как-то победить?

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

Если стоит 1, то вторая задача будет ждать в очереди.

Ответить
slo_nik

Опять же, возвращаясь к слабым виртуальным машинам.

Можно ли как-то освобождать swap по завершению сборки, то есть, дописать в Jenkinsfile соответствующую команду? И будет ли это эфективно для слабых машин?

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

В этом нет смысла.

Ответить
Андрей

А у меня такая проблема. Jenkins сканирует github репозиторий раз в минуту и смотрит есть ли изменения. Но бывает, что он запускает пайплан даже если изменений никаких не было. И происходит это не систематизировано, может днем запустить, может ночью. Может неделю все тихо быть, а потом бац - билд пошел. Не сталкивались с таким?

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

Сталкивался. Но проблемы в этом не вижу.

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

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

Google
GitHub
Yandex
MailRu