Senior Software Developer
Published at

How to containerize your Rails in minutes

Even Ruby on Rails is one of the fastest frameworks of web development, and we can use it to build a web rapidly. We still need the DevOps to deploy or update it manually that we can test or release it.

Can we have a better way to resolve it?

Boxing Gem

I create the Boxing gem to save my time. It will detect your Ruby project and generate a workable Dockerfile for you.

It is inspired by Bundler Audit. The boxing gem will detect the Gemfile and pick a suitable Linux package to resolve your dependency when building the container image.

This is an early stage for this gem, I need people to report package dependency to improve it.

To make it work, we only need to add “boxing” to your Gemfile:

1group :development do
2	gem 'boxing'

After bundle install to install it, we can use bundle exec boxing generate to create a Dockerfile for your project.

The generated Dockerfile is dependent on The best practice of containerizing the Ruby on Rails which is my summary of experience about containerizing a Rails project.

Currently, in the 5xRuby which is I am working for. All new projects will use this configuration with CI/CD to provide automatic deployment to let dev teams can test it directly.

Openbox Gem

You may have some problems if you are already using Docker or Docker Compose in your project.

One of the problems is the Docker Compose’s depends isn’t mean the service is ready even we have the health check in the Dockerfile. That means we may have some error after Rails is booted because the database is not ready.

The most common solution on the internet is adding PostgreSQL or MySQL client to your container, and run a check script in your entrypoint, and running Rails after its success.

1while ! mysqladmin ping -h"$DB_HOST" --silent; do
2    sleep 1
5rails server

In this way, we have to add a needless binary and grow the container image size. To build a production-ready container image, we have to reduce the size if possible. Reduced size can speed up the deployment, low down the pressure of the network, and help Kubernetes to migrate between nodes faster.

For the smaller container image size, I create a ruby gem Openbox which uses an installed database adapter the check the connection of the database. If we choose Openbox as entrypoint, it will use the environment variable DATABASE_URL to connect the database. That means we can ensure database connectivity and install fewer packages.

Besides the connectivity check, the Openbox provides a shortcut for the Rails console. We can use docker run --rm -it myapp console instead of docker run --rm -it myapp rails console and it also limited the command to execute to make the container more secure.

GitLab CI Template

The ruby gems reduce the time to containerize. But we still manually build containers and deploy them. To automatic it, we will need a CI/CD solution.

However, configuring CI/CD tasks will spend us a lot of time. GitLab provides AutoDevOps as an option to resolve it, but the AutoDevOps is slow, and hard to customize the Dockerfile.

The alternative solution is to create a customize GitLab CI config and correctly config the artifacts to let GitLab support it the same as AutoDevOps.

The elct9620/ruby-gitlab-ci is created to replace AutoDevOps to let you write fewer config to have a CI/CD pipeline for Rails.

Now, integrate the 3 tools I created. We can containerize Rails in minutes only add a new ruby gem and apply my template.

Fast And Faster

I tell my colleagues “if you are lazy enough, you will be a good developer.” We have a lot of things to try and experience, we didn’t have any reason to spend time on it.

Technology is used to make life easier, our works are to reduce the “waste time and repeatable things”, doesn’t it?

This work a repeated for each new project I am starting work on in many years. I decided to build a solution to create more time to work on more reasonable things and hope it can help you to resolve the same problem.