Enterprise Jenkins on Azure Part 2

Enterprise Jenkins on Azure, Part 2

This post is part 2 of a series:

Part 1: Overview and Deploy Azure Resources
Part 2: Deploy Jenkins Operations Center, Master and Shared Agent
Part 3: The Jenkinsfile, tweaks and tips

In this post I deploy the Jenkins distributed builds model: a Jenkins client master will delegate build jobs to one or more Jenkins agents.  In addition, I deploy a Jenkins Operations Center to manage all client masters in one place.

Configuring Jenkins

Previously I created these Azure resources:

  • Linux VM, template for provisioning CloudBees Jenkins Operations Center (CJOC).
  • Linux VM, template for provisioning CloudBees Jenkins Enterprise (CJE).
  • Linux VM, Ubuntu 14.04: to use as Jenkins build agent.
  • Azure App Service, template for provisioning a Jetty web container.

The next step is to configure the VMs.

 

CloudBees Jenkins Operations Center

CJOC is an enterprise-class product from CloudBees, for centrally managing a cluster of Jenkins client masters. A client master is a Jenkins master in a CJOC cluster. Here I am using only one client master so CJOC is not essential, but with an evaluation licence I can experiment with enterprise features like centrally managed client masters, shared agents, and security across the cluster.

On the main configuration page: Manage Jenkins | Configure System, set # of Executors to zero because CJOC should manage client masters and shared agents, not execute build jobs.

 

Shared agent

From the Jenkins dashboard: New Item | Shared Slave, set the following values:

  • # of executors = 1
    1 executor because no parallel build tasks will be supported at this stage.
  • Remote FS root = /home/jenkins
    This lets the agent know where it can create a workspace for any job.
  • Labels = linux
    A label that we can use to restrict which agents may build a given job. The restriction is applied in the Pipeline job’s Jenkinsfile (I’ll describe that in the next part.)
  • Launch method = Launch agent via Java Web Start
    This is the easiest option for connecting the agent to CJOC/CJE.

Below is a screenshot of the configuration:

Azure shared agent config

 

After saving the new configuration, CJOC displays the shared agent status:

Azure shared agent status

 

Azure shared agent status

Though the agent is neither running nor connected, CJOC shows it on-line by default. The agent must be off-line to change its configuration. Note the “slave command line”. Copy the following to use later on the build agent VM:

  • The URL for link slave.jar.
  • The full text of the command line.

 

CloudBees Jenkins Enterprise

CJE is an enterprise-class product, designed to address scale, efficiency, and security. CJE is standard Jenkins plus additional plugins from CloudBees for orchestrating build agents.

On the main configuration page: Manage Jenkins | Configure System set # of Executors to zero because CJE should be orchestrating build agents, not executing build jobs.

On the same page, the section GitHub has a list GitHub Servers. Click the help icon at right to see the default GitHub webhook URL for this Jenkins:

Azure config GitHub

 

In GitHub, create a repository webhook with defaults, except these fields:

  • Payload URL, set to the above default webhook URL
  • Content type, set to application/x-www-form-urlencoded

GitHub webhook screenshot:

GitHub Manage Webhook

 

Back in Jenkins, the build job needs access credentials for resources on remote hosts:

  • The source code repository on GitHub.
  • The Azure App Service directory for FTP deployment.

Create Jenkins credentials for these resources: from the Jenkins dashboard, click Credentials to see defined credentials and available stores. Click the little black triangle to the right of (global) then click Add credentials:

CJE credential stores: Add

 

Set the fields as below for the FTP deployment credential:

CJE credential: Azure app service deployment

 

Notes:

  • Username must match FTP/Deployment User from the Azure App Service’s Properties. This is the fully-qualified username gboys-gameoflife\gboy, not the username (gboy) shown at Deployment credentials.
  • The value at ID will be referenced in Jenkinsfile code.
  • Jenkins provides these fields to an executing job as environment variables (more about this in the next part).

For access to GitHub, create another credential with type SSH Username with private key.

Next, create a Pipeline job from the Jenkins dashboard: New Item | Pipeline with fields set as below:

  • Check the box at GitHub project and enter the repository URL:
    https://github.com/groverboy/game-of-life-azure-pipeline/
  • Under Build Triggers, check the box at Build when a change is pushed to GitHub.
  • Under Pipeline, set Definition to Pipeline script from SCM. At SCM choose Git.
  • For the repository:
    • URL: https://github.com/groverboy/game-of-life-azure-pipeline.git
    • Credentials: choose the Jenkins credential for access to GitHub.
  • Branches to build – since the source code is on a non-default branch, set this to: */azure-pipeline
  • Script path: use the default, Jenkinsfile

 

The Jenkinsfile code assumes that Jenkins is configured with a Maven tool installer named “maven-3.3”. From the Jenkins dashboard, Manage Jenkins | Global Tools Configuration, add the tool:

Azure config tools Maven

 

Remember that the shared agent is set to connect via Java Web Start, i.e. JNLP. From the Jenkins dashboard, Manage Jenkins | Configure Global Security: the default for TCP port for JNLP agents is disabled. Change it to Fixed and keep the default value:

Azure CJE security TCP JNLP

 

Build Agent

Start by connecting to the build agent VM. In the Azure Portal, open the blade for the VM. Assuming the VM has started, click Connect to get the current IP address:

Azure dialog: Connect to Linux VM

 

Start a local Bash terminal and connect using SSH. Below I use switch -i <keyfile> because I’ve got a few keyfiles in my .ssh/ directory:

$ ssh -i ~/.ssh/id_rsa_jenkins_azure gboy@40.127.83.42

Now that we’re connected, the commands below apply to the build agent’s shell.

 

Install dependencies

Install the Java development kit (JDK) and Git:

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install default-jdk
$ sudo apt-get install git-core

JDK compiles and packages the Java source code, and includes a Java virtual machine (JVM) that we need to run the build agent binary, a Java jarfile.

Git gets source code from the remote repository.

Note: the build process also depends on Maven but there’s no need to install Maven manually, because I added it to CJE’s global tools above, CJE provides it to the build agent as needed, and the Jenkinsfile has code to use that tool.

 

Run the agent as user jenkins

Add a user jenkins to own the agent process (you will need to create a password):

$ sudo adduser jenkins

Now login as jenkins:

$ su jenkins

The above should set the directory to jenkins home. To do that explicitly:

$ cd /home/jenkins

 

Download the binary for the agent process

Use the slave.jar URL from the shared agent’s status page (on CJOC) to download the build agent binary to the jenkins user’s home directory:

$ curl -LO http://jenkins-gboy.australiasoutheast.cloudapp.azure.com/jnlpJars/slave.jar

Note: we only need to download the binary once. The remaining steps must be done whenever the VM starts up.

 

Automating steps

I could do the remaining steps by hand but that will get tedious if I want to stop and start the VM frequently. That’s because it’s needed only when, for example, developers might push changes to GitHub. I pay Azure by the hour and it wouldn’t be cost-effective to have the VM available 24×7.

Instead, get the OS to run the build agent on start-up.

Change to user root in order to modify system files:

$ sudo -i

To run shell script on start-up, edit the rc.local file:

$ vi /etc/rc.local

Add the following line to run a new script:

/home/jenkins/run_build_agent.sh

Save the change to rc.local, then create the script file:

$ vi /home/jenkins/run_build_agent.sh

Add the following lines:

#!/bin/sh

# Get current timestamp as a UNIX time:
TIMESTAMP=$(date "+%s")

# Build a path for the build agent log file based on the current time:
FILE_PATH=/home/jenkins/slave_$TIMESTAMP.log

# Run the build agent:
# "-b" in the background
# "-E" preserve the user's environment (see /home/jenkins/.profile)
# "-i" run login shell as the target user to get that user's environment
# "-u jenkins" as user "jenkins"
#
# slave.jar args:
# "-slaveLog $FILE_PATH" write output to log file
sudo -b -E -i -u jenkins \
  azureHost=waws-prod-sg1-021.ftp.azurewebsites.windows.net \
  svchost=http://gboys-gameoflife.azurewebsites.net \
  java -jar /home/jenkins/slave.jar \
  -jnlpUrl http://jenkins-gboy.australiasoutheast.cloudapp.azure.com/jnlpSharedSlaves/shared-agent-1/slave-agent.jnlp \
  -secret 15911f81cdffef2e30446c6ca073d4fb2b06bd3ccbc1c4d007372ecf918e5113 \
  -slaveLog $FILE_PATH

In the above script, the sudo command sets two environment variables to be available to the agent process: azureHost and svchost.  azureHost corresponds to the FTPS host name (see Azure App Service in previous post), except that it omits the scheme ftps:// which will be supplied by the Jenkinsfile.

Save the file, then make it executable:

$ chmod +x /home/jenkins/run_build_agent.sh

Now the build agent will start automatically when its VM starts.

Note: for details on the above use of sudo, see Running a background process as a specific user on Linux startup.

That’s all for this post. In the next part I’ll describe the Jenkinsfile and wrap up the series.

2 thoughts on “Enterprise Jenkins on Azure, Part 2”

  1. Pingback: Enterprise Jenkins on Azure, Part 3 – Code Partners

  2. Pingback: Enterprise Jenkins on Azure, Part 1 – Code Partners

Leave a Comment

Scroll to Top