Доброго времени суток, 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.
На рабочей машинке создаём директорию, клонируем созданный репозиторий для фронтенда.
Далее выполняем команду для создания react приложения.
Ждём пока yarn установит все зависимости, по окончании в случае успеха получим следующее сообщение
Удалим созданый create-react-app README.md файл за ненадобностью. Добавим созданный файл .gitignore, а затем всё остальное в репозиторий.
Проверим что приложение работает - выполнив команду yarn start. В результате откроется браузер по адресу localhost:3000 и мы увидим такое вот
Отлично, теперь переходим к настройки Travis. Вся настройка сводится к созданию файла .travis.yml в корне репозитория, давайте воспользуемся прекрасным редактором vscode и откроем папку репозитория и создадим файл.
Добавим его в индекс, закоммитаем, запушим и переключимся на настройку удаленной машины. Цепляемся по ssh…
Nginx
Замечательный легковесный веб-сервер. Юзается для всего. Прост и податлив в настройке. Настройка сводится к настройке файла nginx.config плюс минус разграничение по правам для системы.
вот так в данном случае выглядит конфигурация. Этот файл мы помещаем по пути
Саму статику размещаем там где удобно не забывая поправить root в конфиге, например сюда: /home/example/www/articleapp.ru
далее делаем линкуем его с sites-enabled
и перезапускаем nginx. Ах да, если есть домен, лучше соблюдать доменные наименования.
Ну вообщем всё просто как и обещал, проверим что всё это работает. создав html заглушку c its works.
На этом с настройкой линукс машины закончили (тема с тем что у nginx свой пользователь должен быть под каждый сайт и и т.д. опущена)
Настройка Travis для Фронтенда
Переходим к настройки CI Travis, подошли к самому интересному. Итак, прежде всего нужно зайти на travis-ci.org под своим гитхаб аккаунтом.
Далее Travis предложит выбрать репозиторий
Я выбираю CIfrontend - двигая свитч напротив репозитория:
После чего по ссылке
Я хочу организовать следующий процесс:
Итак, пошли по порядку.
Первый шаг реализуется строкой где мы указываем Travis какой язык используем (подробнее тут
тут мы также указываем версию node. Почему мы собираем на node? Для сборки react приложений нужен webpack, а ему node - всё логично. Неплохо было бы кэшировать модули которые установит yarn, так что давайте реализуем эту возможность добавив папку node_modules в кэш:
Самое простое выполнено, дальше у нас идет секция скрипт, где мы уже можем управлять своим пайплайном.
Помните да? Сначала тесты, потом билд. А пока мне бы хотелось подробнее рассказать про строки 9 и “--coverage && codecov”. Как многие наверное догадались - это метрика покрытия кода, существует проект codecov который собирает статистику по вашему коду вернее по тому как ваши тесты покрывают ваш код. Разумеется чем выше покрытие, тем лучше, тем больше достоверности что ваше приложение работает так как вы того ожидаете. Так вот на строке 9 мы устанавливаем раннер для проверки покрытия а затем запускаем тестирование (в данном случае jest) чтобы убедиться, что у нас всё хорошо. Я вернусь к покрытию, когда буду рассказывать о гитхаб бейджиках. Пока давайте остановится и закоммитаем travis-файл в репозиторий, мне не терпиться показать вам что случилось.
Итак оно работает
только что я просто закомитал код, а тревис начал собирать мне релиз. Чудеса… Тревис выполнит свою работу выложит вам всю информацию в удобный лог, который я не буду скринить, а затем сохранит инфу о успешном билде в Build History
А значит мы можем гордо забрать динамичный бейдж для нашего Readme.md - для этого составим ссылку вот такого вида (markdown)
выглядит теперь у нас readme будет так
Закоммитаем, запушем, погладим себя по голове - мы молодцы, мы заслужили пойдём намутим кофе.
Вернемся к разговору о покрытии кода тестами. Так как мы поставили пакет codecov мы можем получить ещё один бейджик с информацией о покрытии. Для этого нам нужно отредактировать вот эту вот ссылку
тут нужно заменить enterDevelop/CIfrontend на путь до вашего репозитория и мы получим вот такую вот картинку
Теперь переходим к самой интересной на мой взгляд части - автодеплою.
Travis CD
Travis предоставляет множество способов деплоя из коробки в различные облака, хостинги и тд. Мы же пойдём путём джедаев, попутно сэкономив на облаке. Travis поддерживает деплой как как набор команд оболочки, воспользуемся этой фичей и настроим деплой по ssh. План такой:
Так вот первое что нужно сделать сгенерить ключи для ssh.
Используем для этого команду
Далее криптуем всё это дело командой
Копируем публичный ключ на сервер
удаляем файлы ключи из директории
добавляем в репозиторий зашифрованный ключ для тревис
В случае успеха в Travis кликаем на More options, выбираем Settings проматываем до секции “Environment Variables” и видим примерно такую картину:
Travis создал себе ключи для расшифровки, а так же сам добавил расшифровку в файл .travis.yml:
Создадим еще несколько переменных, с помощью формы ниже , для большей секьюрности. А именно server_port, server_ip, server_user так мы сможем инкапсулировать пользователя ssh (разумно будет для тревиса создать отдельного юзера). В финале должно получиться что-то такое
Переходим к конфигурированию в файле travis.yml. Добавим секцию before_deploy которая отвечает за действия (очевидно) происходящие перед деплоем.
на 16ой строке мы проверяем наличие ssh-agent и тот факт что он запущен (на всякий случай). Далее разрешаем доступ ко всем хостам (отключив проверку stricthostkey) тревис каждый раз поднимает новую машинку для билда, так что нам не принципиально что это не очень секьюрно. Далее мы выставляем права на расшифрованный ключ.
Далее переходим непосредственно к стадии deploy
В качестве provider выбираем script - это позволит Travis исполнять команды bash во время деплоя, в секции скрипт указываем команду для копирования результатов билда:
тут важно использование переменной $TRAVIS_BUILD_DIR - это системная переменная в которой хранится путь куда Travis помещает файлы так как create-react-app билдит свои файлы в папку build мы дописываем путь и до туда. Секция on позволяет нам указать при пуше в какую ветку, мы должны провести деплой (мы же не хотим на каждый коммит отправлять файлы на сервер, верно?). Вот собственно и всё - теперь при коммите мы увидим как тревис запустит свой цикл. Закомитав и запушив мы получим следующую информацию
Как видим Travis сообщил нам что деплой прошёл успешно. Проверим перейдя по адресу сервера.
Вот мы и закончили с настройкой для фронтенда. Передохнем и пойдём намутим кофе.
Настройка Linux сервера для Backend приложения .NetCore
Теперь настало время заняться вторым репозиторием. Установим на машинку окружения для запуска Netcore приложений, следуя инструкциям
Далее переходим к рабочей машине, клонируем созданный пустой репозиторий для backend создаём в нём asp.netcore проект с апи для демонстрации (следим за тем, чтоб версия проекта сочеталась с версией рантайма на линукс машине). Чучуть поменяем файл Program.cs для того чтоб указать где будет запускаться наше приложение
В данном случае это происходит на порту 5001. Добавляем всё в индекс гита и переходим к настройке Travis.
Возвращаемся к linux машине, напишем демона для запуска нашего dotnet приложения, а также настроим nginx.
Конфиг для nginx выглядит следующим образом
Таким образом мы настроим обратный прокси для Kestrel (мы так же изменим listen порт на 82 и порт у proxy_pass на 5001)
Деплоить будем рядом с фронтенд приложением.
Проводим аналогичные мероприятия с ngnix (создаём конфигурацию, линкуем в sites-enabled), переходим к написанию демона.
Код выглядит так
Сохранить данный файл нужно по пути
я назвал его art-test.service, теперь для включения сервиса мне нужно выполнить команду
Переходим к настройке Travis CI
Travis CI для Backend app на .NetCore
Настройка происходит аналогичным образом за исключением некоторых моментов.
Первым делом, мы точно так же добавляем репозиторий в Travis.
Мы точно так же создаём файл .travis.yml в корне проекта
Как видите поменялись команды в секции скрипт и первые строки, но всё логично - мы заменили язык с Node на C# указали версию dotnet. Далее в секции скрипт мы используем dotnet restore - эта команда запустит установку всех пакетов, которые мы установим в наше приложение. Далее идёт билд и публикация конфигурации release - ничего сложного. Мы аналогичным образом генерируем ключи и шифруем их и точно так же появляется строка before install, как видите тут тоже ничего сложного.
Теперь продублируем секцию before_deploy из фронтенда она тоже будет идентична
Секция deploy будет аналогична фронтенду, за исключением пути к билду ( мы точно так же создаём 3 секьюрных переменных в Travis )
Пожалуй мы подобрались к единственному отличию - это перезапуск нашего демона после того как тревис выполнит деплой. Для этого есть секция after_deploy, давайте добавим её
Да, чуть не забыл, на линукс машине можно отключить запрос пароля для sudo при перезапуске нашего сервиса (гуглим по visudo). Ну вот и всё - пушим и проверяем что CI\CD работает.
Как видим, приложение загрузилось и демон его рестартнул.
А на этом у меня всё, с этими знаниями мы можем сосредоточиться на том чтоб писать код и не отвлекаться. Как всегда актуальные версии в моих репозиториях, спасибо за внимание.
Итак формат хакатона следующий: за отведенное время (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 систему). Надеюсь с созданием репозитория могут справиться абсолютно все читатели данной статьи (если это не про тебя, то дальше читать не стоит).
Я создал два репозитория под статью:
- один для бекэнда enterDevelop/CIbackend
- один для фронтенда enterDevelop/CIfrontend
Начнём с фронтенд приложения. Про то как сделать настройку для react и typescript я уже писал, можно почитать в моей подписи, сейчас же применим супер способ от facebook - create-react-app.
На рабочей машинке создаём директорию, клонируем созданный репозиторий для фронтенда.
Далее выполняем команду для создания react приложения.
Ждём пока yarn установит все зависимости, по окончании в случае успеха получим следующее сообщение
Удалим созданый create-react-app README.md файл за ненадобностью. Добавим созданный файл .gitignore, а затем всё остальное в репозиторий.
Проверим что приложение работает - выполнив команду yarn start. В результате откроется браузер по адресу localhost:3000 и мы увидим такое вот
Отлично, теперь переходим к настройки Travis. Вся настройка сводится к созданию файла .travis.yml в корне репозитория, давайте воспользуемся прекрасным редактором vscode и откроем папку репозитория и создадим файл.
Добавим его в индекс, закоммитаем, запушим и переключимся на настройку удаленной машины. Цепляемся по ssh…
Nginx
Замечательный легковесный веб-сервер. Юзается для всего. Прост и податлив в настройке. Настройка сводится к настройке файла nginx.config плюс минус разграничение по правам для системы.
вот так в данном случае выглядит конфигурация. Этот файл мы помещаем по пути
Код:
/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.
На этом с настройкой линукс машины закончили (тема с тем что у nginx свой пользователь должен быть под каждый сайт и и т.д. опущена)
Настройка Travis для Фронтенда
Переходим к настройки CI Travis, подошли к самому интересному. Итак, прежде всего нужно зайти на travis-ci.org под своим гитхаб аккаунтом.
Далее Travis предложит выбрать репозиторий
Я выбираю CIfrontend - двигая свитч напротив репозитория:
После чего по ссылке
Ссылка скрыта от гостей
для меня становится доступным дашборд с инфой по репозиторию, однако он еще пуст, так что давайте изменим это. Переходим к написанию travis.yml файла.Я хочу организовать следующий процесс:
- Устанавливаем зависимости
- Запуск тестов. Если тесты прошли успешно переходим к шагу два, если нет - останавливаем цикл.
- Запускаем билд. Если билд успешен, переходим к деплою
- Запускаем деплой, если всё прошло хорошо переходим к оповещению
Итак, пошли по порядку.
Первый шаг реализуется строкой где мы указываем Travis какой язык используем (подробнее тут
Ссылка скрыта от гостей
)тут мы также указываем версию node. Почему мы собираем на node? Для сборки react приложений нужен webpack, а ему node - всё логично. Неплохо было бы кэшировать модули которые установит yarn, так что давайте реализуем эту возможность добавив папку node_modules в кэш:
Самое простое выполнено, дальше у нас идет секция скрипт, где мы уже можем управлять своим пайплайном.
Помните да? Сначала тесты, потом билд. А пока мне бы хотелось подробнее рассказать про строки 9 и “--coverage && codecov”. Как многие наверное догадались - это метрика покрытия кода, существует проект codecov который собирает статистику по вашему коду вернее по тому как ваши тесты покрывают ваш код. Разумеется чем выше покрытие, тем лучше, тем больше достоверности что ваше приложение работает так как вы того ожидаете. Так вот на строке 9 мы устанавливаем раннер для проверки покрытия а затем запускаем тестирование (в данном случае jest) чтобы убедиться, что у нас всё хорошо. Я вернусь к покрытию, когда буду рассказывать о гитхаб бейджиках. Пока давайте остановится и закоммитаем travis-файл в репозиторий, мне не терпиться показать вам что случилось.
Итак оно работает
только что я просто закомитал код, а тревис начал собирать мне релиз. Чудеса… Тревис выполнит свою работу выложит вам всю информацию в удобный лог, который я не буду скринить, а затем сохранит инфу о успешном билде в Build History
А значит мы можем гордо забрать динамичный бейдж для нашего Readme.md - для этого составим ссылку вот такого вида (markdown)
Код:
[![Build Status](https://travis-ci.org/enterDevelop/CIfrontend.svg?branch=master)](https://travis-ci.org/enterDevelop/CIfrontend)
выглядит теперь у нас readme будет так
Закоммитаем, запушем, погладим себя по голове - мы молодцы, мы заслужили пойдём намутим кофе.
Вернемся к разговору о покрытии кода тестами. Так как мы поставили пакет 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 CD
Travis предоставляет множество способов деплоя из коробки в различные облака, хостинги и тд. Мы же пойдём путём джедаев, попутно сэкономив на облаке. Travis поддерживает деплой как как набор команд оболочки, воспользуемся этой фичей и настроим деплой по ssh. План такой:
- Расшарить ключ для автоконнекта тревиса к серверу
- Скопировать файлы
Так вот первое что нужно сделать сгенерить ключи для 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.yml:
Создадим еще несколько переменных, с помощью формы ниже , для большей секьюрности. А именно server_port, server_ip, server_user так мы сможем инкапсулировать пользователя ssh (разумно будет для тревиса создать отдельного юзера). В финале должно получиться что-то такое
Переходим к конфигурированию в файле travis.yml. Добавим секцию before_deploy которая отвечает за действия (очевидно) происходящие перед деплоем.
на 16ой строке мы проверяем наличие ssh-agent и тот факт что он запущен (на всякий случай). Далее разрешаем доступ ко всем хостам (отключив проверку stricthostkey) тревис каждый раз поднимает новую машинку для билда, так что нам не принципиально что это не очень секьюрно. Далее мы выставляем права на расшифрованный ключ.
Далее переходим непосредственно к стадии deploy
В качестве provider выбираем script - это позволит Travis исполнять команды bash во время деплоя, в секции скрипт указываем команду для копирования результатов билда:
тут важно использование переменной $TRAVIS_BUILD_DIR - это системная переменная в которой хранится путь куда Travis помещает файлы так как create-react-app билдит свои файлы в папку build мы дописываем путь и до туда. Секция on позволяет нам указать при пуше в какую ветку, мы должны провести деплой (мы же не хотим на каждый коммит отправлять файлы на сервер, верно?). Вот собственно и всё - теперь при коммите мы увидим как тревис запустит свой цикл. Закомитав и запушив мы получим следующую информацию
Как видим Travis сообщил нам что деплой прошёл успешно. Проверим перейдя по адресу сервера.
Вот мы и закончили с настройкой для фронтенда. Передохнем и пойдём намутим кофе.
Настройка Linux сервера для Backend приложения .NetCore
Теперь настало время заняться вторым репозиторием. Установим на машинку окружения для запуска Netcore приложений, следуя инструкциям
Ссылка скрыта от гостей
Далее переходим к рабочей машине, клонируем созданный пустой репозиторий для backend создаём в нём asp.netcore проект с апи для демонстрации (следим за тем, чтоб версия проекта сочеталась с версией рантайма на линукс машине). Чучуть поменяем файл Program.cs для того чтоб указать где будет запускаться наше приложение
В данном случае это происходит на порту 5001. Добавляем всё в индекс гита и переходим к настройке Travis.
Возвращаемся к linux машине, напишем демона для запуска нашего dotnet приложения, а также настроим nginx.
Конфиг для nginx выглядит следующим образом
Таким образом мы настроим обратный прокси для Kestrel (мы так же изменим listen порт на 82 и порт у proxy_pass на 5001)
Деплоить будем рядом с фронтенд приложением.
Проводим аналогичные мероприятия с ngnix (создаём конфигурацию, линкуем в sites-enabled), переходим к написанию демона.
Код выглядит так
Сохранить данный файл нужно по пути
Код:
/etc/systemd/system/имясервиса.service
я назвал его art-test.service, теперь для включения сервиса мне нужно выполнить команду
Код:
systemctl enable art-test.service
Переходим к настройке Travis CI
Travis CI для Backend app на .NetCore
Настройка происходит аналогичным образом за исключением некоторых моментов.
Первым делом, мы точно так же добавляем репозиторий в Travis.
Мы точно так же создаём файл .travis.yml в корне проекта
Как видите поменялись команды в секции скрипт и первые строки, но всё логично - мы заменили язык с Node на C# указали версию dotnet. Далее в секции скрипт мы используем dotnet restore - эта команда запустит установку всех пакетов, которые мы установим в наше приложение. Далее идёт билд и публикация конфигурации release - ничего сложного. Мы аналогичным образом генерируем ключи и шифруем их и точно так же появляется строка before install, как видите тут тоже ничего сложного.
Теперь продублируем секцию before_deploy из фронтенда она тоже будет идентична
Секция deploy будет аналогична фронтенду, за исключением пути к билду ( мы точно так же создаём 3 секьюрных переменных в Travis )
Пожалуй мы подобрались к единственному отличию - это перезапуск нашего демона после того как тревис выполнит деплой. Для этого есть секция after_deploy, давайте добавим её
Да, чуть не забыл, на линукс машине можно отключить запрос пароля для sudo при перезапуске нашего сервиса (гуглим по visudo). Ну вот и всё - пушим и проверяем что CI\CD работает.
Как видим, приложение загрузилось и демон его рестартнул.
А на этом у меня всё, с этими знаниями мы можем сосредоточиться на том чтоб писать код и не отвлекаться. Как всегда актуальные версии в моих репозиториях, спасибо за внимание.