Skip to content

Add Ruby 3.2.11, Bundler, MySQL headers, and Yarn to the anvil image - #91

Merged
CrypticSwarm merged 2 commits into
masterfrom
anvil-ruby
Oct 2, 2026
Merged

CrypticSwarm merged 2 commits into
masterfrom
anvil-ruby

Conversation

@CrypticSwarm

Copy link
Copy Markdown
Owner

Lets an agent run bundle install and assets:precompile for a Rails app on Ruby 3.2.11, Bundler 2.6.9, mysql2, and Shakapacker.

  • Ruby: a ruby-builder stage compiles 3.2.11 into /opt/ruby and checks the tarball's SHA-256 (trixie ships 3.3). It also installs Bundler 2.6.9 and puts the yaml/ffi/gmp/zlib headers in the runtime image.
  • Gems: GEM_HOME=/home/anvil/.gem, because /opt/ruby belongs to root.
  • MySQL: adds default-libmysqlclient-dev for mysql2.
  • Yarn: comes from Corepack, so a project pinning Yarn 2+ in packageManager still works (Yarn 1 refuses to run there). The download prompt and auto-pinning are turned off.
  • Security: $GEM_HOME/bin goes at the end of PATH. Root's startup phase uses the same PATH, so a writable directory at the front would let a session plant commands for root. A new ImagePathOrder test enforces the order.

Changing RUBY_VERSION also means changing RUBY_SHA256.

Debian trixie ships Ruby 3.3, so a project pinned to 3.2 needs the
interpreter built the way Python already is: a ruby-builder stage
compiles the release tarball into /opt/ruby, checked against its
published SHA-256, and installs Bundler 2.6.9 so a lockfile bundled
with it does not trigger a version switch.

/opt/ruby belongs to root and the harness runs as the anvil user, so
GEM_HOME points under the anvil home, where bundle install can write
and which persists for every harness that mounts the home. Its bin
directory goes at the end of PATH, not the front: the image PATH is
also the root phase's, which runs chown, adduser, and gosu by bare
name, so a session-writable directory ahead of /usr/bin would let a
session plant a command for root to run on the next start. A test
holds the Dockerfile's PATH to that.

The yaml, ffi, gmp, and zlib headers go into the runtime stage too:
libruby and its psych, fiddle, and zlib extensions link against
those libraries, and native gems compile against the headers.
A Rails app on MySQL cannot bundle without them: the mysql2 gem
compiles against libmysqlclient, which default-libmysqlclient-dev
provides (as MariaDB's compatible client on trixie), and
assets:precompile runs Shakapacker's JS build, which installs its
packages with yarn.

Yarn comes from corepack, which Node 24 bundles, rather than a
global npm install: Yarn 1 refuses to run in a project whose
packageManager names Yarn 2 or later, while corepack's shim runs
whatever release that field names and falls back to Yarn 1 when
there is none. The shim fetches the release on first use, so the
download prompt is turned off for a session with no one to answer
it, and so is auto-pinning, which would write packageManager into
the project's package.json.
@CrypticSwarm
CrypticSwarm merged commit 3580e56 into master Oct 2, 2026
4 checks passed
@CrypticSwarm
CrypticSwarm deleted the anvil-ruby branch October 2, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant