Статья Travis как система непрерывной интеграции и доставки

mrOkey

mrOkey

Red Team
14.11.2017
609
707
Доброго времени суток, codeby. Не так давно в моем городе “отгремел” локальный хакатон в одном из универов и мне хотелось бы поделиться одним из полезнейших навыков для комфортного участия в таких мероприятиях - настройкой инфраструктуры для непрерывной доставки и развертывании.
Итак формат хакатона следующий: за отведенное время (26 часов) участникам (командам) предлагается решить одну из задач (головных болей) бизнеса (читай заказчика). Разумеется чем более готовый продукт, тем более выше шансы на успех. При таких данных, хочется максимально минимизировать затраты на прогон всех тестов и время для развертывания приложения. Хочется заняться более интересными и трудозатратными вещами: архитектурой, кодингом, анализом проблемы, поиском решения и так далее.

Статья заточена на стек .Net(Core) и React. База данных не делилась на продуктовую и тестовую (вместо этого изначально предполагалось запускать её в контейнере, но от этого решения принято было отказаться в процессе разработки, за избыточностью).

В качестве системы CI\CD был выбран Travis, за счёт простоты настройки и того факта что предоставляет бесплатно свои услуги для open source проектов, приложение разворачивалось на обычной VPS системе под debian, арендованной на (не буду рекламить, хотя хостер весьма достойный и известный местной аудитории). Небольшое замечание, в статье не рассмотрена защита самого сервера, nginx конфигураций, предполагается, что %username%, успешно может загуглить это. Мне не хотелось писать дополнительное приложение ради этой статьи - поэтому это будет просто сочетания стандартного create-react-app на фронте и стартовое приложения asp.netcore на беке. Приступим.

Репозиторий
Как и большинство CI\CD систем, Travis работает с github репозиториями (вообще не только с ними, но я люблю github) эта прелесть основана на github хуках (на случай если кто захочет написать свою ci\cd систему). Надеюсь с созданием репозитория могут справиться абсолютно все читатели данной статьи (если это не про тебя, то дальше читать не стоит).
Я создал два репозитория под статью:
  • один для бекэнда
  • один для фронтенда
Фронтенд
Начнём с фронтенд приложения. Про то как сделать настройку для react и typescript я уже писал, можно почитать в моей подписи, сейчас же применим супер способ от facebook - create-react-app.

На рабочей машинке создаём директорию, клонируем созданный репозиторий для фронтенда.

Travis как система непрерывной интеграции и доставки


Далее выполняем команду для создания react приложения.

Travis как система непрерывной интеграции и доставки


Ждём пока yarn установит все зависимости, по окончании в случае успеха получим следующее сообщение

Travis как система непрерывной интеграции и доставки


Удалим созданый create-react-app README.md файл за ненадобностью. Добавим созданный файл .gitignore, а затем всё остальное в репозиторий.
Проверим что приложение работает - выполнив команду yarn start. В результате откроется браузер по адресу localhost:3000 и мы увидим такое вот

Travis как система непрерывной интеграции и доставки


Отлично, теперь переходим к настройки Travis. Вся настройка сводится к созданию файла .travis.yml в корне репозитория, давайте воспользуемся прекрасным редактором vscode и откроем папку репозитория и создадим файл.

Travis как система непрерывной интеграции и доставки


Добавим его в индекс, закоммитаем, запушим и переключимся на настройку удаленной машины. Цепляемся по ssh…

Nginx
Замечательный легковесный веб-сервер. Юзается для всего. Прост и податлив в настройке. Настройка сводится к настройке файла nginx.config плюс минус разграничение по правам для системы.

Travis как система непрерывной интеграции и доставки


вот так в данном случае выглядит конфигурация. Этот файл мы помещаем по пути

Код:
/etc/nginx/sites-available/articleapp.ru.conf
Саму статику размещаем там где удобно не забывая поправить root в конфиге, например сюда: /home/example/www/articleapp.ru
далее делаем линкуем его с sites-enabled

Код:
ln -s /etc/nginx/sites-available/articleapp.ru.conf /etc/nginx/sites-enabled/articleapp.ru.conf
и перезапускаем nginx. Ах да, если есть домен, лучше соблюдать доменные наименования.
Ну вообщем всё просто как и обещал, проверим что всё это работает. создав html заглушку c its works.

Travis как система непрерывной интеграции и доставки


На этом с настройкой линукс машины закончили (тема с тем что у nginx свой пользователь должен быть под каждый сайт и и т.д. опущена)

Настройка Travis для Фронтенда
Переходим к настройки CI Travis, подошли к самому интересному. Итак, прежде всего нужно зайти на travis-ci.org под своим гитхаб аккаунтом.
Далее Travis предложит выбрать репозиторий

Travis как система непрерывной интеграции и доставки


Я выбираю CIfrontend - двигая свитч напротив репозитория:

Travis как система непрерывной интеграции и доставки


После чего по ссылке для меня становится доступным дашборд с инфой по репозиторию, однако он еще пуст, так что давайте изменим это. Переходим к написанию travis.yml файла.

Я хочу организовать следующий процесс:
  1. Устанавливаем зависимости
  2. Запуск тестов. Если тесты прошли успешно переходим к шагу два, если нет - останавливаем цикл.
  3. Запускаем билд. Если билд успешен, переходим к деплою
  4. Запускаем деплой, если всё прошло хорошо переходим к оповещению

Итак, пошли по порядку.
Первый шаг реализуется строкой где мы указываем Travis какой язык используем (подробнее тут )

Travis как система непрерывной интеграции и доставки


тут мы также указываем версию node. Почему мы собираем на node? Для сборки react приложений нужен webpack, а ему node - всё логично. Неплохо было бы кэшировать модули которые установит yarn, так что давайте реализуем эту возможность добавив папку node_modules в кэш:

Travis как система непрерывной интеграции и доставки


Самое простое выполнено, дальше у нас идет секция скрипт, где мы уже можем управлять своим пайплайном.

Travis как система непрерывной интеграции и доставки


Помните да? Сначала тесты, потом билд. А пока мне бы хотелось подробнее рассказать про строки 9 и “--coverage && codecov”. Как многие наверное догадались - это метрика покрытия кода, существует проект codecov который собирает статистику по вашему коду вернее по тому как ваши тесты покрывают ваш код. Разумеется чем выше покрытие, тем лучше, тем больше достоверности что ваше приложение работает так как вы того ожидаете. Так вот на строке 9 мы устанавливаем раннер для проверки покрытия а затем запускаем тестирование (в данном случае jest) чтобы убедиться, что у нас всё хорошо. Я вернусь к покрытию, когда буду рассказывать о гитхаб бейджиках. Пока давайте остановится и закоммитаем travis-файл в репозиторий, мне не терпиться показать вам что случилось.
Итак оно работает

Travis как система непрерывной интеграции и доставки


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

Travis как система непрерывной интеграции и доставки


А значит мы можем гордо забрать динамичный бейдж для нашего Readme.md - для этого составим ссылку вот такого вида (markdown)

Код:
[![Build Status](https://travis-ci.org/enterDevelop/CIfrontend.svg?branch=master)](https://travis-ci.org/enterDevelop/CIfrontend)
выглядит теперь у нас readme будет так

Travis как система непрерывной интеграции и доставки


Закоммитаем, запушем, погладим себя по голове - мы молодцы, мы заслужили пойдём намутим кофе.
Вернемся к разговору о покрытии кода тестами. Так как мы поставили пакет codecov мы можем получить ещё один бейджик с информацией о покрытии. Для этого нам нужно отредактировать вот эту вот ссылку

Код:
[![Codecov Coverage](https://img.shields.io/codecov/c/github/enterDevelop/CIfrontend/master.svg?style=flat-square)](https://codecov.io/gh/enterDevelop/CIfrontend/)
тут нужно заменить enterDevelop/CIfrontend на путь до вашего репозитория и мы получим вот такую вот картинку

Travis как система непрерывной интеграции и доставки


Теперь переходим к самой интересной на мой взгляд части - автодеплою.

Travis CD
Travis предоставляет множество способов деплоя из коробки в различные облака, хостинги и тд. Мы же пойдём путём джедаев, попутно сэкономив на облаке. Travis поддерживает деплой как как набор команд оболочки, воспользуемся этой фичей и настроим деплой по ssh. План такой:
  1. Расшарить ключ для автоконнекта тревиса к серверу
  2. Скопировать файлы
Звучит просто, но не будем столь наивны, так как, хранить в публичном репозитории ssh ключ к серверу сродни полному идиотизму, однако есть довольно действенный способ избежать этого. Мы можем хранить закриптованный ключ, для этого нам придётся воспользоваться утилитой Travis для командной строки. Установим её на linux систему (существует известная проблема если криптовать ключ с windows-тачки travis - поднимая билд на linux-тачке не сможет его расшифровать, чёрт знает почему, но об этом ребяткам не раз писали, однако на момент выхода статьи - ничего не разрешилось. Я криптую ключи на кали-виртуалке и всё прекрасно работает).
Так вот первое что нужно сделать сгенерить ключи для ssh.
Используем для этого команду

Код:
ssh-keygen -t rsa -b 4096 -C 'CD Fronted key' -f ./deployf_rsa
Далее криптуем всё это дело командой

Код:
travis encrypt-file deployf_rsa --add
Копируем публичный ключ на сервер

Код:
ssh-copy-id -p server_port -i deployf_rsa.pub login@server_ip
удаляем файлы ключи из директории

Код:
rm -f deployf_rsa deployf_rsa.pub
добавляем в репозиторий зашифрованный ключ для тревис

Код:
git add . && git commit -m ‘added ssh encrypted key’
В случае успеха в Travis кликаем на More options, выбираем Settings проматываем до секции “Environment Variables” и видим примерно такую картину:

Travis как система непрерывной интеграции и доставки


Travis создал себе ключи для расшифровки, а так же сам добавил расшифровку в файл .travis.yml:

Travis как система непрерывной интеграции и доставки


Создадим еще несколько переменных, с помощью формы ниже , для большей секьюрности. А именно server_port, server_ip, server_user так мы сможем инкапсулировать пользователя ssh (разумно будет для тревиса создать отдельного юзера). В финале должно получиться что-то такое

Travis как система непрерывной интеграции и доставки


Переходим к конфигурированию в файле travis.yml. Добавим секцию before_deploy которая отвечает за действия (очевидно) происходящие перед деплоем.

Travis как система непрерывной интеграции и доставки


на 16ой строке мы проверяем наличие ssh-agent и тот факт что он запущен (на всякий случай). Далее разрешаем доступ ко всем хостам (отключив проверку stricthostkey) тревис каждый раз поднимает новую машинку для билда, так что нам не принципиально что это не очень секьюрно. Далее мы выставляем права на расшифрованный ключ.

Далее переходим непосредственно к стадии deploy

Travis как система непрерывной интеграции и доставки


В качестве provider выбираем script - это позволит Travis исполнять команды bash во время деплоя, в секции скрипт указываем команду для копирования результатов билда:
тут важно использование переменной $TRAVIS_BUILD_DIR - это системная переменная в которой хранится путь куда Travis помещает файлы так как create-react-app билдит свои файлы в папку build мы дописываем путь и до туда. Секция on позволяет нам указать при пуше в какую ветку, мы должны провести деплой (мы же не хотим на каждый коммит отправлять файлы на сервер, верно?). Вот собственно и всё - теперь при коммите мы увидим как тревис запустит свой цикл. Закомитав и запушив мы получим следующую информацию

Travis как система непрерывной интеграции и доставки


Как видим Travis сообщил нам что деплой прошёл успешно. Проверим перейдя по адресу сервера.

Travis как система непрерывной интеграции и доставки


Вот мы и закончили с настройкой для фронтенда. Передохнем и пойдём намутим кофе.

Настройка Linux сервера для Backend приложения .NetCore
Теперь настало время заняться вторым репозиторием. Установим на машинку окружения для запуска Netcore приложений, следуя инструкциям

Далее переходим к рабочей машине, клонируем созданный пустой репозиторий для backend создаём в нём asp.netcore проект с апи для демонстрации (следим за тем, чтоб версия проекта сочеталась с версией рантайма на линукс машине). Чучуть поменяем файл Program.cs для того чтоб указать где будет запускаться наше приложение

Travis как система непрерывной интеграции и доставки


В данном случае это происходит на порту 5001. Добавляем всё в индекс гита и переходим к настройке Travis.
Возвращаемся к linux машине, напишем демона для запуска нашего dotnet приложения, а также настроим nginx.
Конфиг для nginx выглядит следующим образом

Travis как система непрерывной интеграции и доставки


Таким образом мы настроим обратный прокси для Kestrel (мы так же изменим listen порт на 82 и порт у proxy_pass на 5001)
Деплоить будем рядом с фронтенд приложением.
Проводим аналогичные мероприятия с ngnix (создаём конфигурацию, линкуем в sites-enabled), переходим к написанию демона.
Код выглядит так

Travis как система непрерывной интеграции и доставки


Сохранить данный файл нужно по пути

Код:
/etc/systemd/system/имясервиса.service
я назвал его art-test.service, теперь для включения сервиса мне нужно выполнить команду

Код:
systemctl enable art-test.service
Переходим к настройке Travis CI

Travis CI для Backend app на .NetCore
Настройка происходит аналогичным образом за исключением некоторых моментов.
Первым делом, мы точно так же добавляем репозиторий в Travis.
Мы точно так же создаём файл .travis.yml в корне проекта

Travis как система непрерывной интеграции и доставки


Как видите поменялись команды в секции скрипт и первые строки, но всё логично - мы заменили язык с Node на C# указали версию dotnet. Далее в секции скрипт мы используем dotnet restore - эта команда запустит установку всех пакетов, которые мы установим в наше приложение. Далее идёт билд и публикация конфигурации release - ничего сложного. Мы аналогичным образом генерируем ключи и шифруем их и точно так же появляется строка before install, как видите тут тоже ничего сложного.

Travis как система непрерывной интеграции и доставки


Теперь продублируем секцию before_deploy из фронтенда она тоже будет идентична

Travis как система непрерывной интеграции и доставки


Секция deploy будет аналогична фронтенду, за исключением пути к билду ( мы точно так же создаём 3 секьюрных переменных в Travis )

Travis как система непрерывной интеграции и доставки


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

Travis как система непрерывной интеграции и доставки


Да, чуть не забыл, на линукс машине можно отключить запрос пароля для sudo при перезапуске нашего сервиса (гуглим по visudo). Ну вот и всё - пушим и проверяем что CI\CD работает.

Travis как система непрерывной интеграции и доставки


Как видим, приложение загрузилось и демон его рестартнул.

Travis как система непрерывной интеграции и доставки


А на этом у меня всё, с этими знаниями мы можем сосредоточиться на том чтоб писать код и не отвлекаться. Как всегда актуальные версии в моих репозиториях, спасибо за внимание.
 
Мы в соцсетях:  ТелеграмВконтактеДзенФейсбукТвиттерЮтуб