Closed jpwynn closed 3 years ago
Hi!
I agree it would be helpful if there was a better story for this. Longer term Cloud Native Buildpacks are going to be the solution for this, since with them, one can run virtually an identical build locally as is run in production.
In the meantime I'd check out the Dockerflles in #56 - particularly the more recent comments - there's an example of using the Ruby buildpack to install Ruby.
Alternatively a pretty string option is to just use the official Docker Ruby images (much lighter-weight than the Heroku stack images for local development) and instead rely on Heroku CI/Review Apps/staging app to ensure correctness before production deployment. After all, there are many many differences running locally compared to production (the docker image is likely the least of it; differences in DB configuration/version, RAILS_ENV, ...) so there still needs to be validation performed on Heroku and not just locally.
When attempting to update Ruby from a heroku buildpack, what USED to work (in heroku:18-build) is:
Yeah I wouldn't do that. Use the whole Ruby buildpack and not just the Ruby binary archive. The archive is not meant to be extracted over the system packages. The Ruby buildpack installs the files into the app directory and adds them to PATH, GEM_PATH etc.
In the meantime I've pinned #56 to improve visibility.
Thank you Ed. Can you offer a specific suggestion re "official Docker Ruby images" for Rails apps that will end up on Heroku? In https://hub.docker.com/_/ruby for example there are a lot of options: 2.7.3-buster, 2.7.3-slim-buster, 2.7.3-alpine3.13, 2.7.3-alpine3.12 which is Alpine and Debian, but Heroku uses Ubuntu, yes? and none of the options in that docker hub seem to be Ubuntu.
And of course then there is the issue of all the many apt-get packages to include. Any suggestions for figuring that out?
I suspect I'm not the only Heroku user who uses Heroku precisely so I can focus on my app instead of hundreds of pieces of underlying stack-related minutiae (well, plus the excellent devops of course). So it's unfortunate to discover that no, the Heroku stack images are not a way to quickly configure Docker so we can get back to app development.
It seems like "Sample Dockerfile for a Rails 6 app destined for Heroku-20" would be something Heroku could/should/would publish.
Many of our internal Ruby projects don't use docker for local development and instead run on the local machine. We then use Heroku CI/Review Apps/staging apps to catch any dev-prod parity issues. If you would prefer to use Docker locally, then I don't think it matters too much which base image you use. In terms of apt packages, just install the absolute minimum so that gems install (eg libpq
if using the pg gem).
A local testing environment is never going to fully match a remote production environment, and of the things that differ, the fact that the Docker image OS is Debian vs Ubuntu is much less frequently going to be the cause compared to other factors (eg different env vars, different DB configuration/version/not full prod data, framework debug mode, different load balancer, not real production user load etc). And for the cases where it does matter - there's still Review Apps, staging apps etc.
There are obviously tradeoffs of all approaches, however I think usability locally can often be more important than trying to have still only partial prod-parity.
You are more experienced and probably correct re the tradeoffs of local stack simplicity vs dev/prod parity. However (and maybe because I'm an old guy) I've always leaned pretty hard towards "try to catch at least some of the 'big' gotchas as early as possible right on the dev machine."
That said, review apps and staging apps have been awesomely helpful (we use both). And even wrote up a small blog post favorably comparing the speed of Heroku CI vs rspec locally: https://blog.pardner.com/2019/01/making-heroku-ci-almost-as-fast-as-running-rspec-locally/
Where is it documented how to get the latest heroku:20-build docker image to that happy place for local Dockerized Rails development where it has the default/recommended ruby, bundler versions (at a minimum, and probably also nodejs, npm, and yarn versions)?
I think I understand that "buildpacks" are the magic sauce that lets Heroku support such a wide range of frameworks.
And I think I understand that these stack images are kind of a foundation that those buildpacks rest upon.
Yet, the Heroku online service does have a 'default' ruby version (currently 2.7.3?). And when we do a git push, Heroku only uses its 'curated' Bundler version (2.2.16?). And I expect (especially for Rails 6 apps) there are particular recommended versions of nodejs, npm, and Yarn, too.
After a couple of years of "trial and error" on Heroku-18, trying to iteratively zero in on reasonable dev/prod parity in our local Docker Rails development setup, I figured I'd just ask... how/where do we 'get' the current-default ruby version out of the correct ruby buildpack?
I assume that in a Dockerfile, right below
FROM heroku/heroku:20-build
developers need add a series of apt-get X Y Z commands, and probably purging and reinstalling the default version of Ruby (from where?) and probably manual installation of the "current correct" Bundler version (trivially easy except - which version?)Is that "default ruby version + correct bundler version" Dockerfile documented anywhere? (This git repo seems the logical place.)
If not, oughtn't it be clearly documented given Heroku (correctly) stresses the importance of dev/prod parity?
A few notes:
Running your latest
heroku/heroku:20-build
viadocker run --rm -v ${PWD}:/usr/src -w /usr/src -ti heroku/heroku:20-build /bin/bash
I note that:This is how we (successfully) could update the obsolete stack image Ruby version back on heroku-18:
When attempting to update Ruby from a heroku buildpack, what USED to work (in heroku:18-build) is:
That initial snippet successfully replaced the default image Ruby version with a later version, obtained right from one of your buildpacks. The output of running
docker build --progress=plain --no-cache -t hiapptmp .
is:That method does not work on 20-build
Trying the same thing, using 20-build, and a ruby 2.7.3 does install the new ruby, but the installation is broken:
setting WORKDIR to /usr gets "closer" (ruby -v works) but Gem systems gets bolluxed
another possible issue for build-20 related to Rubygems?
Also disconcerting (with the -20:build) is some possible issue related to rubygems out of the box... I assume a simple
gem update --system
ought to work out-of-the-box on the stack image?(although updating to a specific version less than 3.1.4 does seem to work)