Continuously Integrate and Deploy an App
In the previous module, we looked at how to provision a Jenkins cluster on Azure to support continuously integrate of applications. Now in this module, let’s see how we can use Jenkins to continuously build Node.js projects and continously deploy application updates to our Dokku test environment within minutes. We start the pipeline by integrating with GitHub to automatically trigger this CI pipeline to run when a change is pushed to GitHub. Then we end with pushing updates to Dokku environment.
Installing Plugins
Jenkins provides hundreds of plugins to support building, testing, deploying, and automation for virtually any project.
From your browser, click Manage Jenkins
in the navigation sidebar and then click Manage Plugins
. From the Available
tab, search and select the following plugins:
- GitHub Plugin
- Embeddable Build Status Plugin
- NodeJS Plugin
Click Install without restart
to install the plugins and all the dependencies for these plugins. Once all plugins indicate Success
, click the checkbox next to “Restart Jenkins” at the bottom to finish the installation.
Integrating with GitHub
To create an end-to-end CI pipeline for an application, we need to start with cloning the code from the code source repository. Jenkins supports many source code management systems. With the GitHub plugin, we can integrate with each one of our GitHub repository through the GitHub API. Let’s add GitHub credentials for cloning repositories.
First, we need to generate a GitHub token to use with the GitHub API to ensure the GitHub account has administrative rights to the repos. From your browser, go to GitHub and ensure you are logged in with the account you want to use. Then, visit the Settings
page, then select Personal access tokens
from the sidebar. To the right, click Generate new token
. In the form, set the relevant permissions to enable the hooks to work properly in Jenkins by giving the hook a name, check repo
and then clicking Generate token
. Copy and save the generated key.
From your browser, click Manage Jenkins
then click Configure System
. Under GitHub Plugin Configuration
, click Add GitHub Server Config
to add credentials. Click Add
next to the Credentials
dropdown. From Add Credentials
view, select Secret text
from the dropdown. Set Scope
to Global
and paste the GitHub token in Secret
text field. Provide a description, for example github jenkins
. Then click Add
. Now the Credentials
dropdown should be set to the Jenkins Credential we just created. Click Verify credentials
to verify connectivity. Click Save.
Installing Git on Jenkins
Since we are using git to clone our repo to Jenkins servers and we are using git to push to our Dokku test environment, we need to install git on Jenkins servers. First ssh into Jenkins master VM:
Once logged into the Jenkins VMs, run the sudo apt-get install git
to install git.
Creating a Jenkins Job
Now let’s setup a new Jenkins job for our Node.js project. From your browser, click New Item
, provide a name for the job, for example nodesample
, select the Freestyle project
option. Then hit OK. In the configuration page, check the GitHub project
box, then for Project url
, provide the http url to your Node.js app GitHub repo. Under Source Code Management
, select the Git
radio button. For Repository URL
, provide the http url to your Node.js app GitHub repo.
Next, make sure to check the Build when a change is pushed to GitHub
option as that will automatically trigger this job to run whenever a change has been commited to the master branch of the GitHub repo. Click Save.
Now go ahead and checkin some changes to your repo. You should see this Jenkins job automatically running as soon as you do a git push
.
Setting up Node
To build and test Node.js applications with Jenkins, we need to configure the NodeJS plugin to build applications against different versions of Node. It also handles the installations and writes Jenkins scripts in Node. From Jenkins, click Manage Jenkins
and Configure System
. Under NodeJS
section, click NodeJS installations
. For NodeJS Name, provide a value so you can easily refer to it in a job. Check the Install automatically
box, click Add Installer
dropdown to select Install from nodejs.org
. Select NodeJS 5.5.0
for Installation
. Leave npm packages empty, since we will build dependencies locally for each job. Click Save.
Note: If you are using Jenkins 2, the UI is a little different. You can find
NodeJS
configuration settings underManage Jenkins
andConfigure Tools
.
Now from Jenkins, let’s configure our job to use a specific Node installation to build the application.
From your browser, click the job for your Node application, for example nodesample
. Scroll down to Build Environment
and check Provide Node & npm bin/ folder to PATH
. Then, select the desired Node installation to build this application.
To test our installation of Node, let’s build our Node app on Jenkins. Scroll down to Build
section, click Add build step
. Let’s confirm the Node and npm versions and let’s execute npm install
to build the app. Click Save.
Let’s build this job by clicking Build Now
. To see the output of this job, click on the running instance and Console Output
. The output should contain something like the following:
Exposing Build Badges
Build badges can be added to your Github readme.md and elsewhere that indicate the state of the build. From your browser, click Manage Jenkins
then click Configure Global Security
. Under Authorization
and Project-based Matrix Authorization Strategy
, in the matrix table, for the Anonymous
user, check ViewStatus
under the Job
category. Then Save.
To get the build badge for our application, from Jenkins, click into the job for our application. Click the Embeddable Build Status
icon in the project sidebar to reveal embeddable markup. Copy and paste the relevant format for your readme file. Make sure to copy the unprotected markup so it can be accessed anonymously.
Now add the badge status markup to the top the README.md
file in your node.js sample app. Commit your changes and git push origin master
. This will kickoff the job we just created in Jenkins and the real-time status of the current build will be visible on the main page of your GitHub repo.
Configuring Jenkins to Deploy to Dokku
Recall from the previous deploying app module, before we could git push
our app to Dokku, we had to create and add an SSH key for deploying apps to Dokku. Now we need to do the same for the Jenkins user.
Creating SSH Key for the Jenkins User
Before you can push anything to remote git on Dokku, we have to first create a pair of SSH key to be used for pushing apps to Dokku. SSH into the Jenkins server with the jenkinsadmin credentials. Then su jenkins
to run the following commands as the jenkins user. Note, run the following without passphrase to avoid password prompt later. The resulting key pair will be generated in your current directory.
Adding a Deploy User for Jenkins to Dokku
Now let’s use the key you just created to add a new deploy user to Dokku. To add the new key, we need the old key to ssh into the dokku VM. Copy the dokku
key we generated from the provision platform module to the jenkins user root directory. Then run the following:
Configuring Job to Push Updates to Dokku
From Jenkins in the browser, click the job you have created previously for the node.js app. Click Add build step
to add the following commands to the Execute Shell
section after npm install
.
What is this script doing?
First we use git
to checkout the latest code from remote master. Then we check if dokku remote already exists, if not, we add dokku remote with git remote add dokku dokku@<DNSNAMEFORPUBLICIP>.<LOCATION>.cloudapp.azure.com:hackathon-starter
. Note, once dokku remote has been added, you do not need to re-add it. Before the job can git push -f dokku master
, we need to add the ssh key to the running ssh-agent for the Jenkins user with ssh-add
. Finally we push the latest to dokku master.
Now go ahead and commit some changes to your node.js app repo. This will kickoff the Jenkins job we just updated. To see the output of this job, click on the running instance and Console Output
. The output should contain something like the following: