Kamal, Rails, and Ruby version

Today I have an undocumented trick for those building images with Kamal for those of you who are, like me, bothered that the ruby version is duplicated in the Dockerfile and .ruby-version.

Dockerfile

The default Dockerfile contains the directive:

ARG RUBY_VERSION=4.0.1
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base

This allows injection of the Ruby version by setting a docker build-arg option. If you were to run docker build and set --build-arg RUBY_VERSION without a value, docker will get the value from the environment.

Ruby

When you run Ruby, it sets RUBY_VERSION in it’s environment. Any commands run from within Ruby will get this enviroment variable. Kamal is a Ruby executable, so it will have the correct RUBY_VERSION for your application.

deploy.yml

Kamal allow you to set build args in deploy.yml. It even already has a commented out RUBY_VERSION: 4.0.1.

Connecting the dots

Just uncommenting the line is not enough. Kamal expects the build args to be a hash, which conflicts with trying to get Kamal to run with --build-arg RUBY_VERSION at first glance. The trick here is a (seemingly) undocumented feature of Kamal::Utils.argumentize. Any value that gives false to VALUE.present? will result in --OPTION KEY, while “present” values result in --OPTION KEY=VALUE.

This means that any of the following will result in passing of RUBY_VERSION from the Kamal process to the docker build and save you a duplicated config:

RUBY_VERSION: ""
RUBY_VERSION: null
RUBY_VERSION: []
RUBY_VERSION: {}