© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2022
P. P. DingareCI/CD Pipeline Using Jenkins Unleashedhttps://doi.org/10.1007/978-1-4842-7508-5_17

17. Jenkins Distributed Builds

Pranoday Dingare1  
(1)
Pune, Maharashtra, India
 

You have learned how to implement various Jenkins jobs as free-style jobs and as pipeline jobs throughout this book. You have seen execution of these jobs by triggering builds, either manually or through some external trigger like Webhooks, SCM polling, etc. To execute these jobs, you used one Jenkins machine that had all the necessary hardware/software requirements. This kind of setup does not help in building a huge application with multiple time-consuming phases. Sequential execution of huge build phases will take a lot of time and ultimately will delay the release of the build. Frequent releases of such time-consuming builds are difficult to trigger and manage too. Another important problem is that you need to have all the necessary software installed on that single machine, which may not be possible due to hardware constraints. If that build machine breaks down, then replicating all the installations on a new build server would be a huge task. Modern applications demand testing to be done on different hardware/software combinations, which will not be possible if you have only one machine taking care of the entire build process.

To solve all these problems, Jenkins comes with a great feature called distributed builds. This chapter explains how Jenkins distributed builds work. It discusses how to set up Jenkins to run distributed builds and how to set up free-style and pipeline jobs to run distributed builds.

Jenkins Distributed Architecture

Jenkins uses a master-slave architecture to manage distributed builds. Let’s look at the master-slave concept:
  • Jenkins master: This is a machine with Jenkins installed on it. This Jenkins instance sends different phases of the build to different machines for execution. This distribution will seldom be based on hardware/software requirements that a particular build phase needs.

  • Jenkins slave: Also called a Jenkins agent, this is another machine with network access to the Jenkins Master. This machine has the Jenkins agent installed and is responsible for executing the build phases assigned by the Jenkins Master. One or more Jenkins slaves can be responsible for executing multiple build phases in parallel and complete the entire build process. An architectural diagram of a Jenkins master-slave is shown in Figure 17-1.

A diagram of 2 T P C Connection of Jenkins Master, which has the windows slave node, and Linux slave node, both boxed.

Figure 17-1

The Jenkins master-slave architecture

Ways to Connect the Master and Slaves

In order to execute the distributed build, the master and slaves need to be connected. There are two ways to do this:
  • Master to agent: In this way, the agents (slaves) are configured to get connection requests from the master. In this configuration, the slave machines need to be minimally configured. They just need to have JDK/JRE installed. The master will connect with the agent machine through a SSH port, copy the remoting.jar on the agent machine, and will start running it using the JDK/JRE available on that machine. Through this remoting.jar agent, the machine will run the Jenkins job. In this case, the master should be able to send requests to the slave machine.

  • Agent to master: If the master does not have access to the agent machines, it will not be able to start the agent process. In this case we need to use a different type of agent configuration, called JNLP (Java Network Launch Protocol). With this approach, you need to set the Fixed or Random radio control for the TCP Port for Inbound Agents option on the Manage Jenkins ➤Global Security page on the Jenkins master machine.

If you select the Fixed option, you need to set a port in the field. This is the port that agents use to connect to the master through JNLP. I am setting this port to 7070. Click the Save button.

Once this is set, you need to open an agent page inside a browser on the agent machine. This will show a JNLP Launch icon. Click that icon to install the JNLP agent and start the slave machine.

Once the JNLP agent is installed, you can install it as a Windows service so that you do not need to start the agent interactively again.

This is convenient when the master cannot connect to the agents because it's outside of the firewall, for example.

Understanding the Configuration to Connect the Master to the Agent Using SSH

This section goes through the step-by-step process to configure the master-slave machines to start the Jenkins agent using an SSH connection. I use two different machines to explain this configuration.
  • Master: the IP address of this machine is 192.168.43.10. This machine has a full Jenkins installation.

  • Slave: the IP address of this machine is 192.168.43.185. This machine does not need a Jenkins installation. It has JDK11 installed.

Step 1: Install the SSH Build Agent's Plugin

Log into Jenkins on the master machine and install the SSH Build Agents plugin using the Plugin Manager.

Step 2: Install Java on the Slave Node

Install Java on the slave machine if it is not already installed. The Java installation steps are outside the scope of this book.

Step 3: Create an SSH Public-Private Key Pair

On the master machine, create a public-private key pair using the ssh-keygen command.

I created a key pair in the default path ${CURRENT_USER}.ssh. I did not specify a passphrase for the key. You can create a key pair at a different location and may provide a passphrase too.

Step 4: Add a Credentials Entry with a Private Key to the Master Machine

Go to the Jenkins dashboard on the master machine. Then go to the Manage Jenkins ➤Manage Credentials menu. The Credentials page will appear.

Click the Jenkins link shown in the Stores Scoped to Jenkins section, which will open the System page.

Click the Global Credentials (Unrestricted) link to open the Global Credentials (Unrestricted) page. Click the Add Credentials menu shown on the left side.

Select the SSH Username with Private Key option from dropdown. Enter the username in the Username field

Note that the Username field should have a username of a authenticated user from the slave machine. The Jenkins master will connect to the slave using the username mentioned in this field. The ID and Description fields can have any value.

Click the Enter Directly radio button. I entered ADMIN into the Username field here. (Remember this name, as you need in future steps.)

Click the Add button and paste the created Private Key value copied from the ${CURRENT_USER}.sshid_rsa file inside the field.

I keep the Passphrase field blank, as I did not specify a passphrase when creating the key pair. If you added a passphrase when you created the key pair, you need to include it here too.

Click the OK button.

Step 5: Add a Node Entry to the Jenkins Master

On the Jenkins master, click the Manage Jenkins menu. Click the Manage Nodes and Clouds link. This will open a page on which you can create new nodes.

Click the New Node link available on the left side. The next page will open, which is where you add the node details.

Enter a name in the Node Name field; I entered Node1. Click the Permanent Agent radio button.

Click the OK button. This will open page on which you can specify other details of the node.

Let’s review all the parameters on this page before you fill them in:
  • Name: The name of the slave, which should be unique.

  • Description: This field is optional, but if mentioned, it can be helpful for other team members.

  • # of executors: The maximum number of concurrent builds that Jenkins may perform on this agent. I used one executor for testing purposes. You can check the server stat and then define the number of executors.

  • Remote root directory: An agent needs to have a directory dedicated to Jenkins. Specify the path to this directory on the agent. It is best to use an absolute path, such as c:jenkins ode1. This should be a path local to the agent machine. There is no need for this path to be visible from the master. The Jenkins agent will create a workspace in the directory mentioned in this field.

  • Labels: Labels (or tags) are used to group multiple agents into one logical group. Multiple labels must be separated by a space.

    For example, the linux docker would assign two labels to the agents linux and docker.

  • Usage: This controls how Jenkins schedules builds on this node. Utilize this node as much as possible. This is the default and normal setting. In this mode, Jenkins uses this node freely.

  • Launch method: This controls how Jenkins starts this agent. The following three options are available in this dropdown:
    • Launch agent by connecting to the master

    • Launch agent via execution of the command on the controller

    • Launch agents via SSH

  • Launch agent via Java Web Start: This allows the slave to be launched using Java Web Start. In this case, a JNLP file must be opened on the agent machine, which will establish a TCP connection to the Jenkins master. This means that the agent need not be reachable from the master; the agent just needs to be able to reach the master. If you have enabled security via the Configure Global Security page, you can customize the port on which the Jenkins master will listen for incoming JNLP agent connections.

    By default, the JNLP agent will launch a GUI, but it's also possible to run a JNLP agent without a GUI, e.g., as a Window service. The next section of this chapter includes an example and detailed steps.

  • Launch the agent via execution of the command on the master: This starts the slave by having Jenkins execute a command from the master. Use this when the master is capable of remotely executing a process on another machine, e.g. via SSH or RSH. Usually, a utility like Psexec.exe can be used to start the agent on a remote machine.

  • Launch the slave agents via SSH: This starts a slave by sending commands over a secure SSH connection. The slave needs to be reachable from the master, and you have to supply an account that can log into the target machine. For this, no root privileges are required. This is the one that I am using for my slave configuration.

    If you select this option in the Launch Method dropdown, you get two additional fields on the form—Credentials and Host Key Verification Strategy.
    • Credentials: In the Credentials dropdown, you need to select the credentials entry with the authentication information to be used to authenticate the user on the agent node.

    • Host Key Verification Strategy: This controls how Jenkins verifies the SSH key presented by the remote host while connecting. This dropdown has the following options:

    • Known hosts file verification strategy

    • Manually provided key verification strategy

    • Manually trusted key verification strategy

    • Non verifying verification strategy

  • Known hosts file verification strategy: Checks the known_hosts file (~/.ssh/known_hosts) for the user Jenkins is executing, to see if an entry exists that matches the current connection. If you get a SSH Host Key Verification error as shown here:

No entry currently exists in the Known Hosts file for this host. Connections will be denied until this new host and its associated key is added to the Known Hosts file.
Key exchange was not finished, connection is closed.
java.io.IOException: There was a problem while connecting to node2.scmquest.com
It could be a problem with the SSH lib used by Jenkins, which does not support newer ciphers like ecdsa-sha2-nistp256. Just delete the known_hosts entry and create a new one using the following command:
ssh -o HostKeyAlgorithms=ssh-rsa node2.scmquest.com (where node2.scmquest.com is the hostname of the slave server)
This will solve your problem.
  • Manually provided key verification strategy: This ensures that the key provided by the remote host matches the key set by the user who configured this connection.

  • Manually trusted key verification strategy: Requires a user with Computer.CONFIGURE permission to authorize the key presented during the first connection to this host before the connection is allowed to be established.

  • Non verifying verification strategy: Does not perform a verification of the SSH key presented by the remote host, allowing all connections regardless of the key they present. It’s not advisable to select this, as it may open the path for attackers.

  • Let Jenkins control this Windows slave as a Windows service: This starts a Windows slave by a remote management facility built into Windows. This is suitable for managing Windows slaves. Slaves need to be IP reachable from the master.

  • Availability: Controls when Jenkins starts and stops this agent.

  • Keep this slave online as much as possible: This is the default setting. In this mode, Jenkins tries to keep the slave online as much as possible. If Jenkins can start the slave without user assistance, it will periodically attempt to restart the slave if it is unavailable. Jenkins will not take the slave offline.

  • Take this slave online when in demand and offline when idle: In this mode, if Jenkins can launch the slave without user assistance, it will periodically attempt to do so while there are unexecuted jobs; otherwise, the slave will be taken offline by Jenkins.

You can now fill in these fields to create the node entry:
  1. 1.

    In the Name field, I entered Node1.

     
  2. 2.

    In the Number Of executors field, I have used value 1 as I do not want to run more than one builds on a single agent.

     
  3. 3.

    In the Remote Root Directory, I have used C:JenkinsJobExecution. Once you run the job in this directory, the workspace of the job will be created. I used the directory from C: because this is my SystemRoot and once the master connects to the slave it will enter the user directory from SystemRoot (C: in my case). If you include a directory from a different root, such as D:, Jenkin will throw an error while running the job.

     
  4. 4.

    In the Labels field, I entered CalculatorAPI_Node.

     
  5. 5.

    In the Usage field, I kept the Use This Node As Much As Possible value selected.

     
  6. 6.

    In the Launch method, I selected the Launch Agents via SSH value.

     
  7. 7.

    In the Host field, I used 192.168.43.185, which is the IPv4 address of my slave node.

     
  8. 8.

    In the Credentials field, I selected the credentials entry we created in this chapter.

     
  9. 9.

    In the Host Key Verification Strategy field, I selected the Known Hosts File Verification Strategy value.

     
  10. 10.

    I selected the Environment Variables checkbox under the Node Properties section and created the JAVA_HOME environment variable by entering JAVA_HOME into the Name field. The Value field contains the path of the JDK on the slave machine. You need this because the job you are going to run on the slave runs mvn commands and Maven needs the JAVA_HOME environment variable pointing to the JDK (see Figure 17-2).

     

A window box of a browser, with Node 1 Configuration tab open. In vertical arrangement, going downward, it has an address bar, 2 filled boxes, a ticked checkbox, details to fill out, which are name and value, a button labeled Add, an unticked checkbox, and a button labeled Save.

Figure 17-2

The JAVA_HOME environment variable in Node Properties

  1. 11.

    Click the Save button to save the node configuration.

     

After you perform these steps on the master machine, you can move to the slave/agent machine for further steps.

Step 6: Add a Public Key to the authorized_keys File on the Slave Machine

Let’s go to the {CURRENT_USER} directory on the agent machine. In my case, this directory is C:UsersADMIN. Create a directory called .ssh. Right-click to get the context menu. Click the Git Bash Here menu option, which will open the Git bash window

Create a file named authorized_keys by running the following bash command in Git bash:
touch authorized_keys

This command will create a file named authorized_keys in the .ssh folder under the ${CURRENT_USER} directory. Open this file and paste the public key from the key pair you generated on the master machine.

Step 7: Change the Permissions of the authorized_keys File on the Slave Machine

Right-click the authorized_keys file. Select the Properties menu option, which will open the Properties window.

Click the Security tab. Then click the Advanced button. This will open the Advanced Security Settings for authorized_keys window (see Figure 17-3).

A dialog box titled Advanced Security Settings for authorized keys. Under permissions, in a vertical arrangement, going down on the left side, there are 3 principal entries in a box, 3 buttons in a horizontal arrangement, which have to add, remove, and view, a button labeled Disable inheritance, and 3 buttons in horizontal arrangement on the right side.

Figure 17-3

The advanced security settings of the authorized_keys file

Click the Disable Inheritance button. Then select the Convert Inherited Permissions into Explicit Permissions on this Object option (i.e., the first option).

Keep only the system and your current user in the list; delete any other users by clicking the Remove button while being parked on the user entry you want to delete.

Figure 17-4 shows that I have kept only two users: ADMIN (which is my current user and the one for which you created the credentials entry in Step 4) and SYSTEM. See Figure 17-4.

A dialog box titled Advanced Security Settings for authorized keys. Under permissions, in a vertical arrangement, going down on the left side, there are 2 principal entries in a box, 3 buttons in a horizontal arrangement, which have to add, remove, and view, a button labeled Enable inheritance, and 3 buttons in horizontal arrangement on the right side.

Figure 17-4

Only the ADMIN and SYSTEM user entries are left

Click the OK button on this window and the OK button on the authorized_keys properties window.

Step 8: Restart the sshd Service

Go to the services window and restart the service named OpenSSH SSH Server.

Step 9: Check the Connection to the Agent Machine from the Master

Open the command prompt on master machine and run the following command:
ssh UserName@IPAddress of Slave
I executed the following command:

After pressing the Enter key, you will get the prompt, Are you sure you want to continue connecting(yes/no/[fingerprint])?

Type yes and press Enter, after which the SSH connection will be successful. A file called known_hosts will be created inside the ${CurrentUser}.ssh folder. Open this file; it will have a key entry added for your agent machine.

Step 10: Launch the New Node from the Master Machine

Click the Manage Jenkins ➤Manage Nodes and Clouds menu option. Click the Node1 entry and then click the Relaunch Agent button. You can see that the master was successfully connected to the agent.

During this connection process, the master copies remoting.jar to the agent machine inside the folder that's set as the remote root directory.

Creating a Free-Style Job to Run on the Node1 Agent

After successful configuration of the master and the agent using SSH, it's time to create a job to run on the node you just configured.

I created a free-style job that will deploy the CalculatorAPI JAR on the Nexus repository.

I checked the Restrict Where This Project Can Be Run checkbox and entered Node1 in the Label Expression field. This setting is responsible for running the job on a specified node. It has Git URL set in the Source Code Management section. The build step is set to mvn deploy. Click the Save button.

Running the New Free-Style Job on the Node1 Agent

Before running a job on an agent connected using SSH, you need to launch an agent which you have already created. Run the job; it will be executed on the agent machine.

Understanding the Configuration to Connect the Agent to the Master Using JNLP

Step 1: Configure the Jenkins Master to Receive JNLP Agent Connection Requests

On the master machine, click the Manage Jenkins menu. Scroll down the page and click the Configure Global Security menu.

Scroll down the page again and, under the Agents section, select the Fixed radio button available for TCP Port for Inbound Agents option and enter 7070 as the port number.

You can use any available port number in this field. I use 7070 as it is available on my machine. Scroll down the page and check the Enable Agent ➤ Control Access Agent checkbox under the Agent ➤ Controller Security section. Click the Save button.

Step 2: Set the Jenkins URL

Click the Manage Jenkins menu. Click the Configure System menu. Scroll down the page to see the Jenkins Location section.

Enter http://<IP Address of Master machine:port> in the Jenkins URL field. My Jenkins master starts on the IP address 192.168.43.10 and port 8080 so I entered http://192.168.43.10:8080 here.

Note: Do not use http://localhost as you will not be able to access this master machine from the agent machine when the localhost is used.

Click the Save button.

Step 3: Create a New Node Entry from the Agent (Slave) Machine

Open Jenkins on the slave machine using the Jenkins Master URL. Click the Manage Jenkins➤Manage Nodes and Clouds menu. Click the New Node menu entry available on the left side. Enter the name of the node in the Node Name field. I entered Node3. Click the OK button.

Here are the other fields and their entries:
  • Name: Node3

  • Number of executors: 1

  • Remote root directory: C:JNLPNode

  • Labels: JNLPNode

  • Usage: Use this node as much as possible

In the Launch Method dropdown, keep the Launch Agent by Connecting to Master option selected. See the Node Properties section in Figure 17-2. Click the Save button. Then click the agent.jar link highlighted in Figure 17-5 to download the agent.jar file.

A window box of a Jenkins account under a user named Pranoday Dingare. From the top, it has the menu bar, then on the left side is a navigation pane, with options laid vertically. Status is selected that leads to Agent Node 3 section, with a hyperlink and command.

Figure 17-5

The agent.jar hyperlink

After downloading the agent.jar file, keep it at your desired location. I have kept it in the D:Agentjar folder.

Select the command below the Run from Agent Command Line section. My command is as follows:
Java -jar agent.jar -jnlpUrl http://192.168.43.10:8080/computer/node3/jenkins-agent.jnlp -secret 76f01ce9855280b9b743b9afc1ccef4af908675f5a6ed229efd8fb4909aa74b -workdir "C:JNLPNode"
Copy it. Modify the path of the agent.jar accordingly. I kept my agent.jar file in the D:AgentJar folder. The following is the command, modified for me:
Java -jar D:AgentJaragent.jar -jnlpUrl http://192.168.43.10:8080/computer/node3/jenkins-agent.jnlp -secret 76f01ce9855280b9b743b9afc1ccef4af908675f5a6ed229efd8fb4909aa74b-workdir "C:JNLPNode"

After modifying the agent.jar path in the command, execute it from the command prompt.

Note that the value of the workdir parameter in this command has been taken from the Remote root Directory, field which you configured when configuring a node instance. The value of the secret parameter will be different for each node.

Creating a Job to Run on the JNLP Node

I created a job called JNLPNodeJob, which will pull the code from the CalculatorAPI repository and will build the Jar file and deploy it on Nexus (same as the other job you created in this chapter). The only difference is that the Label Expression field has the Node3 value.

Run the job by clicking the clock sign from the dashboard. You can see that the job is getting executed on Node3.

Summary

In this chapter, you learned what distributed builds are and their advantages. You also learned about the different ways to connect the Jenkins master and the Jenkins slave nodes. You learned detailed steps to connect master-slave using SSH and using JNLP. You also configured your Jenkins jobs to run on the slave nodes. The next chapter explains how to create an EC2 instance on the AWS platform and deploy the web application on it through the Jenkins pipeline.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.134.102