How to Install Jenkins CI on Cloud Foundry for Continuous Delivery

by Aliaksei MarydashviliJune 18, 2014
With real-life examples, this tutorial explains how to set up infrastructure, a remote system, an RVM, as well as configure Jenkins and MySQL.

Continuous integration (CI) allows for pushing regular enhancements and bug fixes to your application in an easy, fast, and safe way. When using this practice, every time a developer commits a change, the software has to pass a number of tests. This guarantees that every new release is safe and bug-free. Ultimately, continuous integration can help to automate the entire software delivery process.

Software delivery process based on the continuous integration strategy (Image credit)

In this blog post, we will explain in detail how to set up continuous delivery for a Ruby on Rails (RoR) application running on the Cloud Foundry PaaS with Jenkins CI, a popular continuous integration tool.

 

Infrastructure and setup

For this tutorial, we used a simple RoR application with MySQL as a database. Then, we pushed the code to a public GitHub repository. The local workstation had the following specs: Ubuntu 13.10 x86_64 with MySQL Server 5.5.35. The remote virtual machine ran Ubuntu 10.04 x86_64 with Cloud Foundry v2 (5.4.5), Jenkins 1.550, and a MySQL client (5.1.73).

Pushing a Jenkins CI app to Cloud Foundry

So, let’s begin.

 

Setting up a remote system

Before you start, install Openssh-server (optional).

sudo apt-get install openssh-server

Then, install the latest stable Git from a PPA (Personal Package Archive), since the default Git version (1.7.0.4 for Ubuntu 10.04) is a bit of outdated.

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get install git

Configure Git.

git config --global user.name “jenkins”
git config --global user.email “jenkins@example.com"

Configure iptables. Under this step, you also need to:

  • enable an outbound connection on the remote machine to access the database on the workstation
    sudo iptables -A OUTPUT -p tcp -d database_host_ip --dport 3306 -j ACCEPT
  • save the updated iptables rules to a file
    iptables-save > /etc/iptables.rules
  • make sure the rules are restored at every boot
    vim /etc/network/if-post-down.d/loadiptables
    
    #!/bin/bash
     /sbin/iptables-restore < /etc/iptables.rules
    exit 0

Install RVM pre-requisites under Jenkins on the remote machine.

sudo apt-get install curl libxslt1.1 libxslt-dev xvfb build-essential zlibc zlib1g zlib1g-dev bison openssl libreadline5 libreadline-dev libssl-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev subversion autoconf libtool

Install Cloud Foundry. Under this step, proceed with the following instructions:

  • You can use the Cloud Foundry v2 Nise Installer.
    bash < <(curl -s -k -B https://raw.github.com/yudai/cf_nise_installer/${INSTALLER_BRANCH:-master}/local/bootstrap.sh)
  • Then, restart your devbox.
  • Launch Cloud Foundry.
    cd cf_nise_installer
    ./local/start_processes.sh
  • After this command, wait a couple of minutes to allow all the processes to start.
  • Create an organization and space in Cloud Foundry, please follow the same order of commands.
    cf api http://api.192.168.1.180.xip.io # api..xip.io
    cf login -u admin -p c1oudc0w #credentials provided by cf installation tutorial, see references
    cf create-org altoros #enter your value
    cf create-space -o altoros development #enter your value
    cf target -o altoros -s development
  • Finally, add the .manifest.yml file for the application to your RoR project directory (see the “Examples” section).

Now, it’s time to install Jenkins. For this purpose, follow the next steps:

  • Install openjdk-6-jre and openjdk-6-jdk
    sudo apt-get install openjdk-6-jdk openjdk-6-jre
  • Install the latest version of Jenkins
    wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
    sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
    sudo apt-get update
    sudo apt-get install jenkins
  • Install a MySQL client
    sudo apt-get install mysql-client-core-5.1

 

Setting up an RVM

Switch to the jenkins account.

sudo su Jenkins

Install RVM for the jenkins user.

Important: DO NOT install RVM under the same account where you installed Cloud Foundry to avoid conflicting with RBenv.

cd ~
\curl -sSL https://get.rvm.io | bash -s stable

Install Ruby 1.9.3 or 2.x.0 according to your project settings.

source ~/.bash_profile
rvm autolibs disable
rvm install 1.9.3

Create the cf2 gemset.

rvm use 1.9.3
rvm gemset create cf2
rvm gemset use ruby-1.9.3-p484@cf2

Download and install the Cloud Foundry CLI from this GitHub repo.

wget -O cf.deb https://s3.amazonaws.com/go-cli/releases/v6.1.2/cf-cli_amd64.deb
sudo dpkg -i cf.deb

Note: Currently, the latest version of Cloud Foundry CLI utility is v6.1.2. This may change in the future.

Generate a new SSH key and add it to GitHub.

cd ~
mkdir .ssh
cd .ssh
ssh-keygen -t rsa -C "jenkins@example.com"

Copy the public key to the appropriate settings tab of your GitHub account.

Finally, verify that everything worked out as expected.

ssh -T git@github.com

 

Configuring Jenkins CI

First, you need to add environment variables to Jenkins. To do this, go to: Manage Jenkins -> Configure System -> Global properties/Environment variables and fill out the following fields:

  • login: admin (provided in the Cloud Foundry installation tutorial, see the “References” section)
  • org: altoros (created previously in the Install Cloud Foundry step)
  • password: c1oudc0w (provided by in the Cloud Foundry installation tutorial, see the “References” section)
  • space: development (created previously in the Install Cloud Foundry step)
  • target: http://api.Address.xip.io (provided in the Cloud Foundry installation tutorial, see the “References” section)

Install the following Jenkins plugins: Git Client, GitHub, and Rake.

Configure Jenkins security by adding accounts with appropriate permissions.

Create a new Jenkins project. To do this, fill out the fields related to the GitHub project. Then, enter build steps into the Execute shell field (see the “Examples section”).

Add config files to the JENKINS_HOME/shared folder.

cd JENKINS_HOME
mkdir shared
cd shared
vim manifest.yml (see the “Examples” section)
vim database.yml

Since both Cloud Foundry and Jenkins were installed on the same machine in our setup, we had to assign free port 8081 to Jenkins to avoid conflict with Cloud Foundry. Edit the following line in /etc/default/jenkins.

# port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=8081

 

MySQL configuration on a local machine

Enable an inbound connection on the workstation.

sudo iptables -A INPUT -p tcp -s client_host_ip --dport 3306 -j ACCEPT

Create a new account in the MySQL database and grant necessary permissions to a new user to access the project database remotely.

GRANT ALL PRIVILEGES ON your_database.*
    TO 'user'@'remote_host'
    IDENTIFIED BY 'password';

 

Examples

Below, you will find a sample of manifest.yml.

---
applications:
- name: bc                                                       # you can use any name you like
  memory: 512M
  instances: 1
  host: bc					                                                          # use your own value here
  domain: 192.168.1.180.xip.io		                       # api..xip.io accordingly to cf_nise_installer installation steps
  command: bundle exec rake db:drop db:create db:migrate && bundle exec rails s -p $PORT
  path: .
  env:
    DATABASE_URL: mysql2://user:password@host_name:port/db_name	# replace with actual value

Important: It is necessary to provide the DATABASE_URL variable in the manifest file; otherwise, the deployment will fail. The full list of available environmental variables can be found in official docs.

Jenkins build steps from Execute shell are as shown below.

#!/bin/bash -exl
cd $WORKSPACE
source ~/.bash_profile
rvm gemset use ruby-1.9.3-p484@cf2
cp ~/shared/database.yml config/database.yml

bundle install
bundle exec rake db:drop RAILS_ENV=test
bundle exec rake db:create RAILS_ENV=test
bundle exec rake db:schema:load RAILS_ENV=test
bundle exec rspec

cf login -a ${target} -u ${login} -p ${password}  -o  ${org} -s ${space}
cp ~/shared/manifest.yml .
cf push
cf logout

We hope, this tutorial will help you to provide continuous integration on Cloud Foundry using Jenkins. If you have anything to add, just let us know in the comments.

 

Further reading

 

About the author

Aliaksei Marydashvili is a Cloud Foundry engineer at Altoros. Since 2005, he has acquired broad background in Java and Ruby on Rails. Currently, Aliaksei is improving experience with these technologies on Cloud Foundry, bringing his R&D expertise to integrate solutions around the PaaS and optimize software delivery processes.


This post was written by Aliaksei Marydashvili and edited by Alex Khizhniak.