Jenkins Tips and Tricks
Use Jenkinsfiles and keep your CI/CD process versioned with your code
Jenkins makes it easy to version the workflow you used for your integration and deployment processes. Just put a file named ‘Jenkinsfile’ in your projects’ root, and then create a new ‘Pipeline’ item in the Jenkins UI, setting up the item to pull from your projects’ git repository.
A simple example of a Jenkinsfile might look something like this:
Which, admittedly, is full of assumptions that we’ll not cover here. However, this example is ripe for customization and adaptation to more complex requirements!
For example, if you had both a frontend and a backend to test and package and deploy, you could make each of the stages run their steps in [parallel] to leverage Jenkins’ management of multiple workers and multiple nodes.
Leveraging Jenkins Nodes
Perhaps during your deployment phase you want to build a docker image, and then push that to a registry. Additionally, perhaps you'd prefer to have these tasks isolated to their own machine.
This is relatively easy to do -- Jenkins does not have demanding requirements on new nodes. A user, SSH credentials, and a remote root directory for Jenkins to operate within is roughly the minimum requirements. Jenkins can then handle connecting to the server via SSH, and installing/executing the necessary services for accepting and running jobs.
On a node dedicated to building docker images, you’d need to additionally install, at least, Docker.
From there, your “Deploy” stage might change to look something like:
With the ‘agent’ section, this configuration specifies that the stage should only be run on nodes that are labelled with ‘docker-builder’ (which will presumably mean they are capable of building docker images).
This becomes an extremely powerful remote job executor that gives you the potential ability to provision Jenkins nodes for all sorts of specialty purposes, without having to install and manage a totality of configuration on each node.
A note about strings…
Jenkins has some ‘interesting’ idiosyncrasies when it comes to strings. This gist summarizes them in the most succinct and useful way:
For reference, here is a screen shot:
For all the amazing things Jenkins enables, it still has a couple dusty, dark corners.
Jenkins provides a ‘post’ section that allows for further action to happen under certain circumstances. For instance, when a build regresses (goes from a success condition to a failed condition) or becomes fixed (goes from a failed condition to a success condition), perhaps an (HTTP) API should be called to notify the appropriate people.
This might look something like:
Of course, there are many more options here. You could use any number of conditions a job could be in after it is run, and perform any number of actions.
Jenkins provides a mechanism for storing secrets, and providing those secrets conditionally to the jobs it runs.
For instance, perhaps you have a custom pypi repository that you’d like to supply credentials to each time you interact with it (as opposed to storing the credentials in your .pyprc, for example). First, you’d add the credentials to the Jenkins Credentials system as a username and password.
And then you’d want to specify the credentials as an environment variable for a stage, and reference the variable in the various steps you might run. Let’s use the ‘Package’ stage as an example:
The credential manager isn’t limited to just passwords either. It can manage SSH certificates, as well as miscellaneous secret files and text. For example, what if you needed to install a certificate and key for connecting to a service inside a docker image?
You might do something like:
And then the ‘Docerfile.prod’ might include lines for ‘ARG secretkeypath’ and ‘ARG secretcertpath’ so that it could then issue the likes of ‘COPY $secretkeypath /secret.key’ commands and store the secret to a file inside the image.
Jenkins is a powerful utility for continuous integration and deployment, and this article has only touched the surface of what it is capable of.
By Joel Kleier | Senior DevOps Engineer | November 21, 2019