I have used a few different continuous integration (ci) servers before and really like Jenkins. So when running my suite of unit and integration tests started taking more than a minute, it was time for a ci server, specifically Jenkins. Originally I installed Jenkins on my dev machine but it required annoying config tweaks to not interfere with my existing IIS configuration and really needed a home of its own. Since I have been happily hosting my website on Windows Azure and an extra-small node is only $9/month... it seemed like a better option than scrounging up physical hardware.
Since I ran into a few unexpected difficulties, like getting mercurial+ssh+jenkins to play nice, here is the full rundown on how I setup my ci server. I know it seems like a lot of steps but I was able to set this up in less than 2 hours. Plus having a CI server is well worth the time investment!
Provisioning an Azure Virtual Machine
- Create a VM from the gallery, making sure to select the latest platform image. For some reason MS still has old images up with RC builds and other cruft.
- Once your VM is ready, click on the VM and select “Connect”, save the RDP file to your drive so that you can easily connect later.
- Right click on the RDP file and select “Edit…”, then in the Remote Desktop settings uncheck “Always as for credentials” if you want to be able to save them. Otherwise, even if you check “Remember” when entering your password later, it will continue to prompt you for your password.
- Back in the Azure management portal, go to your VM’s Endpoints and add a new endpoint for Jenkins, on TCP port 8080. This will allow you to connect to Jenkins remotely, e.g. mybuildserver.cloudapp.net:8080.
Virtual Machine Housekeeping
Next we need to prep the VM a bit before we can install Jenkins as the VM is pretty bare-bones by default.
- Disable Internet Explorer Enhanced Security for administrators so that you can use IE without throwing a chair. You can find it in the properties for your Local Server in Server Manager.
- Proceed to download your browser of choice and then our prerequisites:
- Since my application is a web app, I installed IIS with IIS Management Console. Server Manager » Local Server » Roles and Features » Tasks » Add Roles and Features.
- Jenkins requires .NET 3.5 which is not installed by default and .NET 4.5 will not cut it. The Jenkins installer will fail because the service will be unable to start if you forget this step.
Configure Mercurial (Hg) with SSH
My source code is on BitBucket, more specifically Mercurial. I ran into trouble using SSH when Jenkins would clone my repository and hang. The problem is that when Jenkins is running as a windows service, it will not be able to accept the host’s ssh keys and hangs waiting for user input. The workaround is to connect once using the console, and then copy the keys from your user to the default windows service user in the registry. If you are using SSH and git, I believe a similar situation can occur.
- Install mercurial.
- Copy the putty and plink executables to C:\Program Files (x86)\Putty.
- Copy your ppk (putty private key) to your VM. This is the key you will use to clone your mercurial repository. As a side note, you may want to use a BitBucket Deployment Key.
- Open a command window and run “C:\Program Files (x86)\Putty\putty” bitbucket.org . When prompted, press Y (yes) to accept the bitbucket SSH host keys.
- Open regedit and navigate to the ssh keys you just accepted. Right click on SshHostKeys and export.
- Now right click on the exported .reg file and select “Edit”. Change HKEY_CURRENT_USER to HKEY_USERS.DEFAULT . Save and import the registry key by double clicking on it.
Windows Registry Editor Version 5.00
- Create a new file, mercurial.ini, in your Mercurial installation directory, e.g. C:\Program Files (x86)\Mercurial. Add the following section so that when mercurial connects via ssh it uses plink and our SSH key.
[ui] ssh=“C:\Program Files (x86)\Putty\plink.exe” -i “C:\Program Files (x86)\Putty\deployment_key.ppk”
Running Jenkins as a Windows Service
Onto the easy part! I kind of lied a bit when I hinted that getting Jenkins to run on Azure was the difficult part. Actually the hardest part was getting mercurial to work with SSH when running under the user account of the Jenkins windows server. So now that you have that working the rest is easy sailing!