Skip to content
This repository has been archived by the owner on Dec 8, 2023. It is now read-only.

sustainable-rails/sustainable-rails-docker

Repository files navigation


Dev Environment for Sustainable Web Development with Ruby on Rails

This is a basis for creating a Ruby on Rails development environment using Docker. It is based on the development environment used for my book Sustainable Web Development with Ruby on Rails and can be used and customized to meet any needs for doing local development.

What problem does this solve?

  • Setting up dependencies for developing Rails apps is not easy, especially as operating systems change.
  • Although Docker can solve this, it is difficult to use and difficult to configure.

How does it solve it?

This provides a template for a Dockerfile in which your Rails app can run. It also provides a template for a docker-compose.yml file you can use to run dependent services like Postgres or Redis. It then provides several shell scripts that wrap the functionality you will need to do work.

It is currently set up to produce a Debian-based ARM64 image, because this is what is needed to do work on Apple Silicon. Although Apple Silicon can emulate Intel and AMD-based images, the emulation is incomplete and, in particular, Chrome does not work. See Customizing below if you don't want to use ARM64 images.

How to Use

  1. Make sure Docker is installed
  2. Clone this repo
  3. Open bin/vars and edit the values in there as instructed. You should only need to change ACCOUNT, REPO, and TAG.
  4. Run bin/build
  5. Run bin/start
  6. In another terminal, run bin/exec bash. You will now be "logged in" to the Docker container where your app can run. This Docker container has:
    • Ruby & Bundler
    • Rails
    • Node
    • Chromium and chromedriver

Customizing

This repo is intended to be the basis for your dev environment, so my recommendation is to create a new repo where you manage your dev-environment and seed it with these files.

There are four main points where you can customize things:

  • bin/vars - this allows limited control over things like the image name and ports.
  • docker-compose.yml.template - If you need a different database, don't need redis, need elastic search, etc, you can add services here as needed. This version includes Postgres and Redis, so you can use those as examples for what to do. Most common pieces of infrastructure can be run in Docker, so you should be able to get what you need. bin/build will currently replace the following variables when it's run:
    • %TAG% - The value of TAG from bin/vars
    • %REPO% - The value of REPO from bin/vars
    • %ACCOUNT% - The value of ACCOUNT from bin/vars
    • %EXPOSE% - The value of EXPOSE from bin/vars
    • %WORKDIR% - The value of WORKDIR from bin/vars
    • %LOCAL_PORT% - The value of LOCAL_PORT from bin/vars
    • %VOLUME_SOURCE% - The full path to the current working directory.
  • Dockerfile.template - this is the basis for the Dockerfile that is generated by bin/build. You can add whatever you like in here, customizing anything as needed. You may wish to remove the many comments in there that explain how it's set up. You also may wish to modify the architecture. Basically, this is a vanilla Dockerfile that you can do what you want to, but it has two variables that are replaced by bin/build:
    • %EXPOSE% - The value of EXPOSE from bin/vars
    • %WORKDIR% - The value of WORKDIR from bin/vars
  • The scripts in bin/ - You can modify and enhance these scripts to provide more customizations as needed. I strongly recommend maintaing these scripts as no-arg, dependency-free shell scripts, because that will be the simplest and most reliable way to keep your dev environment consistent and working. Aliases and required command-line arguments are just annoying.

Where is this being used?

This was extracted from the toolchain I created for my book, Sustainable Web Development with Ruby on Rails. All the examples and code in that book were executed many times in this development environment. I have also been using this for the past two years at my startup to manage the development of two Rails apps and a Zendesk sidebar app.

The World's Quickest Docker Tutorial

Docker is confusing, poorly documented, and poorly designed, so if it makes you feel as stupid as it makes me feel, that is OK. Here is a bit of conceptual grounding to help understand what is going on.

  • A Dockerfile is a set of instructions for a computer you would like to run.
  • Building a Dockerfile produces an Image. This is a set of bytes on your hard drive and you could consider this to be a clone of the hard drive of a computer you want to run.
  • Starting an image produces a Container. This is a virtualized computer running the image
  • In docker-compose.yml, there are services, which describe the containers you want to run in unision. Because a container is a virtualized computer running an image, each service requires an image that will be run. All the containers are run on the same network and can see each other.
  • When you see the word Host that is your computer. That is where Docker is running. I cannot think of a more confusing and unintuitive term but that is what they went with.

To make another analogy, Dockerfile is like source code to a class. An image is the class itself, and a container is an object you created from that class. docker-compose.yml is your program that integrates objects of several classes together.

Helpful Notes

Inside the container, you can connect to Postgres like so:

> PGPASSWORD=postgres psql --host db --username postgres --port 5432
postgres=#

When you run Rails, you need to tell it to bind to 0.0.0.0, so you can't just do bin/rails s. Instead you must:

> bin/rails s --binding 0.0.0.0

When you do that, your Rails app should be available to your localhost on port 9999 (or whatever value you set in bin/vars for EXPOSE)

Core Values

  • As few dependencies as possible
  • Your computer is not your development environment, it runs your development environment
  • Useful for working professionals
  • Programmers should understand how their development environment works

Non-Values

  • Flexibility
  • Production Deployments
  • Hiding details about how this works from the user

Things That Could be Improved

  • A way to QA this on other platforms like Linux or Windows without me having to buy a Linux machine or a Windows machine.
  • Ability to target more than just ARM64 without a lot of customizations
  • Probably some Docker best practices I'm not aware of needing to consider

FAQ

Why is this ARM64?

When running Chrome inside an AMD-based Docker container, Apple Silicon is unable to emulate certain system calls it needs, thus you cannot run Rails system tests in an AMD-based Docker container running on Apple Silicon.

Why is this using Chromium?

See the answer above. Chrome is not available for ARM64-based Linux operating systems, however Chromium is.

How can I use AMD-based Images?

Change this:

FROM arm64v8/ruby:3.1

to whatever base image you like, such as amd64/ruby:3.1.

If you do that, you don't have to use chromium. You can remove this line:

RUN apt-get -y install chromium chromium-driver

You will need to replace it with a more convoluted set of invocations that has changed many times since I first created this repo, so I will not document them here, as they are likely to be out of date. I'm sorry about that, but Google does not care about making this process easy.

What about that docked rails thing?

The Rails GitHub org has a repo called docked that ostensibly sets up a dev environment for Rails. It may evolve to be more useful, but here are the problems it has that this repo does not:

  • It will not work on Apple Silicon for reasons mentioned above re: Chrome
  • It does not provide a solution for running dependent infrastructure like Postgres which, in my experience, is much harder to do than getting Rails running.
  • It requires setting up shell aliases, which I dislike.
  • It uses an odd-numbered version of Node, and it's not a good idea to use that for development or production unless you are working on Node itself. Odd-numbered versions go end-of-life frequently and become unsupported. It's better and safer to use even-numbered versions.
  • It is designed for beginners to programming and Rails, which is great because we need more Rails developers, but that is a different use-case than a development environment for professional, experienced Rails developers. And yes, I mean "professional" in the sense of "getting paid to write Rails" and not in whatever stupid way Uncle Bob means it.

Why is this all generated from templates?

docker-compose.yml and Dockerfile share some values, but Docker provides no easy mechanism for that that I could figure out. So, the files are generated.

Why not use Vagrant?

Docker is a more generally useful skill to have, so I decided to focus on this and not learn Vagrant, which is less useful.

Contributions

I would love some! I am not a Docker expert and I only have used this for the way I do Rails. I'd love for this to be more useful (see above).

A few things I am not interested in:

  • Adding dependencies. I love Ruby and love writing command line apps in Ruby but Ruby's exsitence is not reliable, which is why the scripts are in bash.
  • Non-Rails web development. I want this to be about Rails
  • Deprecated or unsupported versions of things

About

Setup to run the examples from my sustainable rails book inside Docker

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published