July 21, 2026

Docker for your Rails dependencies

Docker: The fastest ever intro

Docker has been around since about 2013 as a way to run software in portable, reusable containers. This has allowed many software development teams to standardise some parts of their development stacks regardless of developer environments and attempt to give parity between environments on each step of the software development and release cycle.

I just never felt the need for Docker

For me though, it felt like it was solving a problem that I just didn’t have. I was already quite a few years into developing Ruby and Rails applications on my Mac hardware. The package management system that I was using, homebrew, had become quite robust and the applications that I was working on worked very well with it, usually requiring a Postgresql database and a Redis instance for the most part.

I worked on the same thing all the time

As well as my dependencies being quite simple a lot of the time, I also didn’t really change what I was working on a lot. By 2014 I started a run of jobs that were each quite long tenured and where I had also moved out of doing consulting work and into product companies. This change in type of role moved me away from working on several applications at once and into working on a company’s application, or group of applications/services that would all need to be able to be running at the same time, they did not need to be isolated from each other.

But, nothing lasts forever

This, however, has come to an end for the time being. As with so many folks in 2026, I was faced with a redundancy earlier this year. I was very fortunate in that I was able to land a contract relatively quickly and keep moving, but it does land me in the positoin where I am more conscious of flexibility, being able to work on multiple things on the same laptop, that any job, no matter how entrenched you are in it, no matter how good your relationship with it is, is safe. I know that these are fairly personal things on what has (even though I have not posted for a long time) a largely technical blog, but it has affected how I look at my work, and my realtionship with it. That is I suppose a very long way to say, I’ve found myself wanting to be able to easily and quickly switch which dependencies I am working with at any given time. As such, Docker has finally made itself useful to me.

Dependencies, just in containers

Now that I am working a contract, and am toying with some application ideas of my own, I want to be able to switch what I am doing quickly and easily. When I had two versions of PostgreSQL on the go as we upgraded at my last job, I would just switch between which I was running at any given time with homebrew. It was a bit clunky, but I didn’t have to do it much. It was fine. At new contracting, there are several services to run, often at once on my laptop as I do my work. The tooling for these services spins up docker containers that house each of the dependencies for those services. This has been great for quickly spinning up and down whichever I need aceess to. It got me thinking, I should do a similar thing so when I work on this app I have an idea for, I can quickly get my database up as the one I am running, run it docker, turn off the container when I am done for day/time being and then be able to spin up the containers I need when I am working on the day job.

How?

It needs to be easy, or frankly, I am not interested. I had written off the idea of using Docker containers on my development laptop, probably unfairly, but also I just didn’t feel like I had a problem that needed to be solved by them. I don’t think I’ve ever worked on a project where the exact container that you use in development ends up running the application in staging or production, so I felt like I just didn’t really care that much. Now that it is useful to me, and I’ve been introduced into how easily something gotten running then shutdown again, I’ve decided it’s time to re evaluate that, so I have some rake tasks to get all this going.

An aside

To have any of these work on my development machine, I use a Macbook Air these days, I need to have Docker for Mac running. I just use the desktop app so I can easily containers that are running, but you can run it on the terminal if you prefer, but Docker will need to be running to set this up.

A service in a container

I’m just starting out an app, so I only need my PostgreSQL instance running in a Docker continer for now. The not deploying containers was not the only reason I did not really care for Docker as a development tool. Any project I worked on where folks suggested it as an option there was never any really great tooling around it. To use it now for myself, I’ve decided that that tooling was absolutely necessary to keep it easy to use. What do I need for that? I need to be able to start or stop my container with a single command.

I started by being able to start up PostgreSQL with a single command:

bx rails docker:postgres:start

and can stop it with:

bx rails docker:postgres:stop

To do this, some pretty simple code in a rake task:

# lib/tasks/docker.rake

namespace :docker do
  namespace :postgres do
    CONTAINER_NAME = "personal-postgres"

    desc "Start the personal PostgreSQL Docker container"
    task :start do
      if system("docker inspect #{CONTAINER_NAME} > /dev/null 2>&1")
        sh "docker start #{CONTAINER_NAME}"
      else
        abort "Container '#{CONTAINER_NAME}' does not exist. Create it first with docker run."
      end
    end

    desc "Stop the personal PostgreSQL Docker container"
    task :stop do
      sh "docker stop #{CONTAINER_NAME}"
    end
  end
end

And it running:

❯ bx rails docker:postgres:start
docker start personal-postgres
personal-postgres
PostgreSQL is not the only one

This was a pretty good result, but I was not satisified for long. It very quickly occurred to me that a basic rails app, I still use Rails all the time unless I have a good reason not to, has other dependencies. I don’t have them yet, but they will be there in any app that is not trivial, at least Redis. This meant that I wanted to be able to start (and stop) any dependency that runs in Docker with a single command. This mean I needed to be able define the dependencies that could be started/stopped, and also trigger a command. Nothing too crazy, so adding to the file:

namespace :docker do
  SERVICES = %w[postgres].freeze

  # Existing code omitted
  desc "Start all Docker services"
  task start: SERVICES.map { "docker:#{_1}:start" }

  desc "Stop all Docker services"
  task stop: SERVICES.map { "docker:#{_1}:stop" }
end

So now I can stop the containers I had running earlier:

❯ bx rails docker:stop
docker stop personal-postgres
personal-postgres

Now my PostgreSQL container can be stopped, by stopping all containers that are running, and I can start up my Docker dependencies:

❯ bx rails docker:start
docker start personal-postgres
personal-postgres
We are almost there

This is all great, but I realised I still had one complaint about running Docker as a development dependency, creating the container in the first place. It’s mostly academic for this project I have, I am the only one working on it, and only on one laptop, but I wanted to better equipped for how do I get an app up and running quickly from scratch if needed. New laptop, new person, whatever the reason. That means there is one missing piece. Get the containers up and running even if they do not exist. Not a big deal, just need to add a new task:

# lib/tasks/docker.rake

namespace :docker do
  # Omitted existing code
  desc "Create the personal PostgreSQL Docker container"
  task :init do
    if system("docker inspect #{CONTAINER_NAME} > /dev/null 2>&1")
      puts "Container '#{CONTAINER_NAME}' already exists."
    else
      sh "docker run -d " \
          "--name #{CONTAINER_NAME} " \
          "-e POSTGRES_USER=#{ENV.fetch('POSTGRES_USER', 'postgres')} " \
          "-e POSTGRES_PASSWORD=#{ENV.fetch('POSTGRES_PASSWORD', 'postgres')} " \
          "-p #{ENV.fetch('POSTGRES_PORT', 5432)}:5432 " \
          "-v personal-postgres-data:/var/lib/postgresql " \
          "postgres:18"
    end
  end

  # Omitted existing code
  desc "Create all Docker services"
  task init: SERVICES.map { "docker:#{_1}:init" }

  # Omitted existing code
end

This one involves a little more. It needs to know a POSTGRES_USER, a POSTGRES_PASSWORD and a POSTGRES_PORT to set up. By setting them up in my Rails application with dotenv:

# .env

POSTGRES_HOST=host
POSTGRES_PORT=5432
POSTGRES_USER=username
POSTGRES_PASSWORD=password

They are then available for use in my database.yml for the rails app config:

# config/database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  host: <%= ENV.fetch("POSTGRES_HOST", "localhost") %>
  port: <%= ENV.fetch("POSTGRES_PORT", 5432) %>
  username: <%= ENV.fetch("POSTGRES_USER", "postgres") %>
  password: <%= ENV.fetch("POSTGRES_PASSWORD") %>
  max_connections: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: development_database

With these files set, I am then able to just run the rake tasks, and I can create, start and stop a docker container for development of my Rails app. This allows me to easily isolate my own personal work from anything I am doing while contracting, quickly and easily switching between the different versions of dependencies when I need to.

Conclusion

Whilst for many folks writing software none of this is revolutionary or new, Docker has been around for over a decade after all. It did get me thinking though, not only about things like right tool for the job, but also, sometimes, the right time for the tool. I guessI am saying that what has changed recently is not anything about this tooling, it’s been me, my outlook, and now my recent change in circumstance that let me to have a problem that I didn’t think needed solving before. So whilst this is well trodden ground for many, if it helps you out or solves a problem for you as well, I am really happy about that, and I’d love to hear about it.

Comments?

I've changed how I run my blog now and have decided to not integrate comments into this new version. I am happy to answer any questions though, feel free to send me an email through the link at the top of the screen. Happy Programming.