Deploying a Rails 5 App with MongoDB, Redis, and CarrierWave to IBM Bluemix

Learn how to add and configure services step by step via the CLI or the UI.

ibm-bluemix-rails5-mongodb-object-storage-redis-v2

In this post, we show how to deploy a Rails 5 application with MongoDB as a database and CarrierWave for image processing to Bluemix. The source code for the article is available in this GitHub repo.

Please keep in mind one slight difference: in the article, credentials are set in a more explicit way with user-defined environment variables, while in the repository, they are fetched from the Cloud Foundry application auto-generated VCAP_SERVICES variable.

 

Prerequisites

To follow the steps of this tutorial, you need:

  • a Bluemix account
  • cf
  • swift (a Python client)

 

Adding and configuring services

Before deploying, you need to create services instances for your application. You can do it through the CLI or the UI. Note that a free MongoDB service hosted by Bluemix is not available in the UI. In addition, some configuration options have to be specified in the manifest.yml file.

 

Adding services through the CLI

The organization you intend to use and the space within it should be created in the Bluemix UI before you authenticate with cf login. They can have any names that you choose.

adding-ibm-bluemix-services-via-cloud-foundry-cli-v1

After creating a new service, you should bind it to your application as explained in the official Bluemix documentation. Alternatively, you can specify dependencies names in manifest.yml, and then cf push will do it for you.

To add a service from the command line, use cf create-service. Below, you will find its syntax.

cf create-service SERVICE PLAN SERVICE_INSTANCE

where:

  • SERVICE is the service name.
  • PLAN is the service plan.
  • SERVICE_INSTANCE is the name of your service instance. It is an instance alias that is meaningful to you.

For more information, please check out the official Cloud Foundry docs.

First, we need to set up our MongoDB.

cf create-service mongodb 100 mongodb01
cf set-env APP-NAME DATABASE_URL “YOUR_MONGODB_URI”

After that, configure the database connection in your config/mongoid.yml.

...
production:
  clients:
    default:
      uri: <%= ENV[‘DATABASE_URL’] %>

We will also need the Object Storage service and Redis.

# Object Storage
cf create-service Object-Storage Free ostorage01
cf set-env APP_NAME OSTORAGE_CREDENTIALS ‘{“auth_url”:...}’ # Get credentials from the Bluemix console.

# Redis
cf create-service rediscloud 30mb redis01
cf set-env APP_NAME REDIS_URL "http://rediscloud:password@hostname:port"

If you store the Object Storage credentials in an environment variable as described above, your CarrierWave initializer should look similar to the one in this example. Note that you should choose the fog-openstack gem version 0.1.2 or later to use Bluemix Object Storage in your application.

config/initializers/carrierwave.rb:

CarrierWave.configure do |config|
  if Rails.env.production?
    creds = JSON.parse(ENV['OSTORAGE_CREDENTIALS'])
    config.storage = :fog
    config.fog_credentials = {
      provider:               'OpenStack',
      openstack_auth_url:     creds['auth_url'] + '/v3/auth/tokens',
      openstack_api_key:      creds['password'],
      openstack_project_id:   creds['projectId'],
      openstack_userid:       creds['userId'],
      openstack_region:       creds['region'],
      openstack_temp_url_key: ENV['OS_TEMP_URL_KEY'],
      openstack_auth_omit_default_port: true
    }
    config.fog_directory  = 'your_ostorage_container_name'
    config.fog_public     = false
    config.fog_authenticated_url_expiration = 600
  end
end

As we use MongoDB instead of PostgreSQL, we have to provide ActionCable with Redis configuration. The following configuration file addresses this issue as shown below.

config/cable.yml:

production:
  adapter: redis
  url: <%= ENV[‘REDIS_URL’] %>

To use Object Storage, you need to create a container and set fog_directory to its name. You also need TEMP_URL_KEY—a random secret string—to generate public URLs for your images. To do so, run the following commands.

swift --os-auth-url 'https://identity.open.softlayer.com/v3' --auth-version 3 --os-project-id PROJECT_ID --os-region REGION --os-user-id USER_ID --os-password PASSWORD post -m 'Temp-URL-Key:YOUR_KEY'
cf set-env APP_NAME OS_TEMP_URL_KEY YOUR_KEY

 

Adding services through the UI

Note that sometimes you can choose between different offerings for the same tool in the Bluemix services catalog. For example, you have two options for Redis: Redis Cloud and Redis by Compose.

adding-ibm-bluemix-services-via-ui-v1

The last one gives you a configuration that is pretuned for high availability, includes additional security features, and also provides a number of metrics. The same is true for MongoDB.

ibm-bluemix-mongodb-metrics-v1MongoDB Compose metrics

After you create all the services, you should set the environment variables—DATABASE_URL, REDIS_URL, OSTORAGE_CREDENTIALS, and OS_TEMP_URL_KEY—according to their credentials.

ibm-bluemix-mongodb-redis-environment-variables-v1Setting environment variables in the Bluemix UI

Below, you can also see an example of reading service credentials.

ibm-bluemix-mongodb-object-storage-credentials-v1Reading services credentials on the Bluemix website

 

Manifest.yml

The manifest.yml file consists of two sections. The first section—declared-services—describes services that an application uses. Below, you will find this very section for the sample application.

declared-services:
  mongodb01:
    label: Rails 5 blog MongoDB
    plan: 100
  ostorage01:
    label: Rails 5 blog Object Storage
    plan: Free
  redis01:
    label: Rails 5 blog Redis
    plan: 30mb

The keys are the names of the services that are to be referenced later. The values specify the services labels and plans.

The second section—applications—describes the application itself. Here is this section for the sample application with the properties defined below.

applications:
- name: rails-5-blog
  memory: 256M
  instances: 1
  path: .
  stack: cflinuxfs2
  buildpack: https://github.com/ddollar/heroku-buildpack-multi.git
  command: bundle exec puma -e production -p $PORT
  services:
    - mongodb01
    - ostorage01
    - redis01

where:

  • name is the application name as it is shown in your Bluemix console.
  • memory is the amount of RAM that is reserved per a single instance of the application excluding services.
  • instances is the number of instances to start.
  • path is a relative path to the project that is deployed. It can be a folder for Ruby or, for example, a war/jar file for Java.
  • stack is the Cloud Foundry image for the application. The cflinuxfs2 image is based on Ubuntu 14.04 (Trusty), and it is the most common choice for Ruby applications.
  • buildpack is a Git or local path to the used buildpack. For plain Ruby applications, it is typically https://github.com/cloudfoundry/ruby-buildpack.git. To use wkhtmltopdf in the example, we refer to the buildpack that lets to specify multiple buildpacks for a single application. In this case, the used buildpacks are included in the .buildpacks file.
  • command defines what command to run to start the application. It has to be a foreground program, and the default start timeout is 60 seconds. Note that your application should listen to the port specified with the $PORT environment variable and not to the port 80 that is used as an upstream for the NGINX server.
  • services lists the names of all services bound to the application. These services should be described in the declared-services section mentioned above.

 

Deploying the application

To deploy, you can just go to your application directory and run cf push. (Of course, you need to use cf login for the first time.) For real-world applications, you might need something more powerful:

build-and-deploy-in-ibm-bluemix-v1Build and deploy in Bluemix

When using the CLI, you will get the result as shown below.

cloud-foundry-cli-cf-push-result-v1

If you want to use background jobs in your Rails application, check out the official Cloud Foundry docs. Notice that your application needs to be deployed twice in this case.

 

Further reading

 

About the authors

Nick Herman is a software engineer at Altoros. He specializes in web development using Ruby and JavaScript as his primary tools. Nick also has professional interests and expertise in many other areas related to software engineering, including programming languages and cloud technologies.

Dzmitry Bardziyan is a Ruby and JavaScript developer at Altoros. He has solid knowledge of Rackspace, AWS, SoftLayer, vSphere, and other infrastructure solutions, as well as background in system administration. Dzmitry also contributes to a number of IT magazines.