Jenkins tutorial: Get started with Jenkins continuous delivery

How to use Jenkins Blue Ocean and NPM to create a CICD pipeline for a Node.js and React application

Jenkins tutorial: Get started with Jenkins continuous delivery
Stockbyte/Thinkstock

Jenkins is one of the earliest and still one of the most-used continuous integration and continuous delivery (CICD) servers. It has lots of competition these days, but still has a robust community and a wide range of plugins (1,400 when I last checked). Even if you wind up using a different automation server, it is worth understanding how to use Jenkins: The underlying concepts of CICD don’t change much from one implementation to another, even though the vendors do tend to make up their own terminology.

In this article I’ll draw on the official Jenkins tutorials, in particular the one that shows you how to use the new-ish Blue Ocean GUI, but add my own explanations and illustrations for steps and code that may be obscure. My goal is to get you to the point where you can create build, test, and delivery pipelines for your own projects.

Jenkins and Docker installations

As a matter of convenience, the Blue Ocean tutorial runs Jenkins in a Docker container. Before you can run the Docker command that will launch Jenkins, you need to have Docker installed and running.

docker install IDG

If you need to install Docker, browse to the Docker site, click on the Get Docker dropdown at the top as shown above, and click on the menu item that matches your operating system. All you need for the purposes of this tutorial is the current stable community edition, which is free.

Now you need to run the Docker daemon, if it isn’t already running. If you installed Docker for Mac or Docker for Windows, you can tell that Docker is running by dropping down the menu from the Docker icon in the menu bar on MacOS or the taskbar on Windows, as shown below.

docker menu IDG

Then you will control Docker from a shell prompt. For the Bash shell on MacOS or Linux, back-slash characters (\) denote line continuations. In a Windows cmd shell, circumflex characters (^) perform that function. Another difference between Unix shells and Windows shells is the syntax for the HOME environment variable, which is ”$HOME” in Unix and ”%HOMEPATH%” in Windows.

The command to run the Blue Ocean Docker image in a Bash shell is:

docker run \
  —rm \
  -u root \
  -p 8080:8080 \
  -v jenkins-data:/var/jenkins_home \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v “$HOME”:/home \
  jenkinsci/blueocean

This command maps the container’s port 8080 to the host’s port 8080, and maps the /var/jenkins_home directory in the container to the Docker volume with the name jenkins-data. If this volume does not exist, then this docker run command will automatically create the volume for you. It also maps the $HOME directory on your local machine (usually the /Users/<your-username> directory) to the /home directory in the container.

The Windows version of this command has the changes we discussed in the continuation characters and the HOME environment variable.

In the terminal output after running the docker run command, there is a message about “Jenkins initial setup” that includes a long hexadecimal password, which you can copy and paste into the unlock screen in your browser at http://localhost:8080. Then you can select your plugins; for the purposes of this exercise, the suggested plugins will be fine. If any plugins don’t install correctly the first time, use the retry option—don’t try to continue with errors.

Finally, you’ll create a new administrator and restart Jenkins, following the prompts. You may then have to refresh your browser to get to the login page, where you should enter the administrative credentials you just created. You should then see the Jenkins dashboard, with Open Blue Ocean shown as a navigation menu item at the left.

jenkins welcome IDG

Note that you can always terminate Jenkins by typing Control-C into the shell that you used to start Jenkins. You can restart Jenkins with the same docker run command you used to start Jenkins initially, and again browse to http://localhost:8080 or, if you wish to go directly into Blue Ocean, http://localhost:8080/blue. Since the instance has already been unlocked, you should quickly see the login screen.

Before proceeding into Blue Ocean, we’re going to set up the app repository the demo will use in your GitHub account.

Fork the Jenkins sample app repository

Log in to your GitHub account, creating a new free account first if necessary. Then browse to the creating-a-pipeline-in-blue-ocean repo and fork it using the button at the top right, as shown in the screenshot below.

jenkins pipeline repo fork IDG

After a few seconds, during which GitHub will display a progress screen, you should see a linked copy of the repo in your own account. As you can see in the screenshot below, GitHub will remember the original repo you forked, watch it from the forked repo, and let you know if there are any differences between the two repos.

jenkins pipeline forked repo IDG

You can optionally clone (preferred) or download this repo onto your own development machine, which will enable you to view and edit files in a desktop programming editor, such as Visual Studio Code or Atom, as shown in the following screenshot.

jenkins pipeline repo atom IDG

Examine the repo

As you can see in the screenshot above, the React app lives primarily in the src folder. The jenkins folder contains an example of a Jenkinsfile generated by Blue Ocean, although yours may differ somewhat. The jenkins/scripts folder contains heavily commented shell scripts with commands that are executed when Jenkins processes the Test and Deliver stages of your Pipeline. Since the Docker image runs Linux internally, the shell scripts don’t need to have different versions for each host operating system.

Set up the build pipeline in Blue Ocean

If you have stopped your Jenkins container, please restart it. Browse to the http://localhost:8080/blue directory, which is also reachable by clicking on the Open Blue Ocean link from the Jenkins Dashboard. Blue Ocean will quickly forward you to the Pipelines page so that you can create your first pipeline.

blue ocean new pipeline IDG

A Jenkins pipeline is a Groovy-like file (always named Jenkinsfile) that defines builds and other stages for Jenkins and supports a general CICD use case. Blue Ocean can generate new pipelines as well as discover existing pipelines by looking for Jenkinsfiles in repositories.

Click on the Create a New Pipeline button in the Welcome to Jenkins popup menu, or on the New Pipeline menu item at the top of the page. Either one will take you to the Create Pipeline page, which will ask you to choose a Git server. For this exercise, choose GitHub. You’ll see a new step for connecting to your GitHub repository.

jenkins blue ocean connect to github IDG

Click on the Create an Access Key Here link, log into your GitHub account, enter a brief description of the repo, and click Generate Token. Copy the generated token, paste it into the Blue Ocean edit box, and press the Connect button. Then click on the correct organization, pick New Pipeline, choose the creating-a-pipeline-in-blue-ocean repos, and click on Create Pipeline.

jenkins blue ocean create pipeline IDG

Blue Ocean will detect that there is no Jenkinsfile at the root level of the repository’s master branch (and ignore the sample Jenkinsfile in the jenkins folder) and will help you create one graphically when you press Create Pipeline again. Drop down the Agent control and pick docker, then fill in the Image field as node:6-alpine and the Args as -p 3000:3000.

The image node:6-alpine will be downloaded from the Docker repository if not already in your Docker host, and run as a second container, along with the Blue Ocean container. Port 3000 will be mapped out of the Node.js container to the host.

Click on the + button in the main pipeline editor to add a new stage, and call it Build. Then add a step of type Shell Script and type in the command npm install. Click on Save, enter Initial pipeline in the description box, and click Save & Run. Jenkins will show you a progress page for the pipeline; on my laptop this step took almost two minutes to complete.

npm install looks at the package.json file in the root directory of the repository and uses its dependency list to install whatever NPM packages are needed and their dependencies. For this project, as shown below, the list is react, react-dom, and react-scripts.

package.json IDG

If you now view your repo on GitHub and refresh the page, you’ll see the new check-in Initial pipeline with a new Jenkinsfile. You can also do a pull from your local clone of the repo. In my repo, with Jenkinsfile syntax highlighting turned on, the file looked like this:

jenkinsfile IDG

That makes perfect sense. Blue Ocean simply added the information we supplied to its own syntax template for generating pipelines.

If we now click into the Pipeline display we can see the steps we just defined (and tested) for the Build phase, as shown below.

jenkins blue ocean pipeline display IDG

You can see the actual terminal logs by clicking into any of the steps. Note that the npm install step generated more than 1,000 lines of output, mostly dependencies for react-scripts.

Add the test and delivery stages

Now click the X at the top-right to go back to the main Pipelines console. Click into Branches, and click on the pencil-shaped edit icon at the right to add a stage named Test. Then add a Shell Script step containing ./jenkins/scripts/test.sh, and click the left arrow above (next to Test / Shell Script) to go back to the stage editor. Click the Start icon at the left, and add an environment variable CI with the value true. Save the pipeline, committing the new stage with a description of Add Test stage by clicking Save & Run.

If you look at your GitHub repository, you’ll see that the Jenkinsfile has been updated with two new sections. On my laptop, running the test script took about 40 seconds, and the test passed.

jenkins blue ocean test stage IDG

Now we need to add a Delivery stage. Once again, click Branches at the top-right to access your repository’s master branch, click the pencil icon to edit the pipeline, and click on the + icon at the upper right to add a stage named Deliver. Then add a Shell Script step that contains ./jenkins/scripts/deliver.sh.

Now add a Wait for interactive input step with a message of Finished using the website? (Click “Proceed” to continue), and go back for a final step. This one is another Shell Script step that contains ./jenkins/scripts/kill.sh. Save the pipeline and commit it with a message of Add deliver stage by clicking Save & Run.

Now Jenkins will execute the build and test stages and also spin up the website. When Jenkins shows you the ‘Finished using the website? (Click “Proceed” to continue)’ message, browse to http://localhost:3000 to see the React site. It should look something like this:

react welcome IDG

Then click on Proceed to kill the React server.

The final Jenkinsfile should look like this:

jenkins final jenkinsfile IDG

That’s a wrap. You can Control-C out of Jenkins now, and quit the Docker daemon.

One useful thing we haven’t done in this tutorial is to trigger Jenkins pipelines from all GitHub check-ins in a repository, as opposed to only check-ins made from Jenkins.

To accomplish that, you need to tell Jenkins to build when a change is pushed to GitHub (it’s a checkbox) and add a webhook in GitHub with the Jenkins URL. Unfortunately, GitHub would need to be able to reach the Jenkins instance to set that up, which isn’t easy if you are running Jenkins in a Docker container on your local machine.

Sure, you could buy a static IP address from your ISP, poke a hole in your firewall for Jenkins, and run your Jenkins container any time people are working on your project. That’s probably more trouble than it’s worth. If you set up Jenkins in a cloud container or server with a public IP address, however, this isn’t hard. You can test this for free by installing Jenkins in an AWS t2.micro instance, or pretty much any free cloud VM.

Copyright © 2017 IDG Communications, Inc.