Blog

How to Install Jenkins CI on Cloud Foundry for Continuous Delivery

Aliaksei Marydashvili

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.

Figure 1. Software delivery process based on the continuous integration strategy
Source: Wikipedia

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

 

Infrastructure and setup

For this tutorial, I used a simple RoR application with MySQL as a DB. Then I 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).

Figure 2. Pushing a Jenkins CI app to Cloud Foundry

So, let’s begin.
 

1. Setting up a remote system

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

sudo apt-get install openssh-server

 
1.1 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

 
1.2 Configure Git:

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

 
1.3 Configure iptables:

a) Enable outbound connection on the remote machine to access the DB on the workstation:

sudo iptables -A OUTPUT -p tcp -d database_host_ip --dport 3306 -j ACCEPT

 
b) Save the updated iptables rules to a file:

iptables-save > /etc/iptables.rules

 
c) 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

 
1.4 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

 
1.5 Install Cloud Foundry:

a) For this, 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)

 
b) Restart your devbox

c) 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.

d) 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

 
e) Add the .manifest.yml file for the application to your RoR project directory (see the “Examples” section).

1.6 Install Jenkins:

a) Install openjdk-6-jre and openjdk-6-jdk:

sudo apt-get install openjdk-6-jdk openjdk-6-jre

 
b) 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

 
c) Install a MySQL client:

sudo apt-get install mysql-client-core-5.1

 

2. Setting up an RVM

2.1 Switch to the ‘jenkins’ account:

sudo su Jenkins

 
2.2 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

 
2.3 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

 
2.4 Create the ‘cf2’ gemset:

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

 
2.5 Download and install ‘cf’ from https://github.com/cloudfoundry/cli/releases:

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 command-line utility is v6.1.2. This may change in the future.

2.6 Generate a new SSH key and add it to GitHub:

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

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

2.8 Finally, verify that everything worked out as expected:

ssh -T git@github.com

 

3. Configuring Jenkins CI

3.1 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 1.5)
  • password: c1oudc0w (provided by in the Cloud Foundry installation tutorial, see the “References” section)
  • space: development (created previously in the Install Cloud Foundry step 1.5)
  • target: http://api..xip.io (provided in the Cloud Foundry installation tutorial, see the “References” section)
  • 3.2 Install the following Jenkins plug-ins: Git Client, GitHub, and Rake.

    3.3 Configure Jenkins security by adding accounts with appropriate permissions.

    3.4 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”).

    3.5 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
    

     
    3.6 Since both Cloud Foundry and Jenkins were installed on the same machine in my setup, I 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

     

    4. MySQL configuration on a local machine

    4.1 Enable inbound connection on the workstation:

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

    4.2 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';
    

     

    5. Examples

    5.1 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 at http://docs.cloudfoundry.org/buildpacks/ruby/ruby-tips.html.

    5.2 Jenkins build steps from “Execute shell”:

    #!/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
    

     
    I hope my post will help you to provide continuous integration on Cloud Foundry using Jenkins. If you have anything to add, just let me know in the comments.

     

    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, he is improving experience with these technologies on Cloud Foundry, bringing his R&D expertise to integrate solutions around CF and optimize software delivery processes with Platform-as-a-Service.

    3 Comments
    • http://www.altoros.com Renat Khasanshyn

      Aliaksei, which tools (in addition to Jenkins) would add an additional value while setting up a continuous delivery process for Cloud Foundry?

    • Alex Prismakov

      Thanks Aliaksei for the post. Expecting a post about integrating with Travis-CI )

    • Alex

      Renat, Travis-CI mentioned in the previous comment seems a very good option as well.

    Download Benchmarks and Research

    Subscribe to our newsletter

    Get the best of our content right in your inbox!