Topics:

Welcome to this new edition of One Framework a Day keeps the Boredom Away. In this series I will show you how to deploy a particular framework on Clever Cloud every day until I want to go back to boredom. Today it's about Ruby on Rails.

In each post of this series we'll see how to deploy a particular framework on Clever Cloud. Today we are taking a look at Ruby on Rails.

If you want to tag along, make sure you have git, a Clever Cloud account and that you have installed our CLI Clever-Tools.

What is Ruby on Rails?

Ruby on Rails, or simply Rails, is a server-side web application framework written in Ruby under the MIT License. Rails is a model–view–controller framework, providing default structures for a database, a web service, and web pages.

There are lots of applications built on top of Ruby on Rails. Today I decided to look at Redmine. It's a project management web application. You can read our documentation on Rails first and then folow this tutorial.

Setup

  • Start by cloning the sources, here I am checking out the latest stable branch: git clone https://github.com/edavis10/redmine/ --branch 3.4-stable
  • Create the database you want to use, in my case Postgres: clever addon create postgresql-addon --plan dev --region eu redminePG
  • Create a FS Bucket: clever addon create fs-bucket --plan s --region eu redmineFS
  • Create the Ruby application on Clever Cloud: clever create --type ruby redmine --region par
  • Link the Postgres add-on to the application: clever service link-addon redminePG
  • Link the FS Bucket add-on to the application: clever service link-addon redmineFS

It's time to configure the application with environment variables. To get a list of the already available variables simply run clever env. You will notice all the variables related to PostgreSQL. To use them create a new database.yml file under config: touch config/database.yml

production:
  adapter: postgresql
  database: <%= ENV["POSTGRESQL_ADDON_DB"] %>
  host: <%= ENV["POSTGRESQL_ADDON_HOST"] %>
  username: <%= ENV["POSTGRESQL_ADDON_USER"] %>
  port: <%= ENV["POSTGRESQL_ADDON_PORT"] %>
  password: <%= ENV["POSTGRESQL_ADDON_PASSWORD"] %>
  encoding: utf8
  • Define a new global secret in config/secrets.yml: touch config/secrets.yml

    production:
    secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  • Define all the other configuration variables under config/configuration.yml: touch config/configuration.yml

    production:
    attachments_storage_path: <%= ENV["APP_HOME"] %><%= ENV["ATTACHMENTS_STORAGE_PATH"] %>

    The following property uses two different variables. APP_HOME is already available and injected when the VM starts. It's the absolute path to the application repository. The second one is to tell Redmine where to write files.

Time to install the dependencies with ./bin/bundle install --without development test. And now setup the various environment variables you will need:

  • Set the Ruby version: clever env set RUBY_VERSION 2.3.1
  • Setup the Rails environment to use the production configuration: clever env set RAILS_ENV production
  • Use en as language: clever env set REDMINE_LANG en
  • Use a newly generated secret: clever env set SECRET_KEY_BASE `./bin/rake secret`
  • Setup where to write files: clever env set ATTACHMENTS_STORAGE_PATH /data/attachments
  • Define where to mount our FS Bucket:clever env set CC_FS_BUCKET /data:`clever env | awk -F = '/BUCKET_HOST/ { print $2}'`

The FS bucket is one of the add-ons we setup earlier. It's a FileSystem mounted when the VM starts. Here it's mounted under /public. This path being relative to the home of the application, which is what we had under APP_HOME earlier. The second part of the CC_FS_BUCKET variable separated by a semi-colon is the host for your FS Bucket. It's already available under the BUCKET_HOST variable.

Now Redmine requires to write in some folder, and those folder to be pre-created. To make sure this executed each time the app is ran, we can use a pre-run hook. It will run something each time prior to starting the app. Let's start with the script:

mkdir clevercloud; touch clevercloud/initDirectories.sh && chmod +x clevercloud/initDirectories.sh

[ -d tmp ] || mkdir tmp
[ -d tmp/pdf ] || mkdir tmp/pdf
[ -d data/plugin_assets ] || mkdir data/plugin_assets
[ -d tmp/pdf ] || mkdir tmp/pdf
[ -d data/attachments ] || mkdir data/attachments

It first tests the existence of the folder and if it does not exist, creates it. To make sure it's run add the hook like this: clever env set CC_PRE_RUN_HOOK ./clevercloud/initDirectories.sh

The minimum configuration is ready, we can move on to the deployment phase.

Deploy

As usual with Clever Cloud the deployment phase is tied to the runtime and build tool used by the application. Here it's a Ruby app so we are going to create a ruby.json file: touch clevercloud/ruby.json

{
  "deploy" : {
    "rakegoals": ["db:migrate"],
    "sidekiq": true
  }
}

Now we need to commit our changes. Create a new deployment branch, commit your stuff and deploy!

git checkout -b clever/deploy
git add Gemfile.lock clevercloud/initDirectories.sh clevercloud/ruby.json config/configuration.yml config/database.yml config/secrets.yml
git commit -m"add clever specifics"
clever deploy

Last command is the equivalent of git push clever yourBranch where clever is a remote branch that was added when you created the application with the CLI at the very begining.

There is one last thing we can do. In Redmine's documentation they mention some default data you can import by running a rake task. Since we don't want to run these tasks each time we restart the application, we can SSH on the VM and execute them here. Run clever ssh. This will open a connection to the VM. From here you can execute that task:

[ldoguin@caolila redmine]$ clever ssh
Opening an ssh shell.
Warning: Permanently added '[195.154.154.198]:40707' (ED25519) to the list of known hosts.
bas@76afae97-762c-43ee-b861-d5db873b553d ~ $ cd app_58f97386-2ec5-48b6-a774-31d64241f692/
bas@76afae97-762c-43ee-b861-d5db873b553d ~/app_58f97386-2ec5-48b6-a774-31d64241f692 $ RAILS_ENV=production bundle exec rake redmine:load_default_data
Select language: ar, az, bg, bs, ca, cs, da, de, el, en, en-GB, es, es-PA, et, eu, fa, fi, fr, gl, he, hr, hu, id, it, ja, ko, lt, lv, mk, mn, nl, no, pl, pt, pt-BR, ro, ru, sk, sl, sq, sr, sr-YU, sv, th, tr, uk, vi, zh, zh-TW [en] 
====================================
Default configuration data loaded.
bas@76afae97-762c-43ee-b861-d5db873b553d ~/app_58f97386-2ec5-48b6-a774-31d64241f692 $

If you have tasks to run regularly you can also configure a cron by adding a json fle as explained in our documentation.

To test this, I invite you to run clever open. This should open the running application in your default browser. By default you can login with admin/admin. I invite you to create a project, an issue and add an attachment to that issue. If everything works correctly you can go in our web console, click on redmineFS and then on File Explorer. You should be able to explore your FS bucket and see the file you attached to the issue :)

Application environment variables

What's also interesting here is that everything is configured with env variable so you can use the same code for prod and preprod or staging if you want to.

Setup and Deploy a Preproduction Redmine

You did most of the work already :) Just don't forget to use the --alias option to specify which application you are working with.

clever addon create postgresql-addon --plan s --region eu redminePG
clever addon create fs-bucket --plan s --region eu staging-redmineFS
clever create --type ruby staging-redmine --region par
clever service --alias staging-redmine link-addon staging-redminePG
clever service --alias staging-redmine link-addon staging-redmineFS
clever env --alias staging-redmine set RUBY_VERSION 2.3.1
clever env --alias staging-redmine set RAILS_ENV production
clever env --alias staging-redmine set REDMINE_LANG en
clever env --alias staging-redmine set SECRET_KEY_BASE `./bin/rake secret`
clever env --alias staging-redmine set ATTACHMENTS_STORAGE_PATH /data/attachments
clever env --alias staging-redmine set CC_FS_BUCKET /data:`clever env --alias staging-redmine  | awk  -F = '/BUCKET_HOST/ { print $2}'`
clever env --alias staging-redmine set CC_PRE_RUN_HOOK ./clevercloud/initDirectories.sh
clever deploy --alias staging-redmine

Then you can inject the default data just like before. As you can see most of the work here was to make sure Redmine could be configured with environment variables. Some Rails projects, or other projects in general, are more or less compliant with 12 factors and as such require some work.

Hopefuly you liked what you read. This is a very minimal setup to enjoy Redmine, there are other things to configure like the SMTP server or some plugins to be added. That's up to you :)


Profile picture of Laurent Doguin
By Laurent Doguin

Head of Developer Relation @clever_cloud. Devoxx Champion. I am also a nerdy metal head living in Paris.