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

Reduce nodejs image size by removing /nodejs/include directory #1548

Open
pkwarren opened this issue Mar 19, 2024 · 12 comments
Open

Reduce nodejs image size by removing /nodejs/include directory #1548

pkwarren opened this issue Mar 19, 2024 · 12 comments

Comments

@pkwarren
Copy link

Describe the bug
Distroless nodejs images currently include the /nodejs/include directory (55.4M). A large portion of this is /nodejs/include/node/openssl (53.9M) which includes include files for multiple architectures and variants.

To Reproduce
Steps to reproduce the behavior:

  • Pull gcr.io/distroless/nodejs20-debian12:latest or gcr.io/distroless/nodejs20-debian12:debug images:
gcr.io/distroless/nodejs20-debian12                latest            7fc7b55da7d5   N/A              181MB
gcr.io/distroless/nodejs20-debian12                debug             8f8496cf32e2   N/A              183MB
  • Examine the size of the /nodejs/include directory within the container. Note that it makes up ~30% of the overall image size even though a compiler is not shipped in the image to use the include files.

Expected behavior
Either the nodejs images should omit the /nodejs/include directory or provide an image with a different tag to allow users to reduce the size of their nodejs images.

Console Output

$ docker run --rm --entrypoint sh -it gcr.io/distroless/nodejs20-debian12:debug
/ # du -sh /nodejs/include/
55.4M	/nodejs/include/

Additional context
n/a

@loosebazooka
Copy link
Member

Sounds reasonable. Can you point to some documentation about the include directory?

@omBratteng
Copy link
Contributor

@loosebazooka I have created a draft #1597

@daaain
Copy link

daaain commented Oct 5, 2024

I checked that the PR referenced above was merged in May, but I just built an image using gcr.io/distroless/nodejs22-debian12:nonroot (9f0d01f30f68) with a standalone Next.js app, was wondering why it's still 240.03 MB and apparently the Node.js layer is still 114.09 MB.

What else needs to happen for these changes to be reflected in the images on gcr.io?

image

@omBratteng
Copy link
Contributor

@daaain the nodejs binary itself is about ~114 MB

❯ /bin/ls -la
total 111792
drwxr-xr-x. 2 root root       120 Sep 17 17:09 .
drwxr-xr-x. 6 root root       180 Sep 17 17:09 ..
lrwxrwxrwx. 1 root root        45 Sep 17 17:09 corepack -> ../lib/node_modules/corepack/dist/corepack.js
-rwxr-xr-x. 1 root root 114472472 Sep 17 17:09 node
lrwxrwxrwx. 1 root root        38 Sep 17 17:09 npm -> ../lib/node_modules/npm/bin/npm-cli.js
lrwxrwxrwx. 1 root root        38 Sep 17 17:09 npx -> ../lib/node_modules/npm/bin/npx-cli.js
image

If you use dive, you can also see that the layer that adds 115MB only adds the license and node binary.
Not much that can be reduced there.

image

Do you compile next.js into standalone mode? It could reduce the bundle size a little bit.

This will create a folder at .next/standalone which can then be deployed on its own without installing node_modules.

@daaain
Copy link

daaain commented Oct 5, 2024

Oh right, I tried to use dive, but it doesn't seem to work on my Mac since I switched docker to use containerd.

I'm using standalone mode, so the actual app and dependencies are only 24 MB (you can see in the screenshot as the next layer), so that's why I was wondering where 90% of the image size is coming from.

I thought I could get the image using distroless below what's possible with alpine after reading this post, but maybe not.

@omBratteng
Copy link
Contributor

I think alpine compiles their node version which some different settings than the official nodejs binary.

@daaain
Copy link

daaain commented Oct 5, 2024

I'm trying to research now what's inside that massive binary and wondering if it has all the dependencies statically linked, in which case the rest of the image could jettison SSL and C libs?

This is maybe a bit off topic in this issue, but maybe compiling a Node Single executable application and using base-nossl-debian12 as base could be an alternative way to go? Node SEA wouldn't make any difference, it's just injecting the app into the binary

I couldn't find slimmer prebuilt binaries (e.g. small ICU) so sounds like this might then get into a very custom territory like manually building in a full Debian stage and copying the binary over...

@omBratteng
Copy link
Contributor

I wouldn’t worry that much about the size of the base image. If multiple images ise the same base image, it’s kinda “cached” on the system as long as they all use the same layers

@omBratteng
Copy link
Contributor

Could probably reduce the binary size if we’d compile the binary to be specific for debian.

But I think distroless just wants to use original releases, @loosebazooka could probably verify this statement

@loosebazooka
Copy link
Member

loosebazooka commented Oct 6, 2024

If it doesn't complicate the could too much it'd probably be fine. But we don't really build anything else from source so it would be a one off. Wonder if someone at canonical, red hat or chainguard might be more appropriate for this. They might have more flexible build processes

@omBratteng
Copy link
Contributor

It'll probably complicate a bit, and could break things, so probably not really worth it

@daaain
Copy link

daaain commented Oct 6, 2024

I don't think it's worth the complexity building from source and / or trying to remove something someone at some point will miss, to me there are 2 opportunities:

  1. find a leaner build upstream (that is still complete, but maybe doesn't have support for other distros, etc)
  2. remove library packages from the OS if they are statically linked and included in the binary

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

No branches or pull requests

4 participants