Настройка непрерывной интеграции в Concourse CI в Ubuntu 16.04

Concourse CI – это современная система непрерывной интеграции, которая автоматизирует конвейеры тестирования. В предыдущих руководствах показано, как установить Concourse CI и защитить интерфейс системы с помощью доверенного сертификата Let’s Encrypt.

Данный мануал покажет, как с помощью Concourse автоматически запускать тестирование кода после добавления новых коммитов. Для примера в мануале используется веб-фреймворк Hapi.js.

Чтобы обеспечить синхронизацию процедур сборки и тестирования с кодом, с которым они связаны, нужно добавить определения CI в репозиторий приложения. Затем нужно использовать инструмент командной строки fly для загрузки конвейера в Concourse. В конце нужно выгрузить изменения в репозиторий, что запустит новый тест в рабочем процессе CI.

Требования

Для работы понадобится сервер Ubuntu 16.04, 1 Гб RAM минимум.

Выполните следующие руководства, чтобы настроить пользователя, установить и настроить Concourse, установить Nginx, получить сертификат TLS/SSL и настроить обратный прокси для веб-интерфейса Concourse. Для пполучения сертификата понадобится доменное имя, указывающее на сервер Concourse.

В данном мануале основная работа сосредоточена на локальной машине. Потому на нее нужно установить несколько дополнительных инструментов, в частности текстовый редактор (в зависимости от системы это может быть nano, vim, TextEdit, Sublime Text, Atom или Notepad). Также нужно установить Git.

Читайте также: Установка Git: основы разработки проектов с открытым исходным кодом

Установка fly на локальную машину

Вместе с Concourse на сервер устанавливается инструмент fly, который управляет Concourse из командной строки. Однако для ежедневного использования удобнее установить копию бинарного файла fly в локальной системе, где будут доступны обычные средства разработки и исходный код.

Чтобы получить локальную копию fly, соответствующую версии сервера, посетите экземпляр Concourse в веб-браузере:

https://your_concourse_url

Если вы вышли из системы или у вас нет настроенного конвейера, в центре окна будут отображаться ссылки для загрузки fly для разных платформ.

Если вы вошли в систему Concourse и настроили конвейер, ссылки для загрузки fly будут доступны в правом нижнем углу экрана.

Нажмите на значок операционной системы локального компьютера, чтобы загрузить бинарный файл fly.

Затем следуйте инструкциям в браузере, чтобы настроить fly в локальной системе.

Настройка fly в Linux и macOS

Если локальный компьютер использует дистрибутив Linux или macOS, следуйте этим инструкциям после загрузки соответствующего двоичного файла.

Сначала сделайте загруженный двоичный файл исполняемым. Предположим, что вы загрузили файл в каталог ~/Downloads (при необходимости укажите другое местоположение загрузки).

chmod +x ~/Downloads/fly

Затем укажите путь к файлу в переменной PATH:

sudo install ~/Downloads/fly /usr/local/bin

Убедитесь, что исполняемый файл работает:

fly --version
3.3.1

Если команда вернула версию пакета, все работает должным образом.

Настройка fly в Windows

Если локальная машина использует Windows, нажмите кнопку Windows на клавиатуре, введите powershell и нажмите Enter.

В появившемся окне создайте папку bin.

mkdir bin

Переместите файл fly.exe из папки Downloads в bin.

mv Downloads/fly.exe bin

Проверьте, доступен ли профиль PowerShell:

Test-Path $profile
Если команда вернула True, у вас есть профиль. Если команда вернула False, создайте его:
New-Item -path $profile -type file -force
Directory: C:\User\8host\Documents\WindowsPowerShell
Mode              LastWriteTime       Length Name
----              -------------       ------ ----
-a----       7/9/2017   5:46 PM            0 Microsoft.PowerShell_profile.ps1

Отредактируйте профиль в редакторе:

notepad.exe $profile

Окно редактора будет пустым, если профиль нужно создать. Добавьте:

$env:path += ";C:\Users\8host\bin"

Затем установите политику выполнения RemoteSigned для текущего пользователя, чтобы PowerShell мог прочитать профиль:

Set-ExecutionPolicy -scope CurrentUser RemoteSigned

Затем введите:

. $profile

Теперь вы можете вызвать исполняемый файл fly.exe из любого места. Проверьте это, запросив версию пакета:

fly.exe --version
3.3.1

Примечание: Если вы используете Windows, замените все команды fly командой fly.exe.

Аутентификация на сервере Concourse

После установки fly пройдите аутентификацию на удаленном сервере Concourse, чтобы иметь возможность локально управлять средой CI. Один бинарный файл fly может управлять несколькими серверами Concourse, поэтому команда использует цели (targets) в качестве метки, чтобы определить сервер, которому нужно отправлять команды.

В руководстве используется цель main, но вы можете назвать цель иначе. Введите домен сервера Concourse с протоколом https:// после опции –c.

fly -t main login -c https://example.com

Будет предложено ввести имя пользователя и пароль, которые вы настроили в файле /etc/concourse/web_environment на сервере Concourse:

logging in to team 'main'
username: 8host
password:
target saved

После аутентификации инструмент fly создаст конфигурационный файл ~/.flyrc, чтобы сохранить учетные данные для будущих команд.

Примечание: Если позднее вы обновите версию Concourse, вы можете установить соответствующую версию команды fly, набрав:

fly -t main sync

Эта команда обновит бинарный файл fly.

Форк и клонирование репозитория

Теперь, когда у вас установлена команда fly, можно приступать к созданию репозитория, который будет использован для демонстрации работы конвейеров.

В веб-браузере откройте приложение hello hapi на GitHub, которое можно использовать в качестве примера. Это приложение является простой программой hello world с несколькими модульными и интеграционными тестами, написанными с помощью Hapi.js, веб-фреймворка Node.js.

Примечание: Поскольку это приложение используется как пример для демонстрации множества систем непрерывной интеграции, вы можете заметить некоторые файлы, используемые для определения конвейеров в других системах НИ. В руководстве показано, как создать конвейер  для Concourse в собственном форке репозитория.

Чтобы создать форк репозитория, войдите в GitHub и откройте репозиторий проекта. Нажмите Fork, чтобы скопировать репозиторий в ваш аккаунт.

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

В терминале на локальной машине откройте домашний каталог:

cd $HOME

Клонируйте репозиторий на локальный компьютер с помощью команды:

git clone git@github.com:your_github_user/hello_hapi

В домашнем каталоге появится новый каталог, hello_hapi. Откройте его:

cd hello_hapi

Конвейер непрерывной интеграции для проекта будет определен внутри этого репозитория. Прежде чем вносить какие-либо изменения, рекомендуется создать и переключиться на новую ветку в Git, чтобы изолировать изменения:

git checkout -b pipeline
Switched to a new branch 'pipeline'

Настройка процесса непрерывной интеграции приложения

Конвейер и все связанные с ним файлы определяются в самом репозитории проекта. Это помогает гарантировать синхронизацию процессов интеграции с проверяемым кодом.

Набор тестов уже определен в каталоге под названием test. Он включает в себя один модульный тест и два базовых интеграционных теста. Команда для запуска тестов определяется в файле package.json объекта scripts, который называется test. В среде с установленными инструментами npm и Node.js вы можете запускать тесты с помощью npm test (после установки зависимостей проекта с помощью команды npm install). Это процедуры, которые нужно будет реплицировать в конвейере.

Для начала создайте в репозитории каталог ci, в котором будут размещены активы постоянной интеграции проекта. Также нужно создать два подкаталога, ci/tasks и ci/scripts, для хранения отдельных определений задач, которые ссылаются на конвейер и сценарии.

Создайте структуру каталогов:

mkdir -p ci/{tasks,scripts}

Определение конвейера

Создайте файл под названием pipe.yml в каталоге ci и откройте его с помощью текстового редактора (в этом руководстве используется nano). Как видно по расширению, файлы Concourse определяются в формате сериализации данных YAML:

nano ci/pipeline.yml

Определение типа ресурса кэша NPM

Вставьте в файл:

---
resource_types:
- name: npm-cache
type: docker-image
source:
repository: ymedlop/npm-cache-resource
tag: latest

Чтобы отделить процессы непрерывной интеграции от данных, которые проходят через систему, Concourse выгружает всю информацию о состоянии в так называемые ресурсы. Ресурсы – это внешние источники данных, которые Concourse может использовать для сбора или передачи информации. Таким все данные поступают в систему непрерывной интеграции и распределяются между заданиями. Concourse не предоставляет никакого механизма для хранения или передачи состояния между задачами.

Заголовок resource_types позволяет определять новые виды ресурсов, которые можно использовать в своем конвейере: уведомления по электронной почте, интеграция с Twitter или RSS-каналы. Новый тип ресурса подсказывает, как использовать npm-cache-resource, образ Docker, который позволяет Concourse устанавливать зависимости проекта Node.js.

Определение ресурсов Repository и Caching

Добавьте определения ресурсов в файл:

. . .
resources:
- name: hello_hapi
type: git
source: &repo-source
uri: https://github.com/your_github_user/hello_hapi
branch: master
- name: dependency-cache
type: npm-cache
source:
<<: *repo-source
paths:
- package.json

В этом разделе определяются два ресурса, необходимые для выполнения задач Concourse. Concourse использует определения ресурсов для отслеживания изменений и для понимания того, как загрузить ресурс, когда он нужен задачам. По умолчанию Concourse проверяет каждый ресурс на обновления один раз в минуту. Задания, требующие ресурсов с опцией trigger, автоматически запускают новую сборку, когда доступна новая версия кода.

Первый ресурс представляет собой форк репозитория hello_hapi на GitHub. Строка source содержит анкер YAML repo-source, который помечает элемент для ссылки в будущем. Это позволяет позже включать содержимое элемента (определения uri и branch) в другие разделы документа.

Второй ресурс, dependency-cache, использует тип ресурса npm-cache, который был определен ранее. В спецификации source этого ресурса используется строка <<: *repo-source для ссылки и расширения элементов, на которые указывает анкер &repo-source. Это вставляет параметры uri и branch из ресурса репозитория приложения. Дополнительный элемент paths указывает на файл package.json, где определены зависимости проекта.

Определение задач сбора зависимостей и тестирования

Добавьте в файл:

. . .
jobs:
- name: Install dependencies
plan:
- get: hello_hapi
trigger: true
- get: dependency-cache
- name: Run tests
plan:
- get: hello_hapi
trigger: true
passed: [Install dependencies]
- get: dependency-cache
passed: [Install dependencies]
- task: run the test suite
file: hello_hapi/ci/tasks/run_tests.yml

В этом разделе определяются две задачи, каждая из которых состоит из имени и плана. Каждый из планов, в свою очередь, содержит элементы get и task. Элементы task определяют, как выполнить действие, а элементы get указывают зависимости ресурса задачи.

Первый оператор get в первой задаче требует ресурс hello_hapi и указывает параметр trigger: true. Благодаря этому Concourse автоматически извлекает репозиторий и начинает новую сборку этой задачи каждый раз, когда в репозитории hello_hapi обнаруживается новый коммит.

Второй оператор get в первом задании (get: dependency-cache) требует определяемого ресурса, который загружает и кэширует зависимости проекта Node.js. Этот оператор оценивает требования, найденные в файле package.json, и загружает их. Если эта задача не получает никаких процессов, она не выполняет больше ничего, но загруженные зависимости будут доступны для последующих заданий.

Примечание: В этом конкретном примере есть только одна дополнительная задача, поэтому преимущества кэширования зависимостей Node.js как самостоятельного шага не реализованы полностью. Однако почти все задачи Node.js требуют зависимостей проекта, поэтому, если у вас есть отдельные задачи, которые потенциально могут быть выполнены параллельно, преимущества кэша зависимостей станут более ощутимыми.

Вторая задача (name: Run tests) начинается с объявления тех же зависимостей с одной заметной разницей. Ограничение passed приводит к тому, что инструкции get соответствуют только ресурсам, которые успешно прошли предыдущие шаги в конвейере. Так образуются зависимости между заданиями для объединения процессов конвейера.

После выражения get вызывается задача run the test suite. Вместо того, чтобы определять шаги для завершения конвейера, Concourse будет загружать определение из файла в репозиторий. Мы создадим этот файл позже.

В результате файл ci/pipeline.yml выглядит так:

---
resource_types:
- name: npm-cache
type: docker-image
source:
repository: ymedlop/npm-cache-resource
tag: latest
resources:
- name: hello_hapi
type: git
source: &repo-source
uri: https://github.com/your_github_user/hello_hapi
branch: master
- name: dependency-cache
type: npm-cache
source:
<<: *repo-source
paths:
- package.json
jobs:
- name: Install dependencies
plan:
- get: hello_hapi
trigger: true
- get: dependency-cache
- name: Run tests
plan:
- get: hello_hapi
trigger: true
passed: [Install dependencies]
- get: dependency-cache
passed: [Install dependencies]
- task: run the test suite
file: hello_hapi/ci/tasks/run_tests.yml

Сохраните и закройте файл.

Определение тестовой задачи

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

Откройте новый файл run_tests.yml:

nano ci/tasks/run_tests.yml

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

Вставьте в файл:

---
platform: linux
image_resource:
type: docker-image
source:
repository: node
tag: latest
inputs:
- name: hello_hapi
- name: dependency-cache
run:
path: hello_hapi/ci/scripts/run_tests.sh

В приведенной выше конфигурации указано, что для этой задачи требуется воркер Linux. Сам сервер Concourse может удовлетворить это требование без дополнительной настройки.

Затем нужно указать образ, который будет использоваться воркером для выполнения задачи. Вы можете создавать и использовать свои собственные образы, но на практике почти всегда используется стандартный образ Docker. Поскольку репозиторий является приложением Node.js, выберите последний образ node для запуска тестов, поскольку в нем уже есть соответствующий набор инструментов.

Задачи Concourse могут указывать входные и выходные данные, чтобы определять ресурсы и артефакты. Входные данные соответствуют ресурсам, загруженным ранее на уровне «job». Содержимое этих ресурсов становится доступным для среды задач как каталог верхнего уровня, которым можно управлять во время выполнения задачи. Репозиторий приложений будет доступен в каталоге hello_hapi, а зависимости Node.js будут находиться в каталоге dependency-cache.

В элементе run указан путь к выполняемой команде.

Каждая задача может запускать только одну команду с аргументами, поэтому чаще всего задачи направлены на файл сценария.

В этом случае указывается сценарий в каталоге ввода hello_hapi, расположенном в hello_hapi/ci/scripts/run_tests.sh.

Сохраните и закройте файл.

Определение тестового сценария

Теперь создайте этот сценарий. Откройте файл ci/scripts/run_tests.sh.

nano ci/scripts/run_tests.sh

Этот сценарий управляет входными данными среды тестирования и перемещает элементы в правильное местонахождение. Затем сценарий запускает тестовый набор, определенный в репозитории с помощью npm test.

Вставьте в файл:

#!/usr/bin/env bash
set -e -u -x
mv dependency-cache/node_modules hello_hapi
cd hello_hapi && npm test

Первая строка говорит, что сценарий должен выполняться интерпретатором bash контейнера Docker. Опции set изменяют поведение оболочки по умолчанию, чтобы ошибки или неустановленные переменные остановили выполнение сценария и распечатывали каждую команду по мере их выполнения. Это поможет сделать сценарий более безопасным и простым в отладке.

Первая команда перемещает кэшированные зависимости, расположенные в каталоге node_modules, из каталога dependency-cache в каталог hello_hapi. Помните, что оба этих каталога доступны, потому что они указаны как входные данные в определении задачи. Это новое место, где npm будет искать загруженные зависимости.

Затем перейдите в репозиторий приложения и запустите npm test, чтобы начать тестирование.

Сохраните и закройте файл.

Сделайте новый сценарий исполняемым:

chmod +x ci/scripts/run_tests.sh

Настройка конвейера Concourse

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

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

Чтобы настроить новый конвейер, определите сервер Concourse как цель команды fly с помощью set-pipeline. Нужно передать имя нового конвейера через опцию -p и файл конфигурации конвейера с помощью параметра -c:

fly -t main set-pipeline -p hello_hapi -c ci/pipeline.yml

Будет предложено подтвердить конфигурацию. Введите y и нажмите Enter:

. . .
apply configuration? [yN]: y
pipeline created!
you can view your pipeline here: https://example.com/teams/main/pipelines/hello_hapi
the pipeline is currently paused. to unpause, either:
- run the unpause-pipeline command
- click play next to the pipeline in the web ui

Согласно выводу, конвейер был создан, но приостановлен. Снова запустить его можно с помощью fly или интерфейса. Используйте для этого интерфейс.

В веб-браузере зайдите на сервер Concourse и войдите в систему.

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

Задания, вызванные изменениями ресурсов, связаны сплошными линиями, а ресурсы, не связанные с запуском, — пунктиром. Ресурсы, исходящие из заданий, указывают на то, что было установлено ограничение passed .

Синий заголовок указывает, что конвейер в настоящий момент приостановлен. Нажмите значок меню (три горизонтальных линии) в верхнем левом углу, чтобы открыть меню. Вы должны увидеть запись конвейера (попробуйте выйти из системы и войти снова, если конвейер не отображается). Нажмите синий значок play рядом с конвейером, чтобы запустить его.

Конвейер возобновит работу.

В самом начале различные ресурсы и задачи могут стать оранжевыми, что указывает на наличие ошибок. Это происходит из-за того, что загружены не все образы Docker, а ветка pipeline еще не объединена с основной веткой репозитория.

Создание коммитов

Теперь процесс непрерывной интеграции определен, и его можно передать в репозиторий git и добавить его в Concourse.

Добавьте каталог ci:

git add ci

Проверьте файлы, для которых нужно создать коммиты, проверив статус:

git status
On branch pipeline
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file:   ci/pipeline.yml
new file:   ci/scripts/run_tests.sh
new file:   ci/tasks/run_tests.yml

Отправьте коммит:

git commit -m 'Add Concourse pipeline'

Изменения теперь переданы нашей ветке pipeline. Ее можно объединить с веткой master:

git checkout master
git merge pipeline

Выгрузите ветку master на GitHub:

git push origin master

Коммит запустит новую сборку в течение шестидесяти секунд, и у Concourse будет доступ к задачам и сценариям конвейера.

Просмотр новой сборки

Вернитесь в интерфейс Concourse, чтобы просмотреть прогресс новой сборки.

Желтый контур указывает, что работа выполняется в данный момент. Чтобы отслеживать прогресс и увидеть текущий вывод, нажмите Run tests. Как только работа будет завершена, вы получите полный вывод, и задача должна стать зеленой.

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

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

Tags: , , , ,