Search code examples
ruby-on-railsrubygoogle-app-enginegoogle-cloud-platformruby-2.5

proper Ruby version for Google App Engine Ruby Standard Environment w/Rails


Using the default app.yaml configuration provided by Google for Google App Engine Ruby 2.5 standard environment, I cannot deploy successfully when using Rails. If I use Ruby 2.5.5 locally, and in my .ruby-version and Gemfile, the deploy fails with:

Your Ruby version is 2.5.7, but your Gemfile specified 2.5.5.

If I use Ruby 2.5.7 locally and in my Gemfile and .ruby-version file, the deploy succeeds, but visiting the app results in the following error in the logs:

bundler: failed to load command: rails (/srv/vendor/bundle/ruby/2.5.0/bin/rails)
Bundler::RubyVersionMismatch: Your Ruby version is 2.5.5, but your Gemfile specified 2.5.7

And note that I have properly set up .gcloudignore to include .ruby-version and other important dotfiles that are ignored by default by app engine.

Quite the predicament!

You can reproduce my build with this repo: https://github.com/sam0x17/ruby_standard_environment_version_issue


Solution

  • Here's the official word from the Ruby App Engine runtime team.

    If you have a Ruby version constraint in your Gemfile, always use a pessimistic version constraint (or other mechanism to allow more recent patchlevels), rather than locking to a specific patchlevel. For example, use something like ruby "~> 2.5.5" to indicate 2.5.5 or any newer patchlevel, rather than ruby "2.5.5" or ruby "2.5.7". This isn't a temporary workaround, but an actual requirement and best practice for App Engine standard.

    The reason is twofold. During a rollout of a new Ruby version, there may be a short period where the bundle install is run on a different Ruby patchlevel than the app itself. This is what you ran into, and it apparently is the expected behavior because the "bundle builder" component is rolled out independently from the runtime image.

    But more importantly, App Engine standard may upgrade your Ruby patchlevel at any time. Your app might be running on Ruby 2.5.6 today, but tomorrow you might find it upgraded to Ruby 2.5.7, even if you didn't redeploy explicitly. This is App Engine's intended behavior: it transparently applies critical updates and security patches, and that may include updating the patchlevel of the Ruby interpreter. (Note that App Engine only updates the Ruby patchlevel. It will never update your app from, say, Ruby 2.5 to Ruby 2.6 unless you explicitly tell it to use a Ruby 2.6 runtime.) Because of this feature, if your Gemfile specifies the Ruby version, it needs to be able to handle patchlevel updates, for example by using a pessimistic version constraint.

    As a secondary note, .ruby-version is ignored on App Engine standard environment. Note this is different from App Engine flexible environment, which uses the file as a way for your app to request a specific Ruby version to run on. The standard environment, however, chooses and controls the Ruby version for you, and you don't get a say.

    Apologies for the predicament. I'll work with the team to try to clarify our documentation on this.