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.
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
.
- My Lando version is
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 theservices
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
.- You can base your configuration on example.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
- See the lando-rails-example repository on GitHub.
- Read Dockerize Ruby on Rails with Docker Compose.
- Read Lando documentation.
- Try dockerizing a new/existing Rails project.
- Post your comments/suggestions/thoughts in the comments area below.