heroku / heroku-buildpack-nginx

Run NGINX in a Heroku app
244 stars 787 forks source link

Vendor Ruby if an installation is not found #103

Closed edmorley closed 2 years ago

edmorley commented 2 years ago

The ERB templating feature of this buildpack requires that the erb command (part of Ruby) be available at runtime, in order that the nginx config templates can be rendered into a valid nginx config.

On Heroku-22 the stack image no longer includes a system Ruby installation, so in order for this buildpack to continue to work, a Ruby install must be vendored by this buildpack.

If an app already uses the Ruby buildpack, and that buildpack is ordered prior to the nginx buildpack, then this buildpack will skip the Ruby vendoring step to save installing a redundant copy of Ruby.

Fixes #101. GUS-W-11321729.

edmorley commented 2 years ago

Tested on Heroku-22 and seems to work fine:

$ mkdir nginx-test && cd $_
$ git init
...
$ h create --stack heroku-22 --buildpack 'https://github.com/heroku/heroku-buildpack-nginx#edmorley/vendor-ruby-if-needed'
...
$ mkdir config public
$ curl -sSfL https://raw.githubusercontent.com/heroku/heroku-buildpack-nginx/main/config/nginx-solo-sample.conf.erb -o config/nginx.conf.erb
$ echo 'hello' > public/hello.txt
$ echo 'web: bin/start-nginx-solo' > Procfile
$ git add -A && git commit -m '.' && git push heroku main
...
remote: -----> Building on the Heroku-22 stack
remote: -----> Using buildpack: https://github.com/heroku/heroku-buildpack-nginx#edmorley/vendor-ruby-if-needed
remote: -----> nginx-buildpack app detected
remote: ./
remote: ./mime.types
remote: ./nginx
remote: ./nginx-debug
remote: -----> nginx-buildpack: Installed nginx/1.20.2 to app/bin
remote: -----> nginx-buildpack: An existing Ruby installation was not found (required for erb template support)
remote: -----> nginx-buildpack: Installed Ruby 3.1.2
remote: -----> nginx-buildpack: Added start-nginx to app/bin
remote: -----> nginx-buildpack: Added start-nginx-debug to app/bin
remote: -----> nginx-buildpack: Added start-nginx-solo to app/bin
remote: -----> nginx-buildpack: Default mime.types copied to app/config/
remote: -----> nginx-buildpack: Custom config found in app/config.
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 25.1M
remote: -----> Launching...
remote:        Released v4
remote:        https://dry-badlands-86959.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/dry-badlands-86959.git
   4c72ab1..eb0ff52  main -> main

$ h run erb --version
...
2.2.3

$ curl https://dry-badlands-86959.herokuapp.com/hello.txt
hello
edmorley commented 2 years ago

In terms of impact on slug size, the uncompressed size of the Ruby install is 48MB:

$ h run -- du -sh .heroku-buildpack-nginx/ruby
...
48M .heroku-buildpack-nginx/ruby

However the 500MB slug size limit applies to the compressed size, for which the increase is only 20.9 MB on Heroku-22:

Before:

remote: -----> Compressing...
remote:        Done: 4.2M

After:

remote: -----> Compressing...
remote:        Done: 25.1M

These slug size increases seem very acceptable, in return for the benefits of no longer having Ruby in the stack image - for which there are more details in: https://github.com/heroku/stack-images/pull/209#issuecomment-1059788051

edmorley commented 2 years ago

And confirmed the vendored Ruby isn't installed on stacks where system Ruby is present:

remote: -----> Building on the Heroku-20 stack
remote: -----> Using buildpack: https://github.com/heroku/heroku-buildpack-nginx#edmorley/vendor-ruby-if-needed
remote: -----> nginx-buildpack app detected
remote: ./
remote: ./nginx
remote: ./mime.types
remote: ./nginx-debug
remote: -----> nginx-buildpack: Installed nginx/1.20.2 to app/bin
remote: -----> nginx-buildpack: Added start-nginx to app/bin
remote: -----> nginx-buildpack: Added start-nginx-debug to app/bin
remote: -----> nginx-buildpack: Added start-nginx-solo to app/bin
remote: -----> nginx-buildpack: Default mime.types copied to app/config/
remote: -----> nginx-buildpack: Custom config found in app/config.
remote: -----> Discovering process types
remote:
remote: -----> Compressing...
remote:        Done: 5.2M
edmorley commented 2 years ago

Published:

$ h buildpacks:publish heroku-community/nginx v1.9
Publishing buildpack heroku-community/nginx... done
Publishing buildpack was successful

$ h buildpacks:versions heroku-community/nginx | head -n4
Version  Released At               Status
───────  ────────────────────────  ─────────
11       2022-06-21T09:57:43.472Z  published
10       2022-05-19T09:33:50.285Z  published