The course is part of this learning path
This course introduces you to Jenkins, a popular open-source tool used to perform Continuous Integration and Continuous Delivery.
We spend time early on reviewing the key Jenkins features and associated terminology. We then take you through a deep dive in configuring Jenkins to perform automated builds using the Jenkins web administration console in hands-on demonstrations, ensuring that you become familiarised with Jenkins and how to administer it. We’ll demonstrate features such as:
- Installing and setting up Jenkins
- Creating and configuring pipelines manually
- Creating and configuring pipelines using a Jenkinsfile
- Triggering build pipelines, manually and automatically
- Navigating downstream and upstream build projects
- Connecting to version control repositories such as GitHub
- Setting up build pipelines for Java-based projects using Gradle
- Recording artifacts and test results
What you'll learn:
- The basic principles of build automation as implemented within Jenkins and how should be applied to manage and maintain building, testing, and deploying your own enterprise software projects
- How to install, setup, and configure Jenkins pipelines
- The key differences between Jenkins declarative and scripted pipelines
- How to manage build artifacts and test results
- How to integrate and leverage 3rd party build tools like Gradle, Maven, Yarn, Webpack, and many more within a Jenkins pipeline
This training course provides many hands-on demonstrations where you will observe first hand how to use Jenkins to build and release different types of software projects, for example:
- Building a back end application developed using Java, Gradle, and Docker, requiring Jenkins to compile the source code, packaging it into a WebArchive file, and then finally releasing it into a Tomcat based Docker image complete with Splunk based instrumentation for logging and monitoring
- A basic understanding of CICD, or Continuous Integration and Continuous Delivery
- A basic understanding of software development and the software development life cycle
- A basic understanding of version control and associated workflows
- Software Build and Release Engineers
- Software Developers
- DevOps Practitioners
The following supporting Jenkins documentation is available online:
- [Instructor] Okay, welcome back! In this demonstration we're going to create another scripted pipeline.
This time we'll call it BuildJob6. So we click on new item, BuildJob6. It's going to be a pipeline project and this time we're going to build an existing GitHub repository at this location. So https://github.com/cloudacademy/devops-WebApp. Now this particular project is a Java Servlet based WebApp and it uses Gradle for Build Management. So if you're unfamiliar with Gradle, Gradle is a build tool and the same since is Ant or Maven, however what differentiates Gradle is the fact that it is very much designed to be a programming language for doing building, whereas the likes of Ant and Maven use a declarative approach to configure the build. So back within our repository, if we take a look at the build.gradle file, this contains the core Gradle configuration.
So a couple of key things here. Under dependencies we list all of the dependencies that are required for both compilation at build time, and also for the system or the WebApp to run at runtime. So here you can see we've got 3 runtime dependencies. The first is log4j, the second is an XML processor, and the third one is a docker library that allows us to interrogate runtime attributes of their docker container. So when we build this project, we're actually going to eventually deploy it into a docker container.
Okay, going back to the root of the repository, we'll never get into the source file, and to main, and onto the WebApp directory. In the WebApp directory we have a single DockerServlet.java source file, and this particular docker servlet class, all it's doing is extending the HTTP servlet framework class. If we have a look at some of the code we set up the ability to interrogate the docker runtime, and finally we query for the container Id, and the container private IP address. We then examine the path that the user queried for in their browser, if it's the home path we retain a dispatcher for response.jsp, otherwise if it is action1, we log out the fact that action1 is being called and we just write to the response stream. Similarly we do the same for action2, and likewise the same for action3. Okay, let's jump back into Jenkins. We scroll down. We'll specify that our build job is a GitHub project. We'll navigate back to the project root, copy the url We'll paste it. N
ow this time on the Build Triggers we'll do something differently. We'll configure it to be built periodically. So to do so we need to specify a schedule, which is a crontab expression. Now the way we can do this easily is to go to a website called crontab.guru, and here we can specify our crontab expression. In this case we're specifying it to run every fifth minute of every hour, of every day of the month, of every month, and of every day of the week. So if we copy that, go back to the Jenkins, and we'll paste it here. Now before we apply this, there's another best practice that we normally add to our crontab expression, and that is capital H forward slash. Now what the capital H indicates here is that it tells Jenkins to take a numeric hash of the job name and, such that the Jenkins scheduler will use this to ensure different jobs with the same Chrome settings do not all trigger at the same time. So we'll apply this, and then we'll move down to Pipeline. So again for Definition we'll specify that it's a Pipeline script, and here we'll paste in some pre-formatted scripted pipeline code. So we'll go through this now. So again we start off with the node keyword. This tells Jenkins that this is a scripted pipeline.
Within node, our first statement is to set Gradle Home, and the way we do this is we're indicating that we want to use a global tool that is set up for Gradle, that has the identifier gradle-4.10.2. This will set up Gradle Home. In the following command we execute the gradle task command. We then have three stages. The first stage is the Clone stage. It simply runs Git and clones our repository, as indicated by the repository url. The next stage actually does the gradle build. So this is the compilation process. And finally we have the Archive stage. The Archive stage is looking for artifacts that it should archive. In this case it's looking in the build directory that our gradle build command will generate for us. Inside that it looks in libs, and it will look for any web archive files. Okay we'll click Apply again, we'll click Save.
Now we'll kick off a Build, but the expectation is that this will fail because we haven't set up our global tool for Gradle yet, and we can see that that is indeed the case. We'll navigate into the console output and we'll just show you that, so that it's very clear as to what has failed. So, it's looking for a global gradle tool named gradle-4.10.2 so we'll copy this, we'll go back to Jenkins, and we'll know configure this. Click on Manage Jenkins, we'll click on Global Tool Configuration, and we'll scroll down to the Gradle section. Here we click on the Add Gradle button.
Under the identifier, we'll paste in our gradle-4.10.2. We ensure that the Install automatically option is enabled, and then under the Install from Gradle.org we'll set this to be Gradle 4.10.2. We'll click Apply, click Save, and then we return to our Build project. We click on BuildJob6, and this time we click Build Now again. And what we're doing here is we're invoking manually another build, and this time this should work because we've configured the Gradle Global Tool. And as indicated, everything is green, so all three stages, the Clone stage, the Build stage, and the Archive stage have completed successfully. Interestingly, in between the time that we mean to manage Jenkins and set up the global tool for Gradle, our scheduled crontab expression kicked on and triggered an automated build, as indicated by build number two.
What we should see also is that a fourth build should occur in roughly five minutes, so at 8:34. While we wait for that, let's navigate into the last build job, we'll go to Console Output. So here we configured gradle build, the gradle build has performed these tasks. The build has been successful, and we have our standard Finished: SUCCESS message. So we go back to the project dashboard page, and what we also see is that under Last Successful Artifacts we have a BuildJob6-1.0.war, web archive file, that has been captured.
So wait here for a few minutes to see the scheduled build trigger to kick off again. While we're waiting for that we'll jump into our terminal and we'll ssh back into our Jenkins master server where the gradle build has actually occurred. And what we'll do is we'll do sudo apt get install dash y the tree command, and we use the tree command to navigate the associated web space folder, we then change directory into /var/lib/jenkins/workspace/BuildJob6, we'll do a directory listing, and here we can see the build directory that Gradle has created for us. We'll never get into it, and then we run the tree command. And here we can see the structure inside the build folder. So here is our web archive file that Jenkins has captured for us as a artifact.
Okay, here we can see the BuildJob number four has occurred at 8:34, which is five minutes after the last scheduled build job 8:29. The one in the middle was the manual one based on us clicking Build Now.
Okay so let's summarize what we've done. So we'll get back into configure. This time we set up a build trigger using a crontab expression, scheduled to run every five minutes with a hash being taken of the job name, so that the scheduler can spread out similar job names if those job names use the same crontab expression. We then specified our pipeline script, we specified it to use the Gradle Tool configured within the global tool area of Jenkins. We told it to clone our GitHub repository, we performed a Gradle Build on it which resulted in Gradle creating a build directory inside their libs, and populating it with a web archive file that was then archived by Jenkins.
About the Author
Jeremy is the DevOps Content Lead at Cloud Academy where he specializes in developing technical training documentation for DevOps.
He has a strong background in software engineering, and has been coding with various languages, frameworks, and systems for the past 20+ years. In recent times, Jeremy has been focused on DevOps, Cloud, Security, and Machine Learning.
Jeremy holds professional certifications for both the AWS and GCP cloud platforms.