Working on a Ruby on Rails project? Chances are that you’ll need a specific version of Ruby, Bundler, and project-specific gems (packages). Instead of installing these things directly on your dev laptop/desktop, you can use Docker to keep things organized. This article aims to help you dockerize your Ruby on Rails project using Lando.

As soon as you start working on multiple Rails projects with different dependencies, things often get complicated. You can use tools like Chruby, RVM, or Rbenv to manage versions of Ruby and gem, however, using Docker gives you even more flexibility.

A few years ago, I mostly used to work with Drupal. That’s when I had stumbled upon Lando – a tool that helps you dockerize your dev setup with ease.

Lando hides away certain complexities of Docker so that you can concentrate on your app instead of the Docker setup.

Recently, I started working on a Ruby on Rails project and I realized that Lando doesn’t have a recipe for Ruby on Rails. Thus began my endeavor to make Lando work with my Rails project. In this article, I’ll share my findings and walk through the steps it takes to make Rails work with Lando.

Screenshot of the Rails welcome screen
This article would’ve been incomplete without this graphic, so, voila!

2 minute version

  • Clone the lando-rails-example repository.
    • For existing projects, read the prepare project directory section.
  • Update  config/database.yml based on example.database.yml.
  • Run lando start.
  • Your Rails app should be available at rails.lndo.site.
  • To customize the setup, see:

Requirements

  • Basic Rails knowledge, at least the installation part.
  • Basic Docker concepts, e.g. what an image and a container is.
  • A working installation of Lando.
    • My Lando version is v3.0.23.

Step 1: Prepare project

You need a Rails app in order to use Lando with it.

New app

If you don’t have a Rails app, you can start by cloning the lando-rails-example repository that contains code for this example.

Existing app

If you already have a Rails app, copy the following files into the root of your app.

  • .lando.yml
  • lando (directory)

Step 2: Create Lando file

Reference: .lando.yml

We begin by creating a Lando file, i.e. .lando.yml containing the following top-level keys.

name: "lando-rails"
proxy:
  appserver:
    - "rails.lndo.site:3000"
services:
  # ...
tooling:
  # ...

Here's a brief description of the various keys of the YML file:

  • name: Project name. Docker container names will be derived from this name.
  • proxy: Sets up a pretty URL for your Lando site.
  • services: Services required by the project.
  • tooling: Shortcuts for frequently-used commands.

Database

A standard Rails app needs to store data in a database. Hence, we start by creating a database service. This example uses PostgreSQL, but you can use a different backend as well.

services:
  # ...
  database:
    type: postgres:12
    portforward: true
    creds:
      database: ror_development
      user: postgres
      password: NO PASSWORD

Let’s take a quick look at what these settings do:

  • type: Name of the database backend image.
  • portforward: Exposes PostgreSQL port (5432) to the host machine. This allows you to connect to Postgres at localhost:5432 with tools like DataGrip.
  • creds: Since the Lando file is only for dev envs, we simply include the database credentials in the Lando file itself.

App server

This is the most complex part of the setup where we use a Dockerfile to build a custom ruby:rails image that fits into our Lando setup.

services:
  # ...
  appserver:
    type: compose
    services:
      image: ruby:rails
      command: "tail -f /dev/null"
      ports:
        - '3000'
      environment:
        DATABASE_USER: postgres
        DATABASE_PASS: ''
        RAILS_ENV: development
    overrides:
      build: ./lando/appserver
    build:
      - bundle install --gemfile=/app/Gemfile

Here’s a brief explanation of what the various appserver.* keys defined above.

  • type: The compose type tells Lando to use a custom Docker image to build this service. This is used for services that Lando doesn’t support out of the box.
  • services: Configures the custom service, i.e. Ruby on Rails in this case.
  • overrides.build: Points to the directory containing a Dockerfile that will be used to build an image for the service. See the heading named Create Dockerfile.
  • build: This contains commands that will be executed on top of the custom ruby:rails image being built by the services section.

Now let’s take a look at the appserver.services.* keys:

  • image: A name/tag for the custom image that’ll be built for this service.
  • command: The command to execute when the container starts.
  • ports: Exposes port 3000 to which the Rails server listens.
  • environment: Configure env vars, usually for configuring the Rails app. The DATABASE_* variables are used in database.yml.

Command

Having spent a bunch of time on appserver.services.command while creating this example, I think it deserves a special mention. When the appserver service starts, this command will be executed to keep the service running. I chose the harmless tail -f /dev/null command which keeps tail running.

It is possible to run rails server -b 0.0.0.0 here, however, there’s a catch. Say, you make some changes you made to the Rails app and the rails server fails to start due to these changes. In this case, the service container will refuse to start, thereby making it difficult to debug the problem.

Thus, this example discommends using rails server as the command. You can start the rails server separately using the lando rails-server command defined under tooling.

Step 3: Configure tooling

In any Docker setup, the app’s services run inside service containers. Issuing commands to these services from the host machine involves prefixing the command with docker-compose exec SERVICE-NAME, followed by the command.

The tooling section in your Lando file can create shortcuts to such commands.

tooling:
  rails:
    service: appserver
    cmd: bundle exec rails
  rails-server:
    service: appserver
    cmd: bundle exec rails server -d -b 0.0.0.0
  rake:
    service: appserver

With the above setup, we can easily start the rails server with lando rails-server. Also, we can issue any rails command with ease, e.g. lando rails version.

Step 4: Create Dockerfile

Reference: The lando directory.

In the appserver.overrides.build section of the Lando file we told Lando to check the lando/appserver directory for instructions on building the ruby:rails image. We must ensure that a Dockerfile and other supporting files are present in that directory.

Since this article is about configuring Lando, I won’t go into the details of the Dockerfile. You can use the Dockerfile provided with this example and modify it according to your needs.

Step 5: Configure Rails

To make the Rails app work, we need to configure it correctly.

  • Ensure correct database connection parameters in config/database.yml.

Step 6: See it in action

Once all the pieces are in place, you can see your Docker setup in action:

lando start # Builds project images and starts the app.
lando rails-server # Starts the Rails server.

Your Rails app should now be available at rails.lndo.site.

Conclusion

The main advantage of using Lando are the easy-to-use recipes that come with it. Though there is no recipe for Ruby on Rails available at the moment, Lando has some helpful features that make life easy. The tooling configuration makes it easy to run commands in various service containers, and it is easy to add other services like Redis and Solr if required.

If you’re already using Lando for other projects, it might make sense to use Lando for your Rails dev envs. If you’re not a Lando user, it might make more sense to use Docker Compose instead.

Next steps

On this page

Subscribe

Never miss an article! Follow me on Twitter and enable notifications.

Follow on Twitter

Thoughts and comments