Configuring the Jenkins URL
Currently it just so happens that the Jenkins URL in the management console does
have the proper config as it is set to http://localhost:8080
. This is merely a
coincidence that the default value and the current address match though. Once we
start moving this thing around, it will be very important that it is set to the
right value else we’ll have all kinds of strange issues. Since it will definitely
have to be configured, let’s start here. It doesn’t hurt that it is a fairly
simple example of configuring Jenkins with an environment variable passed by
Docker Compose.
Passing from Docker Compose
This is a setting that will change from environment to environment and so I think the best place to set it is in the compose file. Let’s create a variable in there that we can read it in during init and make the right configuration. Edit the compose file and create a JENKINS_UI_URL env variable as well as volumes for the configs themselves.
deploy/master/docker-compose.yml
#---
## deploy/master/docker-compose.yml
## Define the version of the compose file we're using
#version: '3.3'
#
## Define our services
#services:
# # Jenkins master's configuration
# master:
# image: modernjenkins/jenkins-master
# ports:
# - "8080:8080"
environment:
- JENKINS_UI_URL=http://localhost:8080
# volumes:
# - plugins:/usr/share/jenkins/ref/plugins
# - warfile:/usr/share/jenkins/ref/warfile
- groovy:/var/jenkins_home/init.groovy.d
#
# # Jenkins plugins' configuration
# plugins:
# image: modernjenkins/jenkins-plugins
# volumes:
# - plugins:/usr/share/jenkins/ref/plugins
# - warfile:/usr/share/jenkins/ref/warfile
- groovy:/usr/share/jenkins/ref/init.groovy.d
#
## Define named volumes. These are what we use to share the data from one
## container to another, thereby making our jenkins.war and plugins available
#volumes:
# plugins:
# warfile:
groovy:
#
Now that it is set, we should be able to write a groovy init script to read it. But first, we will have to restart Jenkins to pick up the new environment:
PWD: ~/code/modern-jenkins
cd deploy/master
docker-compose down -v
docker-compose up -d
# Confirm that the variable is there:
docker inspect master_master_1 | grep JENKINS_UI
# Should output
# "JENKINS_UI_URL=http://localhost:8080",
With the environment variable now being available to us, we can use the script
console at localhost
to develop our script that will set the URL of our
Jenkins instance.
URL: http://localhost:8080/script
images/jenkins-plugins/files/init.groovy.d/01-cofigure-jenkins-url.groovy
import jenkins.model.*
// Read the environment variable
url = System.env.JENKINS_UI_URL
// Get the config from our running instance
urlConfig = JenkinsLocationConfiguration.get()
// Set the config to be the value of the env var
urlConfig.setUrl(url)
// Save the configuration
urlConfig.save()
// Print the results
println("Jenkins URL Set to " + url)
This should output:
Deploying our Groovy Jenkins Configs
We now have a working script that will manage the URL of Jenkins in any environment that we would be deploying into simply by setting a variable in the compose file. Now we need to make this available to the master so that it can be executed on startup. To do that, we will add a director to the plugins image and then mount it into the master in a similar way to how the war and plugins work.
PWD: ~/code/modern-jenkins/
cd images/jenkins-plugins
mkdir -p files/init.groovy.d/
# Add the file above to this directory as
# files/init.groovy.d/01-cofigure-jenkins-url.groovy
Add the full directory (instead of the individual scripts) of Groovy configuration to the Docker image and then export it as a volume.
images/jenkins-plugins/Dockerfile
...
# # Install our base set of plugins and their dependencies that are listed in
# # plugins.txt
# ADD files/plugins.txt /tmp/plugins-main.txt
# RUN install-plugins.sh `cat /tmp/plugins-main.txt`
#
# Add our groovy init files
ADD files/init.groovy.d /usr/share/jenkins/ref/init.groovy.d
#
...
# # Export our war and plugin set as volumes
# VOLUME /usr/share/jenkins/ref/plugins
# VOLUME /usr/share/jenkins/ref/warfile
VOLUME /usr/share/jenkins/ref/init.groovy.d
#
# ...
We can now rebuild the image and pick up our new config that should (hopefully) configure the URL of our Jenkins on boot!
PWD: ~/code/modern-jenkins
./images/jenkins-plugins/build.sh
cd deploy/master/
docker-compose down -v
docker system prune -f
docker-compose up -d
docker-compose logs -f
Ok you should now see that the URL in the Jenkins management console is set to
http://localhost:8080
! Ahhhh, it was like that before? Hmm. Ok well then
let’s break it to confirm it is working. Modify the value in the compose file to
something different and restart Jenkins:
PWD: ~/code/modern-jenkins/deploy/master
# Change the JENKINS_UI_URL to something different in docker-compose.yml
perl -pi -e 's/JENKINS_UI_URL=.*/JENKINS_UI_URL=http:\/\/derpyhooves/g' docker-compose.yml
# Restart the stack
docker-compose down -v
docker-compose up -d
docker-compos logs
Did that work? A typo you say? I can’t imagine it. I’ve typed docker-compose over 1000 times today, it’s not possible for me to misspell it. In addition, if you notice the difference between this set of commands and the one earlier, we seem to be drifting to chaos. Let’s take note of that, but address it after we confirm that this current change is working as expected.
Gooood, it does work :) The URL in the management console has been updated to the
new, wrong, custom value so we can confirm it works. Let’s commit our code now,
but attend to that tiny little pile of tech debt we found (starting and stopping
the system differently every time is definitely tech debt). NOTE: Don’t forget
to set the JENKINS_UI_URL back to http://localhost:8080
PWD: ~/code/modern-jenkins/
git checkout -b feat-configure_jenkins_url
git add .
git commit -m "Configure the Jenkins URL with Groovy
This change adds an environment variable to the compose file
that sets the URL of the Jenkins instance upon boot. This is
done via the script added to init.groovy.d"
Squirrel!
So we’ve noticed something a bit stinky in our code as we’ve been going about our business. This happens very often in our work lives and attending to little tech debts like this is critical to having quality software. I certainly encourage everyone to leave the code better than they found it and to refactor things when they see something turning into a turd like object.
I also encourage you to make note of these things and take care of them after you are in a place to save game. Switching context between one problem and another can be very expensive mind and time wise so feel free to take a note, create a ticket or something, then finish what you are doing (unless there is an actual issue that needs to be addressed before your code will work). When you submit your PR for review, then jump on that Jira and refactor your heart away.
We need to do everything, but we can only do one thing at a time. Try to be aware of time management.
Let’s get that squirrel
What we noticed was that we were beginning to type the command differently every time we did it. That seems like it should be replaced by a shell script. Let’s create a start script so that this thing starts consistently every time:
deploy/master/start.sh
#!/bin/bash -el
echo "INFO: (re)Starting Jenkins"
docker-compose down -v
docker-compose up -d
echo "INFO: Use the following command to watch the logs: "
echo "docker-compose logs -f"
Write that guy out to deploy/master/start.sh
and make it executable with
chmod +x deploy/master/start.sh
and we’ve now got ourselves a script that
will consistently restart our app.
Add that onto the branch with a good message and push, PR, merge, etc.. See, you’re getting the hang of it!
Next let’s get ready to handle some secrets. Shhhhhh!
The repo from this section can be found under the unit3-part2
tag here:
https://github.com/technolo-g/modern-jenkins/tree/unit3-part2
Next Post: Managing Jenkins secrets in GitHub with Transcrypt