- Настройка непрерывной интеграции и непрерывного развертывания с Дженкинсом
- Наше приложение
- Git Up на GitHub
- Наше node приложение
- Тестирование
- Время пушить
- Наше приложение обслуживается
- The First Drop
- Настройка сервера
- Установка нашего приложения
- Продолжайте
- Время тестов
- Второй дроп
- Нанимаем дворецкого
- Поток непрерывной интеграции
- Деплоим
- Ключ к аутентификации
- Автоматический деплой
- All’s Well That Automates Well
Настройка непрерывной интеграции и непрерывного развертывания с Дженкинсом
This sponsored post features a product relevant to our readers while meeting our editorial guidelines for being objective and educational.
Russian (Pусский) translation by Ilya Nikov (you can also view the original English article)
Ежедневная жизнь разработчика заполнена однообразными и повторяющимися задачами. К счастью, мы живем в век автоматизации, а это значит, что компьютеры отлично справляются со скучными делами, и они почти никогда не жалуются на это! Итак, давайте создадим некоторую автоматизацию, чтобы сделать нашу ежедневную шлифовку немного менее хрустящей.
Тестирование и развертывание — два неотъемлемых элемента веб-разработки. При некоторой смешанной автоматизации они становятся решениями, которые обычно называют «непрерывной интеграцией» (CI) и «непрерывным развертыванием» (CD). «Непрерывный» аспект этих решений означает, что ваши проекты будут автоматически протестированы и развернуты, что позволит вам больше сосредоточиться на написании кода и о том, чтобы пасти его на серверы.
В этом уроке мы создадим популярный сервер непрерывной интеграции Jenkins и синхронизируем его с GitHub, чтобы он запускал тесты каждый раз при пуше нового кода. После этого мы создадим решение для автоматического перевода этого кода на наш сервер приложений, устраняя необходимость развертывания вручную.
Мы будем использовать DigitalOcean для быстрого и легкого создания виртуальных частных серверов на основе облачных вычислений (VPS) для размещения нашего приложения и Jenkins.
Примечание. В этом учебном пособии предполагается, что у вас есть базовое знание работы с командной строкой и что на вашем компьютере установлены как Git, так и Node.js.
Наше приложение
Прежде чем мы можем протестировать или развернуть что-либо, нам нужно что-то испытать и развернуть. Позвольте мне познакомить вас с нашим дружественным тестовым приложением, точно названным «hello-jenkins».
Мы будем писать простое приложение Node.js в соответствии с нашими целями. Оно просто будет отображать строку текста в браузере, но этого достаточно, чтобы обеспечить правильную настройку непрерывной интеграции и непрерывного развертывания.
Git Up на GitHub
Поскольку мы будем хранить наш проект на GitHub, давайте начнем там. Войдите в (или создайте) свою учетную запись GitHub и создайте новый репозиторий. Назовите его «hello-jenkins» и дайте ему следующее описание:
Для простоты, давайте сохраним repo Public. Идите и проверьте инициализацию этого репозитория с помощью опции README и выберите опцию Node из раскрывающегося списка Добавить .gitignore.
Нажмите кнопку Create repository, и наш репозиторий будет готов.
Теперь давайте клонируем наш новый репозиторий на нашу локальную машину и перейдем к нему:
Наше node приложение
Вот, какова будет окончательная структура нашего приложения:
Давайте рассмотрим его по шагам. Первым шагом к созданию любого приложения Node.js является создание файла package.json . Вот наш:
В dependencies мы добавили express , который мы будем использовать, чтобы создать наше приложение Node.js. В devDependencies мы добавили mocha и supertest , оба из которых помогут нам написать наши тесты.
Теперь, когда наш package.json определен, установите наши зависимости приложения, запустив:
Пришло время написать наш код приложения. Создайте файл с именем app.js и добавьте к нему следующее:
Давайте раскроем наше простое приложение Node.js:
- Сначала мы импортируем библиотеку express , указанную в нашем package.json .
- Мы используем express для создания нового app .
- Мы сообщим нашему app отвечать на все запросы, которые попадают в корень нашего сайта ( / ), с текстом «hello world».
- Затем мы расскажем нашему app о том, какой порт прослушивает запросы ( process.env.PORT ссылается на переменную окружения, называемую «PORT», а если она не существует, мы вместо этого по умолчанию устанавливаем порт 5000).
- Наконец, мы делаем наше app доступным для других модулей Node.js через module.exports (это будет полезно позже, когда мы добавим тесты).
Это оно! Наше приложение готово — давайте запустим его:
Откройте свой любимый браузер и перейдите по адресу http://localhost:5000 , и вы должны увидеть hello wolrd.
Это не самое захватывающее тестовое приложение, но оно работает! Идите дальше и выключите наше приложение Node.js с помощью Ctrl-C, и давайте двигаться дальше.
Тестирование
Пришло время написать тест для нашего приложения — в конце концов, если нам нечего тестировать, тогда Дженкинсу нечего делать!
Создайте папку с именем test и создайте файл с именем test.js . Добавьте следующий код для test/test.js :
Как работает наш тест? Во-первых, мы импортируем как supertest , так и наше app . Затем мы добавляем один тест, описывающий, что должно произойти, когда запрос GET попадает в корень нашего сайта. Мы говорим нашему тесту, что ответ будет «hello world», и если это так, тест проходит.
Чтобы запустить тест, мы будем использовать библиотеку Mocha. Мы установили Mocha как часть наших devDependencies , поэтому мы просто запустим команду, которая передает наш тестовый файл в Mocha и Mocha запустит наши тесты:
Когда закончите, вы увидите зеленую точку вместе с информацией о том, что один тест прошел. Это означает, что наш тест прошел успешно! Но набрав эту команду снова и снова, скоро появятся судороги пальцев и подергивания глаз, поэтому давайте сделаем для нас вспомогательный скрипт (помните, компьютеры не скучают!).
Создайте новый каталог с именем script , и в нем создайте файл с именем test (обратите внимание, что расширение не существует). Добавьте в script/test следующее:
Теперь у нас есть сценарий оболочки для выполнения этой линии для нас. Но прежде чем мы сможем использовать его, мы должны предоставить ему исполняемые разрешения:
Давайте проверим это! Запускаем:
. и вы должны увидеть прохождение того же теста, что и раньше.
Время пушить
Хорошо, у нас есть рабочее приложение и рабочий тест, поэтому давайте добавим наш новый код в GitHub:
И это все — наше приложение сделано и на GitHub!
Наше приложение обслуживается
У нас есть увлекательное приложение (у «hello world» есть своего рода поэзия к нему, вы не согласны?), Но никто этого не видит! Давайте изменим это и запустим наше приложение на сервере.
Для наших потребностей хостинга мы обратимся к DigitalOcean. DigitalOcean обеспечивает быстрый и простой способ разворота виртуальных облаков VPS, что делает его идеальным местом для нашей игровой площадки CI / CD.
The First Drop
Войдите в систему (или зарегистрируйтесь для) DigitalOcean и нажмите кнопку Create Droplet. Для имени хоста назовите его «hello-jenkins». Экземпляр самого низкого размера (512 МБ / 1/20 ГБ) будет соответствовать нашим потребностям и выберите ближайший к вам географический регион. Затем нам нужно выбрать образ, используемый для создания droplet. DigitalOcean предлагает широкий выбор операционных систем на выбор, но очень приятно, что они также предоставляют изображения, специально предназначенные для определенных типов приложений.
Перейдите на вкладку Applications и выберите опцию node-v0.10.29 on Ubuntu 14.04 — это создаст сервер, который хорошо загружен для нашего приложения Node.js.
Теперь нажмите Create Droplet, и DigitalOcean начнет инициализацию нашего сервера.
Настройка сервера
Через минуту наш новый сервер должен быть готов, и вы должны получить электронное письмо с учетными данными вашего сервера. Давайте использовать эту информацию для входа:
Вам будет предложено ввести пароль, указанный в письме, а затем сразу же необходимо создать новый пароль (сделайте его очень сильным и сохраните его в безопасном месте, например, в базе данных KeePass).
Сейчас мы вошли в систему под именем root , который является полнофункциональным полубогом Linux-land. Но тяжелая голова, которая носит корону, и работать под root , как правило, плохая идея. Итак, первое, что мы хотим сделать, это создать нового пользователя — назовем его «app»:
Вам нужно будет предоставить пароль (другой надежный пароль, надежно сохраненный), а затем команда задаст ряд необязательных вопросов.
Мы хотим перейти к нашему пользователю app , но перед выходом в систему нам нужно предоставить нашим новым пользователям права sudo , чтобы он мог выполнять административные действия:
Теперь закройте соединение командой exit , а затем подключитесь как app :
Вам будет предложено ввести пароль пользователя app , а затем вы должны войти в систему и продолжить работу.
Установка нашего приложения
Давайте добавим наше приложение на машину. Благодаря изображениям приложений DigitalOcean наша машина поставляется с предустановленными Node.js и npm, но нам все равно нужно установить Git:
Вам будет предложено ввести пароль (поскольку вы используете sudo ), и вам нужно будет подтвердить установку с помощью Y. Как только Git будет установлен, мы можем использовать его для получения нашего приложения из GitHub.
Скопируйте URL-адрес клонирования HTTPS с страницы проекта GitHub и затем клонируйте репозиторий в свою домашнюю папку на сервере:
Теперь наше приложение находится на нашем сервере в папке «hello-jenkins». Давайте перейдем к следующему:
Первое, что нам нужно сделать, это установить зависимости приложений:
Как только это будет сделано, мы сможем запустить наше приложение!
. и перейдите к IP-адресу вашего сервера в вашем браузере.
Но подождите, это не сработает! В чем дело?
Ну, давайте вспомним эту строку кода в нашем app.js :
Прямо сейчас у нас нет установленной переменной окружения PORT , поэтому наше приложение по умолчанию использует порт 5000, и вам нужно добавить порт к IP-адресу в браузере ( http://YOUR.SERVER.IP.ADDRESS:5000 ).
Итак, как мы можем заставить наше приложение обслуживать, как ожидалось, без необходимости указывать порт? Ну, когда браузер делает HTTP-запрос, по умолчанию он имеет порт 80. Поэтому нам просто нужно установить переменную среды PORT в 80 .
Мы установим переменные среды в файле /etc/environment на сервере — этот файл будет загружен при входе в систему, а набор переменных будет доступен по всему миру для всех приложений. Откройте файл:
Вы увидите, что прямо сейчас в этом файле установлен PATH . Добавьте после него следующую строку:
Затем введите Ctrl-X, Y и Enter, чтобы сохранить и выйти. Выход из сервера ( exit ) и SSH обратно (это загрузит новую переменную среды).
Последняя маленькая задача — запуск приложения на порту 80 требует прав root, но выполнение sudo node app.js не сохранит переменные среды, которые мы установили. Чтобы обойти это, мы разрешим node иметь возможность запускать на порту 80 под sudo :
Это должно сработать. Теперь запустите:
Перейдите в http://YOUR.SERVER.IP.ADDRESS , и вы увидите hello world!
Продолжайте
Сейчас наше приложение работает только во время выполнения процесса — если мы его закрываем, наш сайт больше не доступен. Нам нужно, чтобы наше приложение Node.js работало в фоновом режиме. Для этого мы будем использовать forever. Первый шаг — установить его глобально:
Теперь вместо запуска нашего приложения с node app.js мы будем использовать:
Обратите внимание, что вместо процесса, зависающего при выполнении, он немедленно завершает работу и дает вам обратный контроль. Это связано с тем, что сервер Node.js работает в фоновом режиме. Теперь нам не нужно беспокоиться о том, что наш сервер отключается при выходе из сервера. forever даже автоматически перезапустит наше приложение, если произойдет сбой!
Чтобы остановить наше приложение, мы можем запустить:
Пока давайте продолжим работать и перейдем к Дженкинсу.
Время тестов
Мы будем размещать наш сервер Jenkins на отдельном дроплете DigitalOcean. Давайте сейчас это сделаем.
Второй дроп
Создайте новый дроп с именем хоста «jenkins-box». Выберите снова 512MB/1/20GB, вместе с тем же местом и тем же типом приложения (node-v0.10.29 on Ubuntu 14.04), как и с предыдущим дроплетом.
Нажмите Create Droplet, и как только она будет завершена, используйте учетные данные, отправленные вам по электронной почте, чтобы войти в систему через SSH (вам нужно будет установить новый пароль, как и раньше).
Как и прежде, мы должны создать нового пользователя, прежде чем мы сделаем что-нибудь еще. На этот раз назовем его admin :
Войдите в систему как пользователь root и войдите в систему как новый созданный admin .
Поскольку цель Jenkins — это получить наш проект и выполнить его тесты, наша машина должна установить все зависимости проекта. Мы создали этот экземпляр с помощью приложения Node.js от DigitalOcean, поэтому Node.js и npm уже установлены. Но нам еще нужно установить Git:
Нанимаем дворецкого
Далее — Дженкинс. Установка Дженкинса довольно проста — apt-get все сделает за нас. Единственное, что перед началом установки нам нужно добавить новый apt -репозиторий:
Теперь мы можем установить Jenkins:
После завершения Jenkins будет запущен и доступен на порту 8080. Перейдите в свой браузер к IP-адресу jenkins-box на порту 8080, и вы увидите целевую страницу Jenkins.
Нажмите ссылку Manage Jenkins, а затем ссылку Manage Plugins. Перейдите на вкладку Available и найдите GitHub Plugin. Установите флажок « Install», а затем кнопку Download now and install after restart.
Это инициирует последовательность установки. Плагин GitHub имеет несколько зависимостей, поэтому будут установлены несколько плагинов. В нижней части страницы установите флажок Restart Jenkins when installation is complete and no jobs are running — это заставит Jenkins перезапустится после завершения установки.
Как только Jenkins перезапустится, пришло время добавить наш проект. Нажмите кнопку New Item. Используйте «hello-jenkins» для имени элемента, выберите Build a free-style software project и нажмите кнопку «ОК».
Как только проект будет настроен, вы попадете на страницу настроек проекта. Добавьте URL-адрес проекта GitHub в поле проекта GitHub:
Затем выберите опцию Git в разделе Source Code Management. В новых появляющихся полях добавьте URL-адрес нашего репозитория проекта GitHub в поле Repository URL:
Прокрутите еще немного вниз и нажмите на квадрат, чтобы включить Build when a change is pushed to GitHub. Если эта опция будет установлена, наш проект будет строиться каждый раз, когда вы делаете пуш в репозиторий GitHub. Конечно, нам нужно, чтобы Дженкинс знал, что делать, когда он запускает сборку. Нажмите раскрывающийся список Add build step и выберите Execute shell. Это сделает диалог Command доступным, и то, что мы добавим в этот диалог, будет запущено, когда инициируется сборка. Добавьте к нему следующее:
Наша сборка состоит из двух этапов. Во-первых, он устанавливает зависимости приложений. Затем он запускает ./script/test для запуска наших тестов.
Чтобы завершить настройку интеграции, перейдите к репозиторию GitHub и нажмите « Settings». Перейдите на вкладку Webhooks & Services, а затем в раскрывающемся списке Add service. Выберите сервис Jenkins (GitHub plugin).
Добавьте в качестве URL-адреса хука Дженкинса следующее:
Нажмите Add service. Наш проект теперь готов к первому непрерывному тесту интеграции!
Давайте дадим ему что-то испытать. Откройте app.js локально и измените эту строку:
Сохраните изменения и зафиксируйте их:
Теперь следите за Дженкинсом, пока вы пушите свои изменения на GitHub:
Через секунду или две вы должны увидеть, что для нашего проекта hello-jenkins в Jenkins была начата новая работа — наши непрерывные интеграционные работы!
Поток непрерывной интеграции
Но . работа терпит неудачу! Почему?
Хорошо, помните, что наш тест ожидает, что корневой вызов вернет «hello world», но мы изменили его на «hello jenkins». Поэтому давайте изменим ожидания нашего теста. Поменяйте эту строку:
Сохраним, зафиксируем и пушим еще раз:
Посмотрите Дженкинс — еще раз, вы увидите, что сборка автоматически запускается, и на этот раз ей это удается!
Это поток непрерывной интеграции. Контрольный сервер постоянно тестирует любой новый код, который вы пушите, чтобы вы быстро узнали о любых неудачных тестах.
Деплоим
Хорошо, поэтому мы автоматически проверяем наши изменения, но как насчет развертывания этих изменений? Нет проблем!
Если вы внимательно наблюдаете, вы, несомненно, заметили, что чего-то не хватает в нашем проекте. В структуре проекта в начале учебника существует файл script/deploy , но мы еще не создали такой файл. Ну, теперь мы создадим!
Ключ к аутентификации
Но сначала обсудим, как будет работать развертывание. Наш скрипт (под управлением Jenkin’s build step) войдет на сервер приложений через SSH, перейдет в нашу папку app, обновит приложение и перезапустит сервер. Перед написанием нашего сценария развертывания нам нужно обработать, как наш Jenkins-сервер будет осуществлять SSH доступ на наш сервер приложений.
До сих пор мы обращались к нашим серверам вручную, вводя пароли, но этот подход не будет работать для автоматизированных сценариев. Вместо этого мы создадим ключ SSH, который сервер Jenkins будет использовать для аутентификации с сервером приложений.
Когда Jenkins устанавливается, он создает нового пользователя под именем jenkins . Jenkins выполняет все команды от этого пользователя, поэтому нам нужно сгенерировать наш ключ с пользователем jenkins , чтобы он имел соответствующий доступ к нему.
При входе в систему в качестве admin в jenkins-box выполните следующие действия:
Предоставьте пароль admin , и он переключит вас на пользователя root . Затем выполните:
Теперь вы действуете как пользователь jenkins . Создайте ключ SSH:
Сохраните файл в местоположении по умолчанию ( /var/lib/jenkins/.ssh/id_rsa ) и не используйте парольную фразу (иначе для доступа SSH потребуется пароль и не будет работать при автоматическом режиме).
Затем нам нужно скопировать открытый ключ, который был создан. Запустите это:
. и скопируйте вывод. Это должна быть длинная строка, начинающаяся с «ssh-rsa» и заканчивающаяся «jenkins @ jenkins-box».
Выйдите из jenkins-box и войдите в наш сервер приложений ( hello-jenkins ) в качестве пользователя app . Нам нужно создать файл с именем authorized_keys в папке .ssh нашего пользователя app :
Вставьте открытый ключ, который вы скопировали, а затем Ctrl-X/Y/Enter, чтобы сохранить и выйти. Чтобы этот файл работал правильно, на нем должны быть установлены строгие разрешения:
Вернитесь в бокс jenkins , переключитесь на пользователя jenkins и убедитесь, что вы можете войти на наш сервер приложений, не вводя пароль:
Вы должны успешно войти на сервер приложений, не вводя пароль. С учетом этого мы теперь можем перейти к развертыванию.
Автоматический деплой
Создайте файл в папке script с именем deploy (обратите внимание, что расширение не существует). Добавьте следующее в script/deploy :
Давайте пройдем через это:
- Во-первых, мы заходим на сервер приложений в качестве пользователя app .
- Затем мы переходим в нашу папку приложений и обновляем последнюю версию GitHub.
- После этого мы устанавливаем наши зависимости.
- Наконец, как только наш код приложения будет обновлен, мы перезагрузим наш сервер с помощью команды forever restartall .
Сделайте наш новый исполняемый файл сценария:
Добавьте этот новый файл и зафиксируйте его:
Но давайте пока не будем пушить. Сначала вернитесь к нашей конфигурации проекта в Jenkins и прокрутите вниз до команды сборки. Добавьте эту новую строку в конец:
Сохраните проект Дженкинса.
Теперь делаем пуш на GitHub, и смотрите, как Дженкинс автоматически начинает сборку. После того, как сборка будет выполнена (она будет успешной), перейдите в свой браузер на IP-адрес нашего сервера приложений. Presto! Наш захватывающий «hello world» был заменен волнующим «hello jenkins»!
Наше приложение теперь постоянно развертывается!
All’s Well That Automates Well
Уф. Это было настоящее преключение!
В итоге мы успешно создали как непрерывную интеграцию, так и непрерывное развертывание, что обеспечивает очень хороший уровень автоматизации в повседневной жизни разработчиков. Помните, что компьютеры не скучают, поэтому, пока они обрабатывают тестирование и развертывание, вы можете делать важные вещи, например, сделать себе бутерброд. Так что сделай этот бутерброд и съешь его, как чемпион по автоматизации!