This article gives an overview of both Jenkins and Docker. It also includes a tutorial on how to configure Jenkins on Docker.
Jenkins is an open source, self-reliant automation server initially developed for the implementation of continuous integration (CI), a development practice. From Jenkins 2 onwards, there has been an exceptionally abundant plugin ecosystem to integrate with the toolchain already in use in an organisation. This enables Jenkins to not only go beyond CI but also implement various other practices such as continuous code inspection, continuous delivery, continuous testing, continuous deployment, and so on. Practically, this tool can automate almost all the steps followed in the practices mentioned and their tools, in the desired order. It wraps up all the tasks in a particular sequence and divides them into various DevOps stages known as the pipeline. Thus, it promotes end-to-end automation of the IT life cycle.
Jenkins is a Web server application that can be deployed as a servlet in a Java servlet application/container server such as GlassFish, Wildfly, IBM WebSphere, and so on. Jenkins also provides a built-in Jetty server, a Java servlet application server, to run as a standalone server. In order to have a Jenkins setup running on a system, the only thing required is the Java 8 Runtime Environments (JRE 8). The minimum hardware requirements are 256MB of RAM and 1GB disk space, whereas the recommended requirements are 1GB or more of RAM and 10GB or more (as per the scale of the project) of disk space.
The language in which Jenkins is written is Java, which makes it easier to design for installing/running it on various operating systems such as MacOS, Windows, Linux and their different flavours such as Ubuntu, Red Hat, Debian as well as platforms like Docker, Microsoft Azure, AWS EC2, etc.
Jenkins started out as a simple CI server and advanced the application life cycle of software organisations by means of automation. It comes with a lot of features and even has the provision to add more, with the help of plugins. Listed below are some of the features Jenkins has to offer:
- Easy to install
- Open source
- Easy to configure
- Supports customisation and extensibility
- Abundance of plugins with well-defined documentation
- Creates custom plugins
- Supports build pipelines
- Facilitates Pipeline as a Code (Blue Ocean)
- Supports Slack/email notifications
- Cron scheduling
- Provides master-agent architecture for distributed builds
- Faster updates
- User interface is simple and clear
- Role based access
- Supports promoted builds
Jenkins, as a standalone server operating on a single machine, can deliver services to a certain extent only. The quality of service it renders depends on the resources of the machine it is running on.
However, some projects require different platforms and environments to build certain stages. Also, to test those different builds, different environments are essential. Let us look at some examples of such environments:
- One project requires JDK 1.7 but the other project requires JDK 1.8.
- Two different Android projects require distinct versions of a build tool (e.g., Gradle 4 and Gradle 4.6).
- Similarly, several iOS projects might depend on different XCode versions.
Likewise, when a platform is considered, iOS development projects have a dependency on iOS machines, Windows environment on .NET, and some might require the Linux environment.
Thus, a single machine cannot fulfil all the pre-requisites and dependencies required to build and test the project. A single machine also cannot give efficient service if the project is very large, and requires building and testing on a very frequent basis. Considering these scenarios, it can be concluded that a single Jenkins server is incapable of catering to the diverse needs of projects, business units or organisations.
To deal with the aforesaid limitations, Jenkins Distributed Architecture, which follows the master-agent architecture, has now become an integral part of the Jenkins architecture. The master is where the main Jenkins server is running and the agent is the one which runs on a remote machine. There can be only one master but many agents. There are many ways in which an agent can be connected to the master but, ultimately, they need to have bi-directional communication, and for this the TCP/IP protocol suite is used. Figure 1 depicts the Jenkins master-agent architecture, where there is one master running on a MacOS system, and the three agents connected with it run on different platforms like MacOS, Windows and Linux. For better performance and optimisation, it is considered best if the master node is only used for monitoring and distributing the build jobs among the agents, and doesn’t perform any build on itself. With this, the agents can provide a variety of platforms and environments. Also, the master can have several jobs running on different nodes simultaneously, which not only saves time but also improves the efficiency.
A best practice is a technique or process that is generally considered as surpassing any other method of doing something, as it produces the best possible outcomes in known scenarios. Best practices are followed in every field of work to meet benchmarks and quality standards. Jenkins best practices result in a better sense of how Jenkins plays a crucial role throughout the project life cycle for software developers and senior management. Some of the best practices that should be followed while using Jenkins are listed in Table 1.
In the next section, we will understand the basics of containers.
Docker is an open platform to develop, deploy and run applications within containers. The use of containers allows the developer to build, test and deploy faster in an isolated environment and separate the application from the host’s environment.
People often get confused between containers and virtual machines (VMs). Both have the same objective — to isolate the application from the host machine and provide its dependencies in an independent module. When Linux containers are used to deploy an application, it is known as containerisation, which is gaining popularity for the reasons listed in Table 2.
Now, as we have a basic idea about Docker and containers, we shall explore the underlying abstraction of Docker, bit by bit.
When a Docker container is completely designed and is stable to run, this container image can be published to the registry. The registry can be public or private — Docker provides its own registry known as Docker Hub. This enables the Docker hosts to pull the image from the registry and run it on their system. As discussed, the Docker host only needs the Docker image’s name and its tag.
Jenkins on Docker
Configuring a Jenkins master on Docker: Before we spin up Jenkins on Docker, we should have Docker installed on our machines.
- Docker can be installed on Mac, Linux and Windows OSs.
- If the machine is running on Windows, then it should be either Windows 10 Pro or the Enterprise version, because the other versions of Windows lack Hyper-V support.
Once Docker has been set up on the machine, we can execute Docker commands. Let’s run some Docker commands and check the version, and see if any containers exist.
The commands are:
Version – docker –version Containers – docker ps -a
In Figure 3, the version has been displayed and there are no containers running in the Docker system.
In order to spin up the container, this image needs to be downloaded first. The image can either be downloaded using the docker pull <image_name> command, or this can be done directly using the docker run command and mentioning the image name. This will check the Docker images, and if the image is not available, it will be downloaded.
As I have already downloaded the image, I have directly issued the docker run command, as shown in Figure 4. When a Docker image is run successfully, the container is assigned a container ID, which is given as a return value on executing the docker run command.
The command executed is:
docker run -u root -d 8080:8080 -p 50000:50000 -v /home/ajay/Desktop/jenkins_home:/var/Jenkins_home/ -v /var/run/docker.sock:/var/run/docker.sock --name Jenkins --restart always jenkinsci/blueocean
This is a complete one-line command. When docker run is fired, the minimum mandatory argument is the name of the image.
Table 4 lists Docker commands and gives a brief description of each.
The Docker container can be checked using the docker ps -a command. Now, when we check the container, it can be seen with the container details such as its name, id, created time, status, ports (Figure 5).
Configuring a Jenkins agent on Docker
Open a browser and go to http://localhost:8080. The Jenkins server UI will load. Once the initial configuration is done, its home page will look as shown in Figure 6.
Before we continue to set up the Jenkins Docker agent, we need to download the plugin for Docker. Go to Manage Jenkins > Manage Plug-ins > Available. Here, search in the filter for Docker; from the results, download the Docker plugin and click on Install without Restart. Once the plugin is successfully installed, go to Manage Jenkins > Configure System. Scroll down and look for the cloud, as shown in Figure 7.
Add a new cloud and select Docker. Now configure the Docker cloud details and the Docker agent templates. In the Docker cloud section, give a name of your choice. Here, we have given the name as docker-master. In the Docker Host URI section, give the path of docker.sock so as to connect the Jenkins server to the Docker daemon. Check the enabled box so that it is available for use. With this, the Docker cloud/server has been configured. This configuration is shown in Figure 8.
It’s time to configure the Docker agent template. The name for each agent template has to be different. The label can be the same for multiple agent templates, in case a group of agents is for one job and any can be used as per availability. But the Docker image name should be the same as the one pulled or built in the Docker system. This is shown in Figure 9. Jenkins-agent is the name of the Docker image which is built using the Jenkins/agent image. This image is configured with tools as per the application’s requirement. This requirement can differ from application to application.
In the Remote File System Root column, give the location inside the container where it has to store the Jenkins Home data.
This is the most basic configuration of the Jenkins agent using Docker. Finally, apply and save the configuration. Now add a new item, give any project name and select any type of project. We have selected the Freestyle project. While configuring the job, look for Restrict, where the project can be run. Here, enter the template’s name, which we have configured as shown in Figure 10. Configure the job as per the application.