CI/CD, Jenkins, Containers, and Microservices | A Hands On Primer

12b13-1xypbv2yj1zraow5d-ifywg.jpeg

This post is the first in a three part series on Continuous Deployment and Continuous Integration with Jenkins, containers, and microservices covering installation, general configuration that works for most use cases, and finally some advanced techniques that demonstrate some of the possibilities Jenkins provides for an enterprise CI/CD environment.

But before we dive into Jenkins, what is CD/CI, why is everyone talking about it, and why do I need it?

Continuous Integration is the practice of using technology to automate the process behind ‘checking in’ new source code to a project. If you’re a developer, the benefits are likely obvious. Imagine a manual build process, which may include new contributions from several developers at a time. What if any of the unit, functional, or integration tests fail? How would you quickly know which commit introduced the discrepancy without some extra effort (meaning time, which at the end of the day means money, and lower operating efficiency)? How would you then go about communicating to that developer that her/his code has an issue? This all seems like needless work, doesn’t it? Instead, imagine that upon every new contribution to the codebase, the entire testing suite is automatically kicked off, a failed test results in instant feedback to the developer, let alone the rest of the team that may depend on the status of the build. Developers could be on completely separate time zones, and an unstable build may directly equate to downtime. Needless to say, it’s hard to raise an argument against the CI practice, can you think of one?

From a business perspective, this means developers are empowered to understand and fix errors more quickly, it means confidence in real time about the current build being a release candidate, and it means the turnaround time between shifting customer demands and delivery to market is faster, more reliable, and easier. While it may not be easy to calculate ROI on roughly a reformed business process, common figures consistently claim an incredibly significant 20–30% increase in development.

Continuous deployment, building from continuous integration, is the practice of making stable builds available immediately to other teams that may need them to maintain productivity, i.e., QA. With QA as an example, this means each stable commit is available to QA incrementally, allowing QA to focus on more creative use cases and testing, knowing that automated tests have already been completed.

This ultimately means the QA budget goes further where it really counts, with more confidence against regressions, and better integration between departments. Both practices fall under the general term DevOps, loosely defined as a relationship between development and operations, centered on fostering better communication, collaboration, and integration between business units through automation tools and culture.

Enter Jenkins, a popular and very capable open-source automation platform designed to be simple, intuitive, modular, and flexible.

Installing Jenkins is a straightforward process, the following are a few examples of technical steps needed to install and deploy Jenkins in an organization.

Prepping for Jenkins On Ubuntu 16.04

Ubuntu from Canonical has become a popular and user friendly release of Linux, and it a good candidate for base tutorial. Installations on other distributions will follow, but will focus on the deviations from the base steps outlined here.

By default, the upstream repository containing Jenkins is not included in the sources list used in Ubuntu, so it must be added, and a few pre-requisites need to be met. Though there are a few different methods on exactly how to install out there, I have had the most luck with the following:

1. In a terminal, add the add-apt-repository module.and with administrative privilege:

$ sudo apt-get install python-software-properties

2. Add the appropriate source to the apt repository and enable apt to directly pull from the Jenkins project.

$ sudo add-apt-repository ppa:openjdk-r/ppa

3. Update all repositories and metadata:

$ sudo apt-get update

4. Since Jenkins runs in Java, install the latest Java Development kit. Many tutorials omit this step, which can lead to an unresponsive Jenkins instance, without explicit errors being logged. This is an infuriating situation and can be difficult to solve without many hints, other than an error about Hudson permissions needed, but not available, when observing a raw HTTP response. If you have encountered this situation and are reading this, hopefully it has been helpful.

$ sudo ‘apt-get install openjdk-8-jdk5. Run wget to add a new GPG (GNU Privacy Guard, built upon PGP keys), to the system as a trusted decryption key. This command does a host of things; making a quiet request to the specified URL, piping the output to standard out, and piping the result into sudo apt-key add command, accepting input from the output stream of the previous command.
$ sudowget -q -O — https://pkg.jenkins.io/debian-stable/jenkins.io.key | apt-key add –

5. Append the deb {URL} to the /etc/apt/sources.list file, adding the package location to apt:

$ sudo echo ‘deb https://pkg.jenkins.io/debian-stable binary/’ | tee -a /etc/apt/sources.list’

6. Refresh the upstream package data once more.

$ sudo apt-get update

7. You can now install a clean version of Jenkins on the system.

$ sudo apt-get install Jenkins

8. Now that Jenkins has been installed, there are a few other steps that should be verified to ensure users can access the appropriate web interface. First, ensure the process is running by executing the command, verifying this command exited cleanly.

$ sudo systemctl start Jenkins

9. Verify that the process has opened a network socket on the system. and confirm an entry for tcp6 ::8080, which is the default port Jenkins is configured to listen on.

$sudonetstat -ant

Should another program already be running on 8080, edit the configuration file to instruct Jenkins to use an unused port instead. The file can be found at /var/lib/Jenkins/config.xml.

10. Ensure that any running firewall is configured to permit tcp traffic on the chosen Jenkins port above. If using ‘ufw’, and the web interface is unreachable, execute:

$ sudo ufw allow 8080’

If using Iptables, the command:

$ sudoiptables -A INPUT -p tcp –dport 8080 -j ACCEPT’

11. Upon first connection, a web page with instructions to Unlock Jenkins, and a form to accept a token will be presented. As per the instructions, copy the contents of /var/lib/Jenkins/secrets/initialAdminPassword into the web form, and submit, to unlock the server. If successful, the next window will present the option to install a suite of common plugins, or to manually select which plugins. For the purposes of this tutorial, select ‘Install Suggested Plugins’, as this will include the Pipeline assets that we’ll use in Part 2 of this tutorial.

Prepping for Jenkins On RHEL 7:

Installing Jenkins on Red Hat Enterprise Linux follows the same basic requirements and process, and may be even more straightforward.

  1. With administrative privilege, execute the following in a shell:

$ sudowget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo

This command outputs the return of the URL into a file located at /etc/yum.repos.s/Jenkins.repo.

2. Import and trust the Jenkins GPG keys for the Jenkins repository, and finally:

$ sudorpm — import https://jenkins-ci.org/redhat/jenkins-ci.org.key

3. Install Jenkins from the yum repository.

$ sudoyum install jenkins

3. As with Ubuntu, it may be necessary to configure the software firewall to allow the incoming connection to the Jenkins instance, and one way to achieve this may be executing the following commands:

$ sudo firewall-cmd — zone=public — add-port=8080/tcp –permanent
$ sudo firewall-cmd — zone=public — add-service=http –permanent
$ sudo firewall-cmd –reload

Prepping for Jenkins On Docker:

In much the same way the virtualization revolution has changed the way organizations manage their systems, containers have taken the idea a step further, virtualizing an imagine and it’s associated dependencies, without the need to also support a host operating system as well, solving many challenges associated with scaling, licensing, and hardware requirements. Docker is a leader in container technology, and many organizations and users have already adopted it’s use.

If this describes your organization or your workflow, then installing Jenkins and managing the image through Docker is as simple as running a command or two. Installing Docker is outside the scope of this article, but should you already have Docker installed and tested working, execute the following to pull the latest Jenkins image from the officially supported Docker repository:

$ sudo docker pull Jenkins’ 

Map a local network socket and data directory to the containerized machine. this example arbitrarily uses port 49001 locally to the host and /jenkins, to map to port 8080 and the containerized /var/jenkins_home directory on the image.

$ sudo dockerrun -d -p 49001:8080 -v $PWD/jenkins/:var/jenkins_home:z -t jenkins

Prepping for Jenkins On OpenShift 3.5:

In environments that already use PaaS services such as Red Hat OpenShift, the process is fundamentally different than installation on an operating system in a bare metal deployment. OpenShift combines the power of Kubernetes, Docker and an included internal Docker registry, and a virtualized software-defined network to enable communication between virtualized ‘containers’, that host one or more microservices, working together to power an application. In this case, it is necessary to instead deploy a Jenkins container, that is, a virtualized image of a platform that contains a running instance of Jenkins onto the platform, and exposing a route in the form of an URL to allow management.

Fortunately, the process is fairly simple. The container that powers Jenkins will communicate with the OpenShift master API, and will run as a service account. This account will need elevated privileges on the project that it will work within. To grant administrative privilege to the ‘default’ service account, execute:

$ sudo oc policy add-role-to-user admin system:serviceaccount:{your project name here}:default

The project name can be discovered by executing oc get projects when in doubt.

To verify the role was assigned successfully, execute:

$ sudooc describe poliyBindings :default

You should expect output to indicate the role of ‘admin’ assigned to the default service account.

Creating the container itself can be accomplished with a simple oc new-app command. A completely arbitrary example via CLI is as follows:

$ sudo oc new-app jenkins-persistent -p MEMORY_LIMIT=2Gi -p VOLUME_CAPACITY=2Gi -p ENABLE_OAUTH=false

At this stage, the container is being created and deployed into the cluster. verify that the pod has been created, and is running. Repeat as needed until the above is verified.

$ sudo oc get pod

Sometimes the deployment can fail, and when this happens, the most common cause is the initialization process exceeded the allowed time set by the liveness probe for the Jenkins template (this is similar to a heartbeat, for those familiar with this concept in networking). If this is the case, increase the default value of 120 seconds to a larger value and attempt the process again.

$ sudo oc set probe dc Jenkins –readiness –initial-delay-seconds=500

Once the Jenkins pod is deployed and running, use a browser to access the management interface. To do so, determine which route has been assigned to the pod by executing:

$ sudo oc get route

Observe the output. Take note of the URL and port, and log in with the default credentials of u.’admin’,p.’password’. You should now have a fully functional Jenkins instance deployed within the OpenShift container environment.

Conclusion

Installing Jenkins is a very easy process. There are multiple options for administrators to deploy an enterprise Jenkins environment from bare metal to containers. Stay tuned for Part 2, where we’ll create a rudimentary pipeline project, getting Jenkins off the ground and working for your organization.