Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heroku-24: Remove gcc, make and libc6-dev from the run image #273

Merged
merged 1 commit into from
Mar 21, 2024

Conversation

edmorley
Copy link
Member

@edmorley edmorley commented Mar 20, 2024

(This is a first step towards reducing image size for Heroku-24: #266)

GCC was added to our run images back in #127 in order to support Ruby 2.6's then new MJIT feature:
https://www.ruby-lang.org/en/news/2018/12/25/ruby-2-6-0-released/

However, since then:

As such, this removes gcc, make and libc6-dev from the run image for a 203 MB saving (they are still present in the build image, hence zero changes to installed-packages-*.txt for that image).

Richard (Ruby owner) has confirmed he's fine with this change.

Note: I'm intentionally not adding binutils back (which was a transitive dependency), since its 15 MB cost is not worth it for the ~once a year platform operator debugging use-case. (More discussion on this at:
https://salesforce-internal.slack.com/archives/C02GZCPPV38/p1709204898451809?thread_ts=1709054633.272659&cid=C02GZCPPV38)

Before:

-----> Size breakdown...
       heroku/heroku:24         661MB
       heroku/heroku:24-build   1.13GB

After:

-----> Size breakdown...
       heroku/heroku:24         458MB  (203 MB reduction)
       heroku/heroku:24-build   1.13GB (unchanged)

Towards #266.
GUS-W-15159536.

GCC was added to our run images back in #127 in order to support
Ruby 2.6's then new MJIT feature:
https://www.ruby-lang.org/en/news/2018/12/25/ruby-2-6-0-released/

However, since then:
- The Ruby MJIT feature hasn't really resulted in significant
  performance benefits for real world use-cases like a Rails app.
- Ruby's MJIT has since been superseded by YJIT, which is faster and
  doesn't need GCC at runtime:
  https://shopify.engineering/yjit-just-in-time-compiler-cruby
  https://shopify.engineering/ruby-yjit-is-production-ready
- The image size impact of including build tools in our run images has
  increased considerably (#127 quoted it as 84 MB, but measuring now
  it's 203 MB).
- In a CNB world, image size is much more of a concern than in the S3
  `.img` + slug model, so we need to be more selective over what
  packages we include.

As such, this removes `gcc`, `make` and `libc6-dev` from the run image
for a 203 MB saving (they are still present in the build image, hence
zero changes to `installed-packages-*.txt` for that image).

Richard (Ruby owner) has confirmed he's fine with this change.

Note: I'm intentionally not adding `binutils` back (which was a
transitive dependency), since its 15 MB cost is not worth it for the
~once a year platform operator debugging use-case.

Before:

```
-----> Size breakdown...
       heroku/heroku:24         661MB
       heroku/heroku:24-build   1.13GB
```

After:

```
-----> Size breakdown...
       heroku/heroku:24         458MB
       heroku/heroku:24-build   1.13GB
```

Towards #266.
GUS-W-15159536.
@edmorley edmorley self-assigned this Mar 20, 2024
@edmorley edmorley marked this pull request as ready for review March 20, 2024 12:16
@edmorley edmorley requested a review from a team as a code owner March 20, 2024 12:16
@edmorley edmorley enabled auto-merge (squash) March 20, 2024 12:16
@edmorley edmorley changed the title Heroku-24: Remove gcc, make and libc6-dev from run image Heroku-24: Remove gcc, make and libc6-dev from the run image Mar 20, 2024
Copy link

@runesoerensen runesoerensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems we might as well get this going so we can discover issues before GA!

@edmorley edmorley merged commit 270aad4 into main Mar 21, 2024
4 checks passed
@edmorley edmorley deleted the edmorley/h24-gcc-build-only branch March 21, 2024 15:03
edmorley added a commit that referenced this pull request May 21, 2024
Python's `ctypes.util.find_library` is used to find libraries at
runtime. `find_library()` calls out to various external programs to help
with this task, initially trying `ldconfig`, and then falling back to
`gcc` and `ld` if needed - as documented here:
https://docs.python.org/3/library/ctypes.html#finding-shared-libraries

Even after the removal of compilation tools from the run image in #273,
`ldconfig` still exists in the run image, so libraries can still be
found by `ctypes.util.find_library` in the base image.

However, whilst the `find_library()` docs say that it supports
`LD_LIBRARY_PATH`, the docs fail to mention that the env var is only
honoured when `ld` can be found:
https://github.com/python/cpython/blob/e870c852c0ea96fa4e4569e9c39c7ceb80ce858d/Lib/ctypes/util.py#L315-L320

As such, when only `ldconfig` is available, `find_library()` only
returns libraries from the base image, and not any installed via eg the
APT or other buildpacks (which rely upon `LD_LIBRARY_PATH` since they
have to do userland "installs" of libraries due to not having root
permissions).

One such popular use of `ctypes.util.find_library` is in Django's GIS
feature, which uses it to locate the GDAL library at runtime:
https://github.com/django/django/blob/4971a9afe5642569f3dcfcd3972ebb39e88dd457/django/contrib/gis/gdal/libgdal.py#L53-L66

Therefore, we sadly have to include `binutils` in the run image after
all - though thankfully doing so only forgoes 19 MB of the original
203 MB run image size reduction from removing `gcc`, `make` and
`libc6-dev`.

GUS-W-15821115.
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.

2 participants