I wanted to blog about how to get Jenkins running on a Mac using its installer.Jenkins is a great product, but its frenetic and crazed (but cheerful and enthusiastic) development process often shows through. Case in point: the default Mac installe…
I wanted to blog about how to get Jenkins running on a Mac using its installer.
Jenkins is a great product, but its frenetic and crazed (but cheerful and enthusiastic) development process often shows through.
Case in point: the default Mac installer, which you can
download from the jenkins-ci.org website, sets up Jenkins to run as a Mac LaunchDaemon running as user
daemon.
Now, there's nothing inherently wrong with this–indeed, it can be quite nice.?? You'll only have one instance of Jenkins running, and no user needs to be logged on for it to do its thing, and if Jenkins ever got hacked you're running as a low-privilege user rather than as some kind of full-fledged user with the ability to ruin your day.
However, this caused some weird problems, nullifying the entire intent of a one-click installer.?? These problems manifest themselves the moment you try to run a Maven build, which suggests to me that this (simple) smoke test is simply not run before new versions of the installer are released.?? Oh well, time to roll up our sleeves and turn the one-click installation process into an exercise in Mac system administration.??
🙂
What's wrong with
daemon?
The first thing to know about user
daemon is that his home directory is
/var/root.?? That should start to give you a funny feeling.
The reason that should give you a funny feeling is that Maven looks for its
settings.xml file in
$HOME/.m2.?? Which of course does not exist in
/var/root.
So when Jenkins launches, it appears to come up fine.?? But if you try to run a Maven build, you'll get a lovely stack trace about how the file
/var/root/.m2 couldn't be created.
When I first encountered this error, I just wanted to get the stupid thing working, so I did:
sudo mkdir -p /var/root/.m2
…and:
sudo chmod a+rwx /var/root/.m2
So this gets Jenkins-running-as-daemon past this problem, but now it wants to create temporary files in /Users/Shared/Jenkins/Home, which it doesn't own, and can't write to.
At any rate, I now realized that I didn't want this thing running as user
daemon anyway, because I didn't want him doing
anything to
/var/root.?? And even if I could somehow tell him to use a different user directory so that
$HOME/.m2/settings.xml would be resolved somewhere else, it was clear that I was going to have to edit
.plist files.?? So, so much for the installer.?? And as long as the installer wasn't going to work, I decided that I wanted to make Jenkins run as a different kind of daemon user anyway.
This turned out (for this rookie Mac system administrator) to be quite difficult.
The steps involved are:
- Create a daemon user (I called mine _jenkins)
- Create a daemon group (I called mine???surprise!???_jenkins)
- Put the daemon user in the newly-created daemon group
- Create the home directory for the new daemon user (/Users/_jenkins in my case)
- chown the /Users/Shared/Jenkins directory so that its hierarchy is owned by your new user.
- edit /Library/LaunchDaemons/org.jenkins-ci.plist so that it reflects all this information.
Creating the user is a task that should not be accomplished through the usual Mac GUI methods.?? You need to use dscl instead.?? This is because you want to create a daemon user.?? I snooped around for a bit and came up with this lovely tutorial: http://www.minecraftwiki.net/wiki/Tutorials/Create_a_Mac_OS_X_startup_daemon#The_hard_.28and_correct.29_way.?? It walked me through steps 1-4 above.
Then I did:
sudo chown -R _jenkins:_jenkins /Users/Shared/Jenkins
Finally, my /Library/LaunchDaemons/org.jenkins-ci.plist looks like this:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">?????? <dict> ?????????????? <key>EnvironmentVariables</key>?????????????? <dict> ?????????????????????????????? <key>JENKINS_HOME</key>?????????????????????????????? <string>/Users/Shared/Jenkins/Home</string> ?????????????????????????????? <key>_JAVA_OPTIONS</key>
?????????????????????????????? <string>-Dfile.encoding=UTF-8</string> ?????????????? </dict>?????????????? <key>GroupName</key> ?????????????? <string>_jenkins</string>?????????????? <key>KeepAlive</key> ?????????????? <true/>?????????????? <key>Label</key> ?????????????? <string>org.jenkins-ci</string>?????????????? <key>ProgramArguments</key> ?????????????? <array>?????????????????????????????? <string>/bin/bash</string> ?????????????????????????????? <string>/Library/Application Support/Jenkins/jenkins-runner.sh</string>?????????????? </array> ?????????????? <key>RunAtLoad</key>?????????????? <true/> ?????????????? <key>UserName</key>?????????????? <string>_jenkins</string> ?????? </dict></plist>
I added the _JAVA_OPTIONS environment variable to force UTF-8 encoding.?? This is because no matter what kind of encoding you might specify in your Java code, Java-on-the-Mac's character encoding for what gets put out to the terminal is MacRoman by default (?!).?? You have to get the file.encoding property passed into the JVM early enough so that it is picked up by the rest of the JVM internals, and the only way to do that is to use the special _JAVA_OPTIONS environment variable picked up by all the Java tools in $JAVA_HOME/bin.?? The only unfortunate side effect of all this is that you get a warning printed to the screen on every JVM startup that says, effectively and incomprehensibly, I am using the environment variable you told me to.
Once you've done all this, you can simply stop the launch daemon and it will automatically restart with the new values:
sudo launchctl stop org.jenkins-ci
I hope that helps other Jenkins Mac users out.