Rails on Docker without Docker

a Balloon, personified as a developer, deploys an application to Fly.io.
Image by Annie Ruygt

Docker will play a major role in the future of Rails production deployments, but not everybody wants to learn Docker, understand Linux systems administration, and install additional tooling on their workstations. Fortunately Fly.io can do this heavy lifting for you so you can focus on building applications and ease into these details later when your application demands it.

During Rails World 2023, several new parts of the Rails stack were announced including an official Dockerfile would be included in Rails 7.1 and a new deployment tool, Kamal, that uses Docker to package up and deploy Rails applications to servers.

There’s just one problem: not all Rails developers want to install Docker on their workstations and learn how to craft a Dockerfile & all the Linux commands that go along with it. The good news is that Fly.io does all that for you so you can focus on building your app and worry about all that stuff later. Let’s see how.

Rails developers don’t have to be Linux system administrators or Docker experts to deploy to production

A Dockerfile is a text file with a bunch of commands that copy files, install packages, install gems, execute Linux commands, and describe the command that launches the app. These files are read by a builder that downloads the necessary Linux operating system, packages, and source code and bundles them all up in an image. This image is then sent to Fly.io and run on top of bare metal servers via Firecracker virtual machines, which is really fast.

For people who are comfortable and experienced managing Linux systems, Docker is relatively easy to learn, but many developers aren’t familiar with Linux and just want to build and ship great apps on a platform that Just Works™.

Fly.io created and open-sourced the dockerfiles-rails gem to make it easier for beginners and experts to create Dockerfiles for their apps. It looks at the gems and dependencies of Rails apps and automatically creates a Dockerfile with the configuration needed to run in production.

The dockerfile-rails gem automatically generates reasonable Dockerfiles so you don’t have to

Want to quickly create secure Rails app Dockerfiles for production? Good news! You don’t have to go searching through 20 tutorials on the internet to piece something together—instead you can run these commands from the root of your Rails project:

bundle add dockerfile-rails --optimistic --group development
bin/rails generate dockerfile

This gem looks at the Gemfile and package.json files, if present, in your Rails application folder to determine what operating system packages should be installed. The gem is capable of automating some pretty gnarly deployments ranging from installing vips for imaging processing to getting Puppeteer working to take screenshots of webpages… all with one command: rails g dockerfile.

Automatically generate Dockerfiles for older Rails apps

Rails 7.1 ships with a default Dockerfile, which is great, but what about that old Rails 6 app you want to run on a Docker host that you don’t plan on upgrading for a while? Yep, the dockerfile-rails gem will happily create a Dockerfile for it so you can deploy it to any Docker-compatible host like Fly.io.

Consolidate Docker knowledge into one gem instead of random internet tutorials

Prior to the dockerfile-rails gem, creating Dockerfiles usually consisted of searching the internet for tutorials showing you how to do it. After hours of hacking together a FrankenDockerfile you might end up with something shippable, but it probably isn’t ideal or as secure as it should be.

The dockerfile-rails gem consolidates and automates all of this knowledge in one place. As more people in the Rails community use it and open PR’s to integrate their use cases, we all benefit and updating that knowledge becomes a matter of running:

bundle update
bin/rails g dockerfile

If you’re up for it, you can open a pull request on the dockerfile-rails repository and commit your Dockerfile configurations.

Run less stuff on development workstations

For Rails developers who are dedicated to having minimal tooling on their machines, Fly.io makes it possible to use Docker without running Docker on your workstation with its remote builder. This offers several benefits:

Deploy over crappy internet connections

When a Rails app is built in Docker from a development workstation it has to download the Linux operating system and packages, build the image, then push everything back over the wire to your servers. This can take a really long time over a slow internet connection, especially if it frequently disconnects.

With Fly.io, the Docker builder runs on Fly’s infrastructure. That means only the application source code is copied from the development workstation to the build server, which is usually a heck of a lot less data to move over the wire than an entire Linux distribution and all of its packages.

Fly’s hosted builder has saved my bacon countless times when I’m on a crappy WiFi connection that barely works and I need to deploy something quickly to production, like this deployment from my local purveyor hopped beverages.

Deploying an application from the Canyon Club's WiFi network.

Developers that use macOS Apple Silicon don’t have to emulate an Intel Docker builder

Intel Linux servers are still the most dominant processor architecture in production environments. That means developers running Apple Silicon or ARM workstations have to emulate Intel processors on their local workstations to build a Docker image that will run on Intel production servers, which can be slow.

Since Fly.io runs Docker builders on Intel servers all a developer workstation needs to do is copy the code files over the wire to the build server. The build server builds the image on native Intel hardware, pushes it up to the image repository, then deploys it to Fly.io servers around the world when fly deploy is run.

What about Kamal?

Kamal is a great way to deploy Rails applications to a wide variety of hosts ranging from bare metal servers to virtual servers, but it does require that you learn more about Docker, know a few things about Linux & networking, manage a load balancer, and install more software on your workstation like Docker.

You should use dockerfile-rails with Kamal

The gem is completely agnostic production servers, which means you can use it with Kamal to generate Dockerfiles for your Rails apps.

Kamal requires you to bring your own Docker builder and image repository

It’s no secret that Kamal is the more manual way of running your infrastructure including managing your own certificates, load balancer, and more. Fly.io manages SSL certificates, load balancing, and Docker for you and only needs your application’s Dockerfile.

Kamal and dockerfile-rails makes it easier to switch hosts

Getting a Rails app running in Docker is the hard part, but once that’s accomplished its possible to deploy a Rails app to more production targets via Kamal, Kubernetes, or Fly.io via fly deploy. This means its easier to switch hosting providers in the future should the need arise.

Can I use Kamal with Fly.io?

Yes, but it’s not necessary to use Kamal since Fly.io manages the load balancer, Docker builds, and restarts for you via the fly deploy command.

fly launch uses dockerfile-rails to configure Rails applications

When you launch a new Rails app on Fly.io the following happens:

  1. fly launch detects a Gemfile in the root of a project with a rails gem dependency.
  2. fly launch detects the absence of a Dockerfile and runs bundle add dockerfile-rails at the root of the project, then runs rails generate dockerfile.
  3. The rails g dockerfile command scans your Gemfile and package.json to install the necessary Linux packages. For example, the puppeteer gem will install headless Chrome.

After Fly.io virtual machines are provisioned when running fly launch, the fly deploy command will use the remote Fly.io Docker builder to build the Docker image, push it to the servers, and get your app up and running.

Read through the Rails on Fly.io documentation for more details on how to lunch your Rails app on Fly.io.

Don’t be afraid of Linux and Docker

It might seem unnecessary to have a Dockerfile in the root of your application when you’re starting out, but there will be a day where you add something different to your Rails application that requires a specific Linux package. When this happens you’ll be glad you can open the Dockerfile, make your change, and deploy.

Fly.io and the dockerfile-rails will gradually introduce you to Docker and Linux concepts in a way that allow you to be immediately productive.

Wrap-up

The Rails community has embraced Dockerfile as its “unit of deployment”, which will make it easier to deploy Rails apps to more hosts that support Docker including your own servers via Kamal or to managed services like Fly.io.

For those who don’t want to stop work on their Rails apps to learn Docker, Kamal, & Linux commands, Fly.io will do the heavy lifting of creating a Dockerfile for your Rails app, deploying it to production behind a load balancer, handle SSL certificates, and host the Docker builder so you don’t have to install it on your workstation.