CI/CD with Jenkins – evaluation

Jenkins Evaluation happened January 2021 and I believe that Jenkins is still improving. This post is supposed to be part of the bigger series with a unified structure.

Overview:
Pipeline definition completely lives in GIT together with code ~> Jenkinsfile
– Support for jenkinsfile via graddle DSL
You can chain the pipelines
– Single pipeline triggered on various branches ~> Multi-branch pipelines (tutorial)
Parallel pipeline stages
– Access to build meta-data (e.g.  build-number, commit hash, …)
Jenkins as a code plugin
– Managing secrets via secrets plugin
Audit trail plugin
Try notifier
– Better UI with Blue Ocean
– Tooling – Jenkins Job Builder (Job builder tutorial)
Pull-request Jenkins pipeline
– Deployment topology – master x slave/agent
Jenkins Helm deployment – seems has autoscaling agents – based on Configuration as a code plugin
– Manual approvals – seems as not so straightforward via input option
Jenkins on Google Kubernetes Engine

Security model:
– Default has no roles – all has single view -> plugins
GitHub OAuth and here
Role base authorisation plugin –  (strategy plugin – role) – that probably doesn’t work together with gitHub OAuth, but can work with Matrix access

Resources:
Jenkins for beginners

Summary:
Jenkins – one of the most popular open source CI/CD systems. Necessary to be self-hosted. But even Kubernetes plugin seems to have agent autoscaling capabilities which should be cost effective. Seems that whole Jenkins configuration can be bootstrapped from code. 

Security model has various options not sure how all fits together e.g. gitHub OAuth + Roles and Securities but there is multiple ways e.g. control matrix. 

Has concept of pipelines and jobs. Pipelines are next generation where they live completely in code-base ~> LTS should be ok. Seems that have some basic manual approvals stages, question how that goes together with auth. Has concept of multi-branch jobs/pipelines = single definition for whole bunch of branches where definition is dynamically taken from source. 

CD capabilities are somewhat simplistic – no advanced release strategies. Like roll back, monitoring etc. That would need to be scripted probably.

Build Number

One of the most important thing during the SDLC (for sure apart from the other stuff) is to keep control over deployed artifacts to all environments at any given time. Lack of control leads to chaos and generates a lot of extra work to the team, degrades throughput, morale and motivation. No need to even mention that arguments among team members regarding deployed features or fixes definitely do not contribute well to the team spirit.
One of the common approaches mitigating this risk is generating a build number to every single build fully automatically. Let’s take a look at how to accomplish this in common project set up – maven project build on build server e.g. TeamCIty. Sample web application follows.
Common place where to store such kind of info is MANIFEST.MF file. All kind of archives have this file located in /META-INF/MANIFEST.MF. Various technologies like OSGi use this location for various metadata. Taking advantage of maven-war-plugin the content of MANIFEST.MF can be easily customized as follows (${xx} are maven variables):
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven
Built-By: ${user.name}
Build-Jdk: ${java.version}
Specification-Title: ${project.name}
Specification-Version: ${project.version}
Specification-Vendor: ${project.organization.name}
Implementation-Title: ${project.name}
Implementation-Version: ${project.version}
Implementation-Vendor-Id: ${project.groupId}
Implementation-Vendor: ${project.organization.name}

To set up a maven project pom file is pretty easy:


org.apache.maven.plugins
maven-war-plugin

true
true

${build.number}

Where build.number variable gets supplied by build server in arbitrary format, e.g. for TeamCity build server:

Build number is visible in build queue status page as well:
To access these project build specific information simple jsp page can be created:
The controller accessing these information using Spring MVC (simplified example) can look like:
@Controller
public class ProjectInfoController {

    @RequestMapping("/info")
    public ModelAndView getProjectInfo(HttpServletRequest request, HttpServletResponse response) throws IOException {

        ModelAndView modelAndView = new ModelAndView("projectInfoView");

        ServletContext servletContext = request.getSession().getServletContext();

        Properties properties = new Properties();
        InputStream is = servletContext.getResourceAsStream("/META-INF/MANIFEST.MF");

        properties.load(is);

        modelAndView.addObject("buildBy",properties.getProperty("Built-By"));
        modelAndView.addObject("buildJdk",properties.getProperty("Build-Jdk"));
        modelAndView.addObject("specificationVersion",properties.getProperty("Specification-Version"));
        modelAndView.addObject("specificationTitle",properties.getProperty("Specification-Title"));
        modelAndView.addObject("implementationVendor",properties.getProperty("Implementation-Vendor-Id"));
        modelAndView.addObject("buildNumber",properties.getProperty("Build-Number"));

        return modelAndView;
    }
}

Accessing MANIFEST.MF in JAR file has a different approach. Motivation taken from Spring source code:

Package  package = someClass.getPackage( );
String version = package.getImplementationVersion();

JSP page or other presentation layer shouldn’t be a problem for anyone.